Advertisement
bruno83

Untitled

Nov 14th, 2024
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Ovo je kopija prikaza dokumenata, odnosno liste dokumenta u 79-17 koja sadržava i details dio ćisto ako nam zatreba ikad više, na početku koda moraju se uključiti import { customComparator, parseQuillText, truncateText } from '../../../utils';
  2.  
  3. List.jsx:
  4.  
  5. import {
  6.   BookOutlined,
  7.   DeleteOutlined,
  8.   ExclamationCircleFilled,
  9.   PlusOutlined,
  10.   SearchOutlined,
  11.   LinkOutlined,
  12. } from '@ant-design/icons';
  13. import { App, Button, Input, Table } from 'antd';
  14. import dayjs from 'dayjs';
  15. import { isEmpty, map } from 'lodash';
  16. import React, { useEffect, useMemo, useState } from 'react';
  17. import { useTranslation } from 'react-i18next';
  18. import { useDispatch, useSelector } from 'react-redux';
  19. import { Link, useNavigate, useParams } from 'react-router-dom';
  20. import CreateCard from '../../../components/common/CreateCard';
  21. import withLoadStatus from '../../../components/common/withLoadStatus';
  22. import { pageSizeOptions } from '../../../enviroment';
  23. import useSearch from '../../../hooks/useSearch';
  24. import useSearchParamsHandler from '../../../hooks/useSearchParamsHandler';
  25. import useTableManagement from '../../../hooks/useTableManagement';
  26. import { selectHasAdminRights, selectHasUserRights } from '../../../store/user/userSlice';
  27. import {
  28.   deleteWorkspaceDocument,
  29.   getWorkspaceDocuments,
  30.   getWorkspaceNotes,
  31. } from '../../../store/workspace/workspaceActions';
  32. import { selectWorkspaceDocuments } from '../../../store/workspace/workspaceSlice';
  33. import { customComparator, parseQuillText, truncateText } from '../../../utils';
  34. import { selectFiles } from '../../../store/file/fileSlice';
  35. import { getFiles, getSelectedMapFiles } from '../../../store/file/fileActions';
  36.  
  37. const List = ({ startLoading, stopLoading, isLoading }) => {
  38.   const { workspaceId } = useParams();
  39.   const { t } = useTranslation();
  40.   const dispatch = useDispatch();
  41.   const workspaceDocuments = useSelector(selectWorkspaceDocuments);
  42.   const hasUserRights = useSelector(selectHasUserRights);
  43.   const hasAdminRights = useSelector(selectHasAdminRights);
  44.   const navigate = useNavigate();
  45.   const { modal } = App.useApp();
  46.   const files = useSelector(selectFiles);
  47.   const [folderFiles, setFolderFiles] = useState(null);
  48.  
  49.   useEffect(() => {
  50.     if (isEmpty(files)) {
  51.       dispatch(getFiles(workspaceId));
  52.     }
  53.   }, [workspaceId]);
  54.  
  55.   useEffect(() => {
  56.     const fetchData = async () => {
  57.       const documentExportMap = files.find((file) => file.title === 'DocumentExportMap');
  58.  
  59.       if (documentExportMap) {
  60.         const { selectedMapFiles } = await dispatch(
  61.           getSelectedMapFiles(documentExportMap.id),
  62.         ).unwrap();
  63.         setFolderFiles(selectedMapFiles);
  64.       }
  65.     };
  66.  
  67.     if (!isEmpty(files)) {
  68.       fetchData();
  69.     }
  70.   }, [files]);
  71.  
  72.   const { searchTerm, setSearchTerm, filteredData } = useSearch(workspaceDocuments, ['name']);
  73.  
  74.   useEffect(() => {
  75.     setSearchTerm(getParam('search') ? getParam('search') : '');
  76.   }, [location.search]);
  77.  
  78.   const { getParam, setParam, setParams } = useSearchParamsHandler();
  79.  
  80.   const { handleTableChange, pagination, filteredValues } = useTableManagement(['updated_by']);
  81.  
  82.   useEffect(() => {
  83.     const defaultParams = {
  84.       order: getParam('order', 'updatedAt'),
  85.       dir: getParam('dir', 'DESC'),
  86.     };
  87.  
  88.     setParams(defaultParams);
  89.  
  90.     const fetchData = async () => {
  91.       startLoading();
  92.       await dispatch(getWorkspaceDocuments(workspaceId)).unwrap();
  93.       await dispatch(getWorkspaceNotes(workspaceId)).unwrap();
  94.       stopLoading();
  95.     };
  96.  
  97.     fetchData();
  98.   }, []);
  99.  
  100.   useEffect(() => {
  101.     setSearchTerm(getParam('search') ? getParam('search') : '');
  102.   }, [location.search]);
  103.  
  104.   const updatedByFilters = [
  105.     ...new Set(workspaceDocuments?.map((document) => document?.content?.updated_by)),
  106.   ].map((updated_by) => ({ text: updated_by, value: updated_by }));
  107.  
  108.   const commonColumns = [
  109.     {
  110.       title: t('document.list.table.name'),
  111.       dataIndex: 'name',
  112.       sorter: (a, b) => customComparator(a.name, b.name),
  113.       sortDirections: ['ascend', 'descend'],
  114.       sortOrder:
  115.         getParam('order') === 'name' ? (getParam('dir') === 'ASC' ? 'ascend' : 'descend') : null,
  116.       render: (name) => <div>{name}</div>,
  117.     },
  118.     {
  119.       title: t('document.list.table.details'),
  120.       dataIndex: 'details',
  121.       render: (details) => {
  122.         const plainText = parseQuillText(details);
  123.         const modifiedNote = truncateText(plainText, 3);
  124.  
  125.         return <p className='whitespace-pre-line'>{modifiedNote}</p>;
  126.       },
  127.     },
  128.     {
  129.       title: t('document.list.table.updatedAt'),
  130.       dataIndex: 'updatedAt',
  131.       sorter: (a, b) => {
  132.         const dateObjA = dayjs(a.updatedAt).isValid()
  133.           ? dayjs(a.updatedAt)
  134.           : dayjs(new Date(a.updatedAt));
  135.         const dateObjB = dayjs(b.updatedAt).isValid()
  136.           ? dayjs(b.updatedAt)
  137.           : dayjs(new Date(b.updatedAt));
  138.  
  139.         return dateObjA.isBefore(dateObjB) ? -1 : dateObjA.isAfter(dateObjB) ? 1 : 0;
  140.       },
  141.       sortDirections: ['ascend', 'descend'],
  142.       sortOrder:
  143.         getParam('order') === 'updatedAt'
  144.           ? getParam('dir') === 'ASC'
  145.             ? 'ascend'
  146.             : 'descend'
  147.           : null,
  148.       render: (updatedAt) => <div>{updatedAt}</div>,
  149.     },
  150.     {
  151.       title: t('document.list.table.updatedBy'),
  152.       dataIndex: 'updated_by',
  153.       sorter: (a, b) => customComparator(a.updated_by, b.updated_by),
  154.       sortDirections: ['ascend', 'descend'],
  155.       sortOrder:
  156.         getParam('order') === 'updated_by'
  157.           ? getParam('dir') === 'ASC'
  158.             ? 'ascend'
  159.             : 'descend'
  160.           : null,
  161.       filters: updatedByFilters,
  162.       filteredValue: filteredValues['updated_by'],
  163.       onFilter: (value, record) => record.updated_by === value,
  164.       render: (updated_by) => <div>{updated_by}</div>,
  165.     },
  166.     {
  167.       title: t('document.list.table.exportDocumentFile'),
  168.       dataIndex: 'export_file',
  169.       render: (export_file) =>
  170.         export_file && (
  171.           <a
  172.             href={export_file}
  173.             target='_blank'
  174.             rel='noreferrer'
  175.             onClick={(e) => e.stopPropagation()}
  176.           >
  177.             <LinkOutlined />
  178.           </a>
  179.         ),
  180.     },
  181.   ];
  182.  
  183.   const adminActionsColumn = {
  184.     title: t('note.list.table.actions'),
  185.     dataIndex: '',
  186.     key: 'x',
  187.     render: (record) => (
  188.       <Link
  189.         className='text-gray-600 hover:text-gray-400'
  190.         onClick={(event) => showConfirm(event, record, workspaceId)}
  191.       >
  192.         <DeleteOutlined />
  193.       </Link>
  194.     ),
  195.   };
  196.  
  197.   const columns = useMemo(() => {
  198.     const baseColumns = [...commonColumns];
  199.  
  200.     if (hasAdminRights) {
  201.       baseColumns.push(adminActionsColumn);
  202.     }
  203.  
  204.     return baseColumns;
  205.   }, [commonColumns, hasAdminRights, adminActionsColumn]);
  206.  
  207.   const showConfirm = (event, record, workspaceId) => {
  208.     event.stopPropagation();
  209.     modal.confirm({
  210.       title: t('note.list.modal.title'),
  211.       icon: <ExclamationCircleFilled />,
  212.       content: <p>{t('note.list.modal.description', { name: record.subject })}</p>,
  213.       okText: t('button.yes'),
  214.       okType: 'danger',
  215.       cancelText: t('button.no'),
  216.       onOk() {
  217.         const successMessage = t('notifications.group.notes.removeNote');
  218.         const documentId = record.id;
  219.  
  220.         dispatch(deleteWorkspaceDocument({ workspaceId, documentId, successMessage }));
  221.       },
  222.     });
  223.   };
  224.  
  225.   const data = useMemo(() => {
  226.     const data = map(!isEmpty(filteredData) ? filteredData : [], (document) => ({
  227.       key: document?.id,
  228.       id: document?.id,
  229.       name: document?.name,
  230.       updatedAt: new Date(document?.updatedAt).toLocaleString(),
  231.       details: document?.content?.details,
  232.       updated_by: document?.content?.updated_by,
  233.       export_file: folderFiles?.find((file) =>
  234.         file?.name?.includes(document?.name.replace(/\s+/g, '_')),
  235.       )?.content.url,
  236.     }));
  237.  
  238.     return data.sort((a, b) => customComparator(a.name, b.name));
  239.   }, [filteredData, folderFiles]);
  240.  
  241.   const handleRowClick = (record) => {
  242.     navigate(`${record.id}`);
  243.   };
  244.  
  245.   const searchHandler = (e) => {
  246.     setSearchTerm(e.target.value);
  247.     setParam('search', e.target.value === '' ? null : e.target.value);
  248.   };
  249.  
  250.   return (
  251.     <>
  252.       {isLoading ? null : isEmpty(workspaceDocuments) && !hasUserRights ? (
  253.         <CreateCard route={'create-document'} title={t('button.create')} icon={<BookOutlined />} />
  254.       ) : (
  255.         <>
  256.           <div className='my-5 flex w-full flex-wrap items-center justify-between gap-2'>
  257.             <Input
  258.               allowClear
  259.               className='order-2 w-full p-1.5 md:order-1 md:w-1/2 lg:w-1/3'
  260.               prefix={<SearchOutlined className='mx-2' />}
  261.               placeholder={t('document.list.searchPlaceholder')}
  262.               value={searchTerm}
  263.               onChange={(e) => {
  264.                 searchHandler(e);
  265.               }}
  266.             />
  267.  
  268.             <div className='order-1 flex gap-3 md:order-2'>
  269.               {!hasUserRights && (
  270.                 <Link to={`create-document`}>
  271.                   <Button type='primary' htmlType='button' icon={<PlusOutlined />}>
  272.                     {t('button.create')}
  273.                   </Button>
  274.                 </Link>
  275.               )}
  276.             </div>
  277.           </div>
  278.           <Table
  279.             columns={columns}
  280.             dataSource={data}
  281.             onChange={handleTableChange}
  282.             onRow={(record) => ({
  283.               onClick: () => {
  284.                 handleRowClick(record);
  285.               },
  286.               className: 'table-row-cursor-pointer',
  287.             })}
  288.             scroll={{ x: 300 }}
  289.             tableLayout='auto'
  290.             pagination={{
  291.               current: pagination.current,
  292.               defaultPageSize: pagination.pageSize,
  293.               total: !isEmpty(data) ? data.length : 0,
  294.               showTotal: (total) => `${t('global.paginationTotal', { total })}`,
  295.               showSizeChanger: true,
  296.               pageSizeOptions: pageSizeOptions,
  297.             }}
  298.           />
  299.         </>
  300.       )}
  301.     </>
  302.   );
  303. };
  304.  
  305. export default withLoadStatus(List);
  306.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement