Files
wanderer/assets/js/hooks/Mapper/components/mapRootContent/components/OnTheMap/OnTheMap.tsx
2024-12-04 18:01:50 +01:00

109 lines
3.6 KiB
TypeScript

import classes from './OnTheMap.module.scss';
import { Sidebar } from 'primereact/sidebar';
import { useMemo } from 'react';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { sortCharacters } from '@/hooks/Mapper/components/mapInterface/helpers/sortCharacters.ts';
import { VirtualScroller, VirtualScrollerTemplateOptions } from 'primereact/virtualscroller';
import clsx from 'clsx';
import { CharacterTypeRaw, WithIsOwnCharacter } from '@/hooks/Mapper/types';
import { CharacterCard, WdCheckbox } from '@/hooks/Mapper/components/ui-kit';
import useLocalStorageState from 'use-local-storage-state';
import { useMapCheckPermissions, useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
import { UserPermission } from '@/hooks/Mapper/types/permissions.ts';
type WindowLocalSettingsType = {
compact: boolean;
hideOffline: boolean;
version: number;
};
const STORED_DEFAULT_VALUES: WindowLocalSettingsType = {
compact: true,
hideOffline: false,
version: 0,
};
const itemTemplate = (item: CharacterTypeRaw & WithIsOwnCharacter, options: VirtualScrollerTemplateOptions) => {
return (
<div
className={clsx(classes.CharacterRow, 'w-full box-border', {
'surface-hover': options.odd,
['border-b border-gray-600 border-opacity-20']: !options.last,
['bg-green-500 hover:bg-green-700 transition duration-300 bg-opacity-10 hover:bg-opacity-10']: item.online,
})}
style={{ height: options.props.itemSize + 'px' }}
>
<CharacterCard showSystem {...item} />
</div>
);
};
export interface OnTheMapProps {
show: boolean;
onHide: () => void;
}
export const OnTheMap = ({ show, onHide }: OnTheMapProps) => {
const {
data: { characters, userCharacters },
} = useMapRootState();
const [settings, setSettings] = useLocalStorageState<WindowLocalSettingsType>('window:onTheMap:settings', {
defaultValue: STORED_DEFAULT_VALUES,
});
const restrictOfflineShowing = useMapGetOption('restrict_offline_showing');
const isAdminOrManager = useMapCheckPermissions([UserPermission.MANAGE_MAP]);
const showOffline = useMemo(
() => !restrictOfflineShowing || isAdminOrManager,
[isAdminOrManager, restrictOfflineShowing],
);
const sorted = useMemo(() => {
const out = characters.map(x => ({ ...x, isOwn: userCharacters.includes(x.eve_id) })).sort(sortCharacters);
if (showOffline && !settings.hideOffline) {
return out;
}
return out.filter(x => x.online);
}, [showOffline, characters, settings.hideOffline, userCharacters]);
return (
<Sidebar
className={clsx(classes.SidebarOnTheMap, 'bg-neutral-900')}
visible={show}
position="right"
onHide={onHide}
header={`On the map [${sorted.length}]`}
icons={<></>}
>
<div className={clsx(classes.SidebarContent, '')}>
<div className={'flex justify-end items-center gap-2 px-3'}>
{showOffline && (
<WdCheckbox
size="m"
labelSide="left"
label={'Hide offline'}
value={settings.hideOffline}
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300"
onChange={() => setSettings(() => ({ ...settings, hideOffline: !settings.hideOffline }))}
/>
)}
</div>
<VirtualScroller
items={sorted}
itemSize={41}
itemTemplate={itemTemplate}
className={clsx(
classes.VirtualScroller,
'w-full h-full overflow-x-hidden overflow-y-auto custom-scrollbar select-none',
)}
autoSize={false}
/>
</div>
</Sidebar>
);
};