Portal/rsconcept/frontend/src/features/library/components/PickSchema.tsx

161 lines
4.9 KiB
TypeScript
Raw Normal View History

2025-02-05 21:55:26 +03:00
import { useState } from 'react';
2024-06-07 20:17:03 +03:00
import { useIntl } from 'react-intl';
2025-02-12 21:36:03 +03:00
import clsx from 'clsx';
2024-06-07 20:17:03 +03:00
import { FlexColumn } from '@/components/Container';
import { MiniButton } from '@/components/Control';
2025-02-19 23:29:45 +03:00
import { createColumnHelper, DataTable, IConditionalStyle } from '@/components/DataTable';
import { Dropdown, useDropdown } from '@/components/Dropdown';
2025-01-28 23:23:03 +03:00
import { IconClose, IconFolderTree } from '@/components/Icons';
import { SearchBar } from '@/components/Input';
2025-01-28 23:23:03 +03:00
import { CProps } from '@/components/props';
2025-02-11 21:07:06 +03:00
import { APP_COLORS } from '@/styling/colors';
2024-09-12 13:27:06 +03:00
import { prefixes } from '@/utils/constants';
2024-06-07 20:17:03 +03:00
2025-02-18 19:39:54 +03:00
import { ILibraryItem, LibraryItemType } from '../backend/types';
2025-02-12 15:12:59 +03:00
import { matchLibraryItem } from '../models/libraryAPI';
2025-02-12 21:36:03 +03:00
2025-02-19 23:29:45 +03:00
import { SelectLocation } from './SelectLocation';
2024-06-07 20:17:03 +03:00
interface PickSchemaProps extends CProps.Styling {
2024-06-07 20:17:03 +03:00
id?: string;
2025-02-12 15:12:59 +03:00
value: number | null;
onChange: (newValue: number) => void;
2024-06-07 20:17:03 +03:00
initialFilter?: string;
rows?: number;
items: ILibraryItem[];
itemType: LibraryItemType;
2024-07-26 00:33:22 +03:00
baseFilter?: (target: ILibraryItem) => boolean;
2024-06-07 20:17:03 +03:00
}
const columnHelper = createColumnHelper<ILibraryItem>();
export function PickSchema({
id,
initialFilter = '',
rows = 4,
items,
itemType,
value,
onChange,
baseFilter,
className,
...restProps
}: PickSchemaProps) {
2024-06-07 20:17:03 +03:00
const intl = useIntl();
2025-02-05 21:55:26 +03:00
const locationMenu = useDropdown();
2024-06-07 20:17:03 +03:00
const [filterText, setFilterText] = useState(initialFilter);
2024-09-12 13:27:06 +03:00
const [filterLocation, setFilterLocation] = useState('');
2025-02-05 21:55:26 +03:00
const baseFiltered = items
.filter(item => item.item_type === itemType && (!baseFilter || baseFilter(item)))
.filter(item => matchLibraryItem(item, filterText));
const filtered =
filterLocation.length > 0
? baseFiltered.filter(item => item.location === filterLocation || item.location.startsWith(`${filterLocation}/`))
: baseFiltered;
2024-06-07 20:17:03 +03:00
const columns = [
columnHelper.accessor('alias', {
id: 'alias',
header: 'Шифр',
size: 150,
minSize: 80,
maxSize: 150
}),
columnHelper.accessor('title', {
id: 'title',
header: 'Название',
size: 1200,
minSize: 200,
maxSize: 1200,
cell: props => <div className='text-ellipsis'>{props.getValue()}</div>
}),
columnHelper.accessor('time_update', {
id: 'time_update',
header: 'Дата',
cell: props => (
<div className='whitespace-nowrap'>
{new Date(props.getValue()).toLocaleString(intl.locale, {
year: '2-digit',
month: '2-digit',
day: '2-digit'
})}
</div>
)
})
];
2024-06-07 20:17:03 +03:00
const conditionalRowStyles: IConditionalStyle<ILibraryItem>[] = [
{
when: (item: ILibraryItem) => item.id === value,
style: { backgroundColor: APP_COLORS.bgSelected }
}
];
2024-06-07 20:17:03 +03:00
function handleLocationClick(event: CProps.EventMouse, newValue: string) {
event.preventDefault();
event.stopPropagation();
locationMenu.hide();
setFilterLocation(newValue);
}
2024-09-12 13:27:06 +03:00
2024-06-07 20:17:03 +03:00
return (
<div className={clsx('border divide-y', className)} {...restProps}>
<div className='flex justify-between clr-input items-center pr-1 rounded-t-md'>
2024-09-12 13:27:06 +03:00
<SearchBar
id={id ? `${id}__search` : undefined}
className='clr-input flex-grow rounded-t-md'
2024-09-12 13:27:06 +03:00
noBorder
query={filterText}
onChangeQuery={newValue => setFilterText(newValue)}
2024-09-12 13:27:06 +03:00
/>
<div ref={locationMenu.ref}>
<MiniButton
icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />}
title='Фильтр по расположению'
className='mt-1'
onClick={() => locationMenu.toggle()}
/>
<Dropdown isOpen={locationMenu.isOpen} stretchLeft className='w-[20rem] h-[12.5rem] z-modalTooltip mt-0'>
<SelectLocation
value={filterLocation}
prefix={prefixes.folders_list}
dense
onClick={(event, target) => handleLocationClick(event, target.getPath())}
/>
</Dropdown>
</div>
{filterLocation.length > 0 ? (
<MiniButton
icon={<IconClose size='1.25rem' className='icon-red' />}
title='Сбросить фильтр'
onClick={() => setFilterLocation('')}
/>
) : null}
</div>
2024-06-07 20:17:03 +03:00
<DataTable
id={id}
rows={rows}
dense
noHeader
noFooter
className='text-sm select-none cc-scroll-y'
data={filtered}
2024-06-07 20:17:03 +03:00
columns={columns}
conditionalRowStyles={conditionalRowStyles}
noDataComponent={
2024-06-21 19:16:41 +03:00
<FlexColumn className='dense p-3 items-center min-h-[6rem]'>
2024-06-07 20:17:03 +03:00
<p>Список схем пуст</p>
<p>Измените параметры фильтра</p>
</FlexColumn>
}
onRowClicked={rowData => onChange(rowData.id)}
2024-06-07 20:17:03 +03:00
/>
</div>
);
}