ship-gis/src/components/ship/ReplayLegend.tsx

149 lines
4.5 KiB
TypeScript
Raw Normal View 히스토리

/**
*
* -
* - ShipLegend , replayStore
*/
import { memo } from 'react';
import { shallow } from 'zustand/shallow';
import useReplayStore from '../../replay/stores/replayStore';
import {
SIGNAL_KIND_CODE_FISHING,
SIGNAL_KIND_CODE_KCGV,
SIGNAL_KIND_CODE_PASSENGER,
SIGNAL_KIND_CODE_CARGO,
SIGNAL_KIND_CODE_TANKER,
SIGNAL_KIND_CODE_GOV,
SIGNAL_KIND_CODE_NORMAL,
SIGNAL_KIND_CODE_BUOY,
} from '../../types/constants';
import './ShipLegend.scss';
// 선박 종류별 SVG 아이콘
import fishingIcon from '../../assets/img/shipKindIcons/fishing.svg';
import passIcon from '../../assets/img/shipKindIcons/pass.svg';
import cargoIcon from '../../assets/img/shipKindIcons/cargo.svg';
import hazardIcon from '../../assets/img/shipKindIcons/hazard.svg';
import govIcon from '../../assets/img/shipKindIcons/gov.svg';
import kcgvIcon from '../../assets/img/shipKindIcons/kcgv.svg';
import bouyIcon from '../../assets/img/shipKindIcons/bouy.svg';
import etcIcon from '../../assets/img/shipKindIcons/etc.svg';
/**
* ->
*/
const SHIP_KIND_ICONS: Record<string, string> = {
[SIGNAL_KIND_CODE_FISHING]: fishingIcon,
[SIGNAL_KIND_CODE_KCGV]: kcgvIcon,
[SIGNAL_KIND_CODE_PASSENGER]: passIcon,
[SIGNAL_KIND_CODE_CARGO]: cargoIcon,
[SIGNAL_KIND_CODE_TANKER]: hazardIcon,
[SIGNAL_KIND_CODE_GOV]: govIcon,
[SIGNAL_KIND_CODE_NORMAL]: etcIcon,
[SIGNAL_KIND_CODE_BUOY]: bouyIcon,
};
interface LegendItemConfig {
code: string;
label: string;
}
/**
*
*/
const LEGEND_ITEMS: LegendItemConfig[] = [
{ code: SIGNAL_KIND_CODE_FISHING, label: '어선' },
{ code: SIGNAL_KIND_CODE_PASSENGER, label: '여객선' },
{ code: SIGNAL_KIND_CODE_CARGO, label: '화물선' },
{ code: SIGNAL_KIND_CODE_TANKER, label: '유조선' },
{ code: SIGNAL_KIND_CODE_GOV, label: '관공선' },
{ code: SIGNAL_KIND_CODE_KCGV, label: '경비함정' },
{ code: SIGNAL_KIND_CODE_BUOY, label: '어망/부이' },
{ code: SIGNAL_KIND_CODE_NORMAL, label: '기타' },
];
interface ReplayLegendItemProps {
code: string;
label: string;
count: number;
icon: string;
isVisible: boolean;
onToggle: (code: string) => void;
}
/**
*
*/
const ReplayLegendItem = memo(function ReplayLegendItem({ code, label, count, icon, isVisible, onToggle }: ReplayLegendItemProps) {
const isBuoy = code === SIGNAL_KIND_CODE_BUOY;
return (
<li className={`legend-item ${!isVisible ? 'disabled' : ''}`}>
<div className="legend-info" onClick={() => onToggle(code)}>
<span className="legend-icon">
<img
src={icon}
alt={label}
style={{ transform: isBuoy ? 'rotate(0deg)' : 'rotate(45deg)' }}
/>
</span>
<span className="legend-label">{label}</span>
</div>
<span className="legend-count">{count}</span>
</li>
);
});
/**
*
*/
const ReplayLegend = memo(function ReplayLegend() {
const { replayShipCounts, replayTotalCount, shipKindCodeFilter } =
useReplayStore(
(state: {
replayShipCounts: Record<string, number>;
replayTotalCount: number;
shipKindCodeFilter: Set<string>;
}) => ({
replayShipCounts: state.replayShipCounts,
replayTotalCount: state.replayTotalCount,
shipKindCodeFilter: state.shipKindCodeFilter,
}),
shallow
);
const toggleShipKindCode = useReplayStore((state: { toggleShipKindCode: (code: string) => void }) => state.toggleShipKindCode);
return (
<article className="ship-legend">
{/* 헤더 */}
<div className="legend-header">
<div className="legend-title">
<span> </span>
</div>
</div>
{/* 선박 종류별 목록 */}
<ul className="legend-list">
{LEGEND_ITEMS.map((item) => (
<ReplayLegendItem
key={item.code}
code={item.code}
label={item.label}
count={replayShipCounts[item.code] || 0}
icon={SHIP_KIND_ICONS[item.code]}
isVisible={shipKindCodeFilter.has(item.code)}
onToggle={toggleShipKindCode}
/>
))}
</ul>
{/* 푸터 - 전체 카운트 */}
<div className="legend-footer">
<span></span>
<span className="total-count">{replayTotalCount}</span>
</div>
</article>
);
});
export default ReplayLegend;