Spaces:
Runtime error
Runtime error
import { t } from 'i18next'; | |
import { useCallback, useEffect, useState } from 'react'; | |
import { useNavigate } from 'react-router-dom'; | |
import { toast } from 'sonner'; | |
import DefaultRadioGroup from '../../components/button/DefaultRadioGroup'; | |
import PrimaryButton from '../../components/button/PrimaryButton'; | |
import SelectDropdown from '../../components/dropdown/SelectDropdown'; | |
import SimpleInput from '../../components/input/SimpleInput'; | |
import Modal from '../../components/modal/Modal'; | |
import PrimarySwitch from '../../components/switch/PrimarySwitch'; | |
import type { Column } from '../../components/table/UITable'; | |
import UITable from '../../components/table/UITable'; | |
import { useSortableTable } from '../../hooks/useSortableTable'; | |
import { useTableFiltering } from '../../hooks/useTableFiltering'; | |
import type { Audit } from '../../services/audits'; | |
import { | |
createAudit, | |
deleteAudit, | |
fetchUsername, | |
generateReport, | |
getAudits, | |
getLanguages, | |
getTypes, | |
} from '../../services/audits'; | |
type RowAction = { | |
label: string; | |
onClick: (item: TableData) => void; | |
}; | |
type ListItem = { | |
id: number; | |
value: string; | |
label?: string; | |
}; | |
const RadioOptions = [ | |
{ id: '1', label: t('default'), value: '1' }, | |
{ id: '2', label: t('multi'), value: '2' }, | |
]; | |
type TypeData = { | |
name: string; | |
templates: { | |
template: string; | |
locale: string; | |
}[]; | |
sections: string[]; | |
hidden: string[]; | |
stage: string; | |
}; | |
type LanguageData = { | |
language: string; | |
locale: string; | |
}; | |
type TableData = { | |
id: string; | |
Name: string; | |
AuditType: string; | |
Language: string; | |
Company: string; | |
Participants: string; | |
Date: string; | |
}; | |
export const Audits = () => { | |
const navigate = useNavigate(); | |
const [myAudits, setMyAudits] = useState(false); | |
const [usersConnected, setUsersConnected] = useState(false); | |
const [isOpenNewAuditModal, setIsOpenNewAuditModal] = useState(false); | |
const [selectedValue, setSelectedValue] = useState('1'); | |
const [nameAudit, setNameAudit] = useState<string>(''); | |
const [auditType, setAuditType] = useState<ListItem[]>([]); | |
const [currentAuditType, setCurrentAuditType] = useState<ListItem | null>( | |
null, | |
); | |
const [loadingAuditType, setLoadingAuditType] = useState<boolean>(false); | |
const [languages, setLanguages] = useState<ListItem[]>([]); | |
const [currentLanguage, setCurrentLanguage] = useState<ListItem | null>(null); | |
const [loadingLanguage, setLoadingLanguage] = useState<boolean>(true); | |
const [isOpenModalDeleteAudit, setIsOpenModalDeleteAudit] = useState(false); | |
const [itemDelete, setItemDelete] = useState<TableData>(); | |
const columns: Column[] = [ | |
{ header: t('name'), accessor: 'Name', sortable: true, filterable: true }, | |
{ | |
header: t('auditType'), | |
accessor: 'AuditType', | |
sortable: true, | |
filterable: true, | |
}, | |
{ | |
header: t('language'), | |
accessor: 'Language', | |
sortable: true, | |
filterable: true, | |
}, | |
{ | |
header: t('company'), | |
accessor: 'Company', | |
sortable: true, | |
filterable: true, | |
}, | |
{ | |
header: t('participants'), | |
accessor: 'Participants', | |
sortable: true, | |
filterable: true, | |
}, | |
{ header: t('date'), accessor: 'Date', sortable: true, filterable: true }, | |
]; | |
const [filteredData, setFilteredData] = useState<TableData[]>([]); | |
const [tableData, handleSorting, setTableData] = useSortableTable<TableData>( | |
filteredData, | |
columns, | |
); | |
const [filters, handleFilterChange] = useTableFiltering<TableData>( | |
filteredData, | |
columns, | |
setTableData, | |
); | |
const fetchAndUpdateData = useCallback(async () => { | |
const dataAudits = await getAudits().then(res => { | |
return res.datas.map((audit: Audit) => ({ | |
id: audit._id, | |
Name: audit.name, | |
AuditType: audit.auditType, | |
Language: audit.language, | |
Company: audit.company?.name ?? '', | |
Participants: audit.collaborators.map(user => user.username).join(', '), | |
Date: new Date(audit.createdAt).toLocaleString(), | |
})); | |
}); | |
setTableData(dataAudits); | |
setFilteredData(dataAudits); | |
}, [setTableData, setFilteredData]); | |
const confirmDeleteAudit = async () => { | |
try { | |
const response = await deleteAudit(itemDelete?.id ?? ''); | |
if (response.status === 'success') { | |
toast.success(t('msg.auditDeletedOk')); | |
void fetchAndUpdateData(); | |
} | |
} catch (error) { | |
toast.error(t('err.failedDeleteAudit')); | |
console.error('Error:', error); | |
} | |
setIsOpenModalDeleteAudit(false); | |
}; | |
const deleteRegisterConfirmation = (item: TableData) => { | |
setItemDelete(item); | |
setIsOpenModalDeleteAudit(true); | |
}; | |
const rowActions: RowAction[] = [ | |
{ | |
label: 'Edit', | |
onClick: (item: TableData) => navigate(`/audits/${item.id}/general`), | |
}, | |
{ | |
label: 'Download', | |
onClick: (item: TableData) => generateReport(item.id, window), | |
}, | |
{ | |
label: 'Delete', | |
onClick: (item: TableData) => deleteRegisterConfirmation(item), | |
}, | |
]; | |
useEffect(() => { | |
fetchUsername() | |
.then(username => { | |
handleFilterChange( | |
'Participants', | |
myAudits ? username.datas.username : '', | |
); | |
}) | |
.catch(console.error); | |
// Desactivado porque realmente no se debe gatillar el efecto cada vez que cambia handleFilterChange a través del useTableFiltering | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [myAudits]); | |
useEffect(() => { | |
const fetchData = async () => { | |
try { | |
const dataLanguage = await getLanguages(); | |
const languageNames = dataLanguage.datas.map( | |
(item: LanguageData, index: number) => ({ | |
id: index, | |
value: item.locale, | |
label: item.language, | |
}), | |
); | |
setLanguages(languageNames); | |
setCurrentLanguage(languageNames[0]); | |
setLoadingLanguage(false); | |
const dataType = await getTypes(); | |
const typeNames = dataType.datas.map( | |
(item: TypeData, index: number): ListItem => ({ | |
id: index, | |
value: item.name, | |
}), | |
); | |
setAuditType(typeNames); | |
setLoadingAuditType(false); | |
void fetchAndUpdateData(); | |
} catch (err) { | |
setLoadingLanguage(false); | |
} | |
}; | |
fetchData().catch(console.error); | |
}, [currentAuditType, fetchAndUpdateData]); | |
const handleCancelNewAudit = () => { | |
setCurrentAuditType(null); | |
setCurrentLanguage(null); | |
setSelectedValue('1'); | |
setNameAudit(''); | |
setIsOpenNewAuditModal(!isOpenNewAuditModal); | |
}; | |
const handleSubmitNewAudit = async () => { | |
if (!currentAuditType || !currentLanguage) { | |
return; // TODO: Show error | |
} | |
try { | |
await createAudit({ | |
name: nameAudit, | |
auditType: currentAuditType.value, | |
language: currentLanguage.value, | |
type: selectedValue, | |
}).catch(error => { | |
toast.error(error.message); | |
}); | |
setCurrentAuditType(null); | |
setCurrentLanguage(null); | |
setSelectedValue('1'); | |
setNameAudit(''); | |
void fetchAndUpdateData(); | |
} catch (error) { | |
console.error('Error:', error); | |
} | |
setIsOpenNewAuditModal(!isOpenNewAuditModal); | |
}; | |
return ( | |
<div className="min-h-screen bg-gray-800 flex flex-col items-center"> | |
<div className="w-full max-w-7xl bg-gray-900 shadow-lg rounded-lg p-6 mt-6"> | |
<div className="flex items-center mb-4"> | |
<div className="ml-1"> | |
<span className="mx-1">{t('myAudits')}</span> | |
<PrimarySwitch enabled={myAudits} onChange={setMyAudits} /> | |
</div> | |
<div className="ml-1"> | |
<span className="mx-1">{t('usersConnected')}</span> | |
<PrimarySwitch | |
enabled={usersConnected} | |
onChange={setUsersConnected} | |
/> | |
</div> | |
<div className="mt-2 mx-2 ml-auto"> | |
<PrimaryButton | |
onClick={() => setIsOpenNewAuditModal(!isOpenNewAuditModal)} | |
> | |
{t('newAudit')} | |
</PrimaryButton> | |
</div> | |
</div> | |
<Modal | |
cancelText={t('btn.cancel')} | |
disablehr={true} | |
isOpen={isOpenModalDeleteAudit} | |
onCancel={() => setIsOpenModalDeleteAudit(false)} | |
onSubmit={confirmDeleteAudit} | |
submitText={t('btn.confirm')} | |
title={t('msg.confirmSuppression')} | |
> | |
<span className="ml-3">{t('msg.auditDeleteNotice')}</span> | |
</Modal> | |
<Modal | |
cancelText={t('btn.cancel')} | |
isOpen={isOpenNewAuditModal} | |
onCancel={handleCancelNewAudit} | |
onSubmit={handleSubmitNewAudit} | |
submitText={t('btn.create')} | |
title={t('createAudit')} | |
> | |
<DefaultRadioGroup | |
name="AuditType" | |
onChange={setSelectedValue} | |
options={RadioOptions} | |
value={selectedValue} | |
/> | |
<SimpleInput | |
id="name" | |
label={t('name')} | |
name="name" | |
onChange={setNameAudit} | |
placeholder={t('name')} | |
type="text" | |
value={nameAudit} | |
/> | |
{!loadingAuditType ? ( | |
<SelectDropdown | |
items={auditType} | |
onChange={setCurrentAuditType} | |
selected={currentAuditType} | |
title={t('auditType')} | |
/> | |
) : null} | |
{!loadingLanguage ? ( | |
<SelectDropdown | |
items={languages} | |
onChange={setCurrentLanguage} | |
selected={currentLanguage} | |
title={t('language')} | |
/> | |
) : null} | |
</Modal> | |
<div className="flex justify-between items-center mb-4" /> | |
<UITable | |
columns={columns} | |
data={tableData} | |
emptyState={t('err.noMatchingRecords')} | |
filters={filters} | |
keyExtractor={item => item.id} | |
onFilter={handleFilterChange} | |
onSort={handleSorting} | |
rowActions={rowActions} | |
sortable={true} | |
/> | |
</div> | |
</div> | |
); | |
}; | |