2023-12-13 14:32:57 +03:00
|
|
|
'use client';
|
|
|
|
|
2024-08-22 22:41:41 +03:00
|
|
|
import fileDownload from 'js-file-download';
|
2024-12-12 21:36:46 +03:00
|
|
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
2024-08-21 16:49:17 +03:00
|
|
|
import { toast } from 'react-toastify';
|
2023-11-26 02:24:16 +03:00
|
|
|
|
2024-08-22 22:41:41 +03:00
|
|
|
import { IconCSV } from '@/components/Icons';
|
|
|
|
import MiniButton from '@/components/ui/MiniButton';
|
|
|
|
import Overlay from '@/components/ui/Overlay';
|
2024-03-20 15:27:32 +03:00
|
|
|
import DataLoader from '@/components/wrap/DataLoader';
|
2024-06-14 21:43:37 +03:00
|
|
|
import { useAuth } from '@/context/AuthContext';
|
2024-09-15 21:19:17 +03:00
|
|
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
2023-12-13 14:32:57 +03:00
|
|
|
import { useLibrary } from '@/context/LibraryContext';
|
2024-08-21 16:49:17 +03:00
|
|
|
import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
|
2023-12-13 14:32:57 +03:00
|
|
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
2024-08-21 16:49:17 +03:00
|
|
|
import { ILibraryItem, IRenameLocationData, LocationHead } from '@/models/library';
|
2024-06-02 23:41:46 +03:00
|
|
|
import { ILibraryFilter } from '@/models/miscellaneous';
|
2024-09-27 12:04:10 +03:00
|
|
|
import { UserID } from '@/models/user';
|
2025-01-14 21:58:16 +03:00
|
|
|
import { useAppLayoutStore } from '@/stores/appLayout';
|
2024-03-27 15:32:59 +03:00
|
|
|
import { storage } from '@/utils/constants';
|
2024-08-21 16:49:17 +03:00
|
|
|
import { information } from '@/utils/labels';
|
2024-08-22 22:41:41 +03:00
|
|
|
import { convertToCSV, toggleTristateFlag } from '@/utils/utils';
|
2023-12-13 14:32:57 +03:00
|
|
|
|
2024-06-26 19:47:31 +03:00
|
|
|
import TableLibraryItems from './TableLibraryItems';
|
|
|
|
import ToolbarSearch from './ToolbarSearch';
|
2024-06-27 11:35:26 +03:00
|
|
|
import ViewSideLocation from './ViewSideLocation';
|
2023-11-26 02:24:16 +03:00
|
|
|
|
|
|
|
function LibraryPage() {
|
|
|
|
const library = useLibrary();
|
2024-06-14 21:43:37 +03:00
|
|
|
const { user } = useAuth();
|
2023-12-05 01:22:44 +03:00
|
|
|
const [items, setItems] = useState<ILibraryItem[]>([]);
|
2024-09-15 21:19:17 +03:00
|
|
|
const options = useConceptOptions();
|
2025-01-14 21:58:16 +03:00
|
|
|
const noNavigation = useAppLayoutStore(state => state.noNavigation);
|
2023-11-26 02:24:16 +03:00
|
|
|
|
|
|
|
const [query, setQuery] = useState('');
|
2024-06-02 23:41:46 +03:00
|
|
|
const [path, setPath] = useState('');
|
|
|
|
|
|
|
|
const [head, setHead] = useLocalStorage<LocationHead | undefined>(storage.librarySearchHead, undefined);
|
2024-08-21 16:49:17 +03:00
|
|
|
const [subfolders, setSubfolders] = useLocalStorage<boolean>(storage.librarySearchSubfolders, false);
|
2024-06-02 23:41:46 +03:00
|
|
|
const [isVisible, setIsVisible] = useLocalStorage<boolean | undefined>(storage.librarySearchVisible, true);
|
2024-09-27 12:04:10 +03:00
|
|
|
const [isOwned, setIsOwned] = useLocalStorage<boolean | undefined>(storage.librarySearchOwned, undefined);
|
2024-06-02 23:41:46 +03:00
|
|
|
const [isEditor, setIsEditor] = useLocalStorage<boolean | undefined>(storage.librarySearchEditor, undefined);
|
2024-09-27 12:04:10 +03:00
|
|
|
const [filterUser, setFilterUser] = useLocalStorage<UserID | undefined>(storage.librarySearchUser, undefined);
|
2024-08-21 16:49:17 +03:00
|
|
|
const [showRenameLocation, setShowRenameLocation] = useState(false);
|
2023-11-26 02:24:16 +03:00
|
|
|
|
2024-06-02 23:41:46 +03:00
|
|
|
const filter: ILibraryFilter = useMemo(
|
|
|
|
() => ({
|
|
|
|
head: head,
|
|
|
|
path: path,
|
|
|
|
query: query,
|
2024-06-14 21:43:37 +03:00
|
|
|
isEditor: user ? isEditor : undefined,
|
|
|
|
isOwned: user ? isOwned : undefined,
|
2024-06-19 22:10:15 +03:00
|
|
|
isVisible: user ? isVisible : true,
|
2024-09-15 21:19:17 +03:00
|
|
|
folderMode: options.folderMode,
|
2024-08-21 16:49:17 +03:00
|
|
|
subfolders: subfolders,
|
2024-09-27 12:04:10 +03:00
|
|
|
location: options.location,
|
|
|
|
filterUser: filterUser
|
2024-06-02 23:41:46 +03:00
|
|
|
}),
|
2024-09-27 12:04:10 +03:00
|
|
|
[
|
|
|
|
head,
|
|
|
|
path,
|
|
|
|
query,
|
|
|
|
isEditor,
|
|
|
|
isOwned,
|
|
|
|
isVisible,
|
|
|
|
user,
|
|
|
|
options.folderMode,
|
|
|
|
options.location,
|
|
|
|
subfolders,
|
|
|
|
filterUser
|
|
|
|
]
|
2024-06-02 23:41:46 +03:00
|
|
|
);
|
2023-12-13 14:32:57 +03:00
|
|
|
|
2024-12-13 21:31:09 +03:00
|
|
|
const hasCustomFilter =
|
|
|
|
!!filter.path ||
|
|
|
|
!!filter.query ||
|
|
|
|
filter.head !== undefined ||
|
|
|
|
filter.isEditor !== undefined ||
|
|
|
|
filter.isOwned !== undefined ||
|
|
|
|
filter.isVisible !== true ||
|
|
|
|
filter.filterUser !== undefined ||
|
|
|
|
!!filter.location;
|
2024-06-18 15:07:41 +03:00
|
|
|
|
2024-12-12 21:36:46 +03:00
|
|
|
useEffect(() => {
|
2023-11-26 02:24:16 +03:00
|
|
|
setItems(library.applyFilter(filter));
|
2024-06-26 22:31:09 +03:00
|
|
|
}, [library, library.items.length, filter]);
|
2023-11-26 02:24:16 +03:00
|
|
|
|
2024-12-13 21:31:09 +03:00
|
|
|
const toggleFolderMode = () => options.setFolderMode(prev => !prev);
|
2024-06-02 23:41:46 +03:00
|
|
|
|
|
|
|
const resetFilter = useCallback(() => {
|
2023-11-26 02:24:16 +03:00
|
|
|
setQuery('');
|
2024-06-02 23:41:46 +03:00
|
|
|
setPath('');
|
|
|
|
setHead(undefined);
|
|
|
|
setIsVisible(true);
|
|
|
|
setIsOwned(undefined);
|
|
|
|
setIsEditor(undefined);
|
2024-09-27 12:04:10 +03:00
|
|
|
setFilterUser(undefined);
|
2024-09-15 21:19:17 +03:00
|
|
|
options.setLocation('');
|
2024-10-23 16:21:08 +03:00
|
|
|
}, [setHead, setIsVisible, setIsOwned, setIsEditor, setFilterUser, options]);
|
2024-08-21 16:49:17 +03:00
|
|
|
|
|
|
|
const handleRenameLocation = useCallback(
|
|
|
|
(newLocation: string) => {
|
|
|
|
const data: IRenameLocationData = {
|
2024-09-15 21:19:17 +03:00
|
|
|
target: options.location,
|
2024-08-21 16:49:17 +03:00
|
|
|
new_location: newLocation
|
|
|
|
};
|
|
|
|
library.renameLocation(data, () => {
|
2024-09-15 21:19:17 +03:00
|
|
|
options.setLocation(newLocation);
|
2024-08-21 16:49:17 +03:00
|
|
|
toast.success(information.locationRenamed);
|
|
|
|
});
|
|
|
|
},
|
2024-10-23 16:21:08 +03:00
|
|
|
[options, library]
|
2024-08-21 16:49:17 +03:00
|
|
|
);
|
2023-11-26 02:24:16 +03:00
|
|
|
|
2024-08-22 22:41:41 +03:00
|
|
|
const handleDownloadCSV = useCallback(() => {
|
|
|
|
if (items.length === 0) {
|
|
|
|
toast.error(information.noDataToExport);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const blob = convertToCSV(items);
|
|
|
|
try {
|
|
|
|
fileDownload(blob, 'library.csv', 'text/csv;charset=utf-8;');
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
|
|
|
}
|
|
|
|
}, [items]);
|
|
|
|
|
2023-11-26 02:24:16 +03:00
|
|
|
return (
|
2024-12-12 13:19:12 +03:00
|
|
|
<DataLoader isLoading={library.loading} error={library.loadingError} hasNoData={library.items.length === 0}>
|
2024-08-21 16:49:17 +03:00
|
|
|
{showRenameLocation ? (
|
|
|
|
<DlgChangeLocation
|
2024-09-15 21:19:17 +03:00
|
|
|
initial={options.location}
|
2024-08-21 16:49:17 +03:00
|
|
|
onChangeLocation={handleRenameLocation}
|
|
|
|
hideWindow={() => setShowRenameLocation(false)}
|
|
|
|
/>
|
|
|
|
) : null}
|
2024-09-15 21:19:17 +03:00
|
|
|
<Overlay
|
2025-01-14 21:58:16 +03:00
|
|
|
position={noNavigation ? 'top-[0.25rem] right-[3rem]' : 'top-[0.25rem] right-0'}
|
2024-09-15 21:19:17 +03:00
|
|
|
layer='z-tooltip'
|
2024-12-12 13:19:12 +03:00
|
|
|
className='cc-animate-position'
|
2024-09-15 21:19:17 +03:00
|
|
|
>
|
2024-08-22 22:41:41 +03:00
|
|
|
<MiniButton
|
|
|
|
title='Выгрузить в формате CSV'
|
|
|
|
icon={<IconCSV size='1.25rem' className='icon-green' />}
|
|
|
|
onClick={handleDownloadCSV}
|
|
|
|
/>
|
|
|
|
</Overlay>
|
2024-06-26 19:47:31 +03:00
|
|
|
<ToolbarSearch
|
2024-06-18 15:07:41 +03:00
|
|
|
total={library.items.length ?? 0}
|
|
|
|
filtered={items.length}
|
|
|
|
hasCustomFilter={hasCustomFilter}
|
2024-01-07 03:29:16 +03:00
|
|
|
query={query}
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangeQuery={setQuery}
|
2024-06-02 23:41:46 +03:00
|
|
|
path={path}
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangePath={setPath}
|
2024-06-02 23:41:46 +03:00
|
|
|
head={head}
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangeHead={setHead}
|
2024-06-02 23:41:46 +03:00
|
|
|
isVisible={isVisible}
|
|
|
|
isOwned={isOwned}
|
2024-12-13 21:31:09 +03:00
|
|
|
toggleOwned={() => setIsOwned(prev => toggleTristateFlag(prev))}
|
|
|
|
toggleVisible={() => setIsVisible(prev => toggleTristateFlag(prev))}
|
2024-06-02 23:41:46 +03:00
|
|
|
isEditor={isEditor}
|
2024-12-13 21:31:09 +03:00
|
|
|
toggleEditor={() => setIsEditor(prev => toggleTristateFlag(prev))}
|
2024-09-27 12:04:10 +03:00
|
|
|
filterUser={filterUser}
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangeFilterUser={setFilterUser}
|
2024-06-18 15:07:41 +03:00
|
|
|
resetFilter={resetFilter}
|
2024-09-15 21:19:17 +03:00
|
|
|
folderMode={options.folderMode}
|
2024-06-19 22:10:15 +03:00
|
|
|
toggleFolderMode={toggleFolderMode}
|
2024-01-07 03:29:16 +03:00
|
|
|
/>
|
2024-06-19 22:10:15 +03:00
|
|
|
|
2024-12-12 13:19:12 +03:00
|
|
|
<div className='cc-fade-in flex'>
|
2024-12-13 21:31:09 +03:00
|
|
|
<ViewSideLocation
|
|
|
|
isVisible={options.folderMode}
|
|
|
|
activeLocation={options.location}
|
|
|
|
onChangeActiveLocation={options.setLocation}
|
|
|
|
subfolders={subfolders}
|
|
|
|
folderTree={library.folders}
|
|
|
|
toggleFolderMode={toggleFolderMode}
|
|
|
|
toggleSubfolders={() => setSubfolders(prev => !prev)}
|
|
|
|
onRenameLocation={() => setShowRenameLocation(true)}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<TableLibraryItems
|
|
|
|
resetQuery={resetFilter}
|
|
|
|
items={items}
|
|
|
|
folderMode={options.folderMode}
|
|
|
|
toggleFolderMode={toggleFolderMode}
|
|
|
|
/>
|
2024-06-19 22:10:15 +03:00
|
|
|
</div>
|
2024-01-07 03:29:16 +03:00
|
|
|
</DataLoader>
|
2023-12-28 14:04:44 +03:00
|
|
|
);
|
2023-11-26 02:24:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
export default LibraryPage;
|