Spaces:
Runtime error
Runtime error
import { useCallback, useEffect, useState } from 'react'; | |
import { useTranslation } from 'react-i18next'; | |
import { toast } from 'sonner'; | |
import PrimaryButton from '../../components/button/PrimaryButton'; | |
import Card from '../../components/card/Card'; | |
import FileInput from '../../components/input/FileInput'; | |
import SimpleInput from '../../components/input/SimpleInput'; | |
import Modal from '../../components/modal/Modal'; | |
import UITable from '../../components/table/UITable'; | |
import { useSortableTable } from '../../hooks/useSortableTable'; | |
import { useTableFiltering } from '../../hooks/useTableFiltering'; | |
import { | |
createTemplate, | |
deleteTemplate, | |
downloadTemplate, | |
getTemplates, | |
updateTemplate, | |
} from '../../services/data'; | |
type NewTemplate = { | |
id?: string; | |
name: string; | |
ext: string; | |
file: string; | |
}; | |
type TableData = { | |
_id?: string; | |
name: string; | |
ext: string; | |
file: string; | |
}; | |
export const Templates: React.FC = () => { | |
const { t } = useTranslation(); | |
const initialTemplateState = { | |
name: '', | |
ext: '', | |
file: '', | |
}; | |
const [newTemplate, setNewTemplate] = useState<NewTemplate | null>( | |
initialTemplateState, | |
); | |
const [templates, setTemplates] = useState<NewTemplate[]>([]); | |
const [_loading, setLoading] = useState<boolean>(true); | |
const [_error, setError] = useState<string | null>(null); | |
const [addModalNameRequiredAlert, setAddModalFirstnameRequiredAlert] = | |
useState<boolean>(false); | |
const [addModalFileRequiredAlert, setAddModalFileRequiredAlert] = | |
useState<boolean>(false); | |
const [editModalNameRequiredAlert, setEditModalFirstnameRequiredAlert] = | |
useState<boolean>(false); | |
const [selectedTemplate, setSelectedTemplate] = useState<TableData | null>( | |
null, | |
); | |
const columns = [ | |
{ header: t('name'), accessor: 'name', sortable: true, filterable: true }, | |
{ | |
header: t('extension'), | |
accessor: 'ext', | |
sortable: true, | |
filterable: true, | |
}, | |
]; | |
const [tableData, handleSorting, setTableData] = useSortableTable<TableData>( | |
templates, | |
columns, | |
); | |
const [filters, handleFilterChange] = useTableFiltering<TableData>( | |
templates, | |
columns, | |
setTableData, | |
); | |
const [isOpenAddTemplateModal, setIsOpenAddTemplateModal] = useState(false); | |
const [isOpenEditTemplateModal, setIsOpenEditTemplateModal] = useState(false); | |
const [isOpenDeleteTemplateModal, setIsOpenDeleteTemplateModal] = | |
useState(false); | |
const fetchTemplates = useCallback(async () => { | |
try { | |
const data = await getTemplates(); | |
setTemplates(data.datas); | |
setTableData(data.datas); | |
setLoading(false); | |
} catch (err) { | |
setError('Error fetching company'); | |
setLoading(false); | |
} | |
}, [setTableData]); | |
useEffect(() => { | |
void fetchTemplates(); | |
}, [fetchTemplates]); | |
const keyExtractor = (item: TableData) => item._id ?? ''; | |
const handleEditTemplateButton = (template: TableData) => { | |
setNewTemplate(prevState => { | |
if (!prevState) { | |
return null; | |
} else { | |
return { | |
...prevState, | |
_id: template._id, | |
name: template.name, | |
}; | |
} | |
}); | |
setIsOpenEditTemplateModal(true); | |
}; | |
const handleDeleteTemplateButton = (template: TableData) => { | |
setSelectedTemplate(template); | |
setIsOpenDeleteTemplateModal(!isOpenDeleteTemplateModal); | |
}; | |
const rowActions = [ | |
{ | |
label: 'Edit', | |
onClick: (item: TableData) => handleEditTemplateButton(item), | |
}, | |
{ | |
label: 'Download', | |
onClick: (item: TableData) => downloadTemplate(item._id ?? '', window), | |
}, | |
{ | |
label: 'Delete', | |
onClick: (item: TableData) => handleDeleteTemplateButton(item), | |
}, | |
]; | |
const handleCancelAddTemplate = () => { | |
setNewTemplate(initialTemplateState); | |
setIsOpenAddTemplateModal(!isOpenAddTemplateModal); | |
setAddModalFirstnameRequiredAlert(false); | |
setAddModalFileRequiredAlert(false); | |
}; | |
const handleSubmitAddTemplate = async () => { | |
let isValid = true; | |
if (!newTemplate?.name || newTemplate.name.trim() === '') { | |
setAddModalFirstnameRequiredAlert(true); | |
isValid = false; | |
} | |
if (!newTemplate?.file || newTemplate.file.trim() === '') { | |
setAddModalFileRequiredAlert(true); | |
isValid = false; | |
} | |
if (!isValid) { | |
toast.error(t('msg.fieldRequired')); | |
return; | |
} | |
try { | |
if (!newTemplate) { | |
return null; | |
} else { | |
await createTemplate({ ...newTemplate, name: newTemplate.name.trim() }); | |
toast.success(t('msg.templateCreatedOk')); | |
setIsOpenAddTemplateModal(!isOpenAddTemplateModal); | |
setNewTemplate(initialTemplateState); | |
void fetchTemplates(); | |
} | |
} catch (error) { | |
toast.error(t('msg.templateNameError')); | |
setError('Error creating template'); | |
console.error('Error:', error); | |
} | |
}; | |
const handleCancelEditTemplate = () => { | |
setNewTemplate(initialTemplateState); | |
setIsOpenEditTemplateModal(!isOpenEditTemplateModal); | |
setEditModalFirstnameRequiredAlert(false); | |
}; | |
const handleSubmitEditTemplate = async () => { | |
let isValid = true; | |
if (!newTemplate?.name || newTemplate.name.trim() === '') { | |
setEditModalFirstnameRequiredAlert(true); | |
isValid = false; | |
} | |
if (!isValid) { | |
toast.error(t('msg.fieldRequired')); | |
return; | |
} | |
try { | |
if (!newTemplate) { | |
return null; | |
} else { | |
await updateTemplate({ ...newTemplate, name: newTemplate.name.trim() }); | |
toast.success(t('msg.templateUpdatedOk')); | |
setIsOpenEditTemplateModal(!isOpenEditTemplateModal); | |
setNewTemplate(initialTemplateState); | |
void fetchTemplates(); | |
} | |
} catch (error) { | |
toast.error(t('msg.templateNameError')); | |
setError('Error updating template'); | |
console.error('Error:', error); | |
} | |
}; | |
const handleCancelDeleteTemplate = () => { | |
setIsOpenDeleteTemplateModal(!isOpenDeleteTemplateModal); | |
}; | |
const handleSubmitDeleteTemplate = async () => { | |
if (selectedTemplate?._id) { | |
try { | |
await deleteTemplate(selectedTemplate._id); | |
toast.success(t('msg.templateDeletedOk')); | |
} catch (error) { | |
setError('Error deleting template'); | |
console.error('Error:', error); | |
} | |
setSelectedTemplate(null); | |
setIsOpenDeleteTemplateModal(!isOpenDeleteTemplateModal); | |
void fetchTemplates(); | |
} | |
}; | |
const handleInputChange = (name: string, value: string) => { | |
setNewTemplate(prevState => { | |
if (!prevState) { | |
return null; | |
} else { | |
return { | |
...prevState, | |
[name]: value, | |
}; | |
} | |
}); | |
}; | |
const handleFileSelect = (ext: string, content: string) => { | |
const base64Content = content.split(',')[1] || ''; | |
setNewTemplate(prevState => { | |
if (!prevState) { | |
return null; | |
} else { | |
return { | |
...prevState, | |
ext, | |
file: base64Content.trim(), | |
}; | |
} | |
}); | |
}; | |
return ( | |
<> | |
<Card title={t('templates')}> | |
<> | |
<div className="flex justify-end mb-2 mr-2"> | |
<PrimaryButton | |
onClick={() => setIsOpenAddTemplateModal(!isOpenAddTemplateModal)} | |
> | |
{t('createTemplate')} | |
</PrimaryButton> | |
</div> | |
<UITable | |
columns={columns} | |
data={tableData} | |
emptyState={<div>{t('err.noMatchingRecords')}</div>} | |
filters={filters} | |
keyExtractor={keyExtractor} | |
onFilter={handleFilterChange} | |
onSort={handleSorting} | |
rowActions={rowActions} | |
/> | |
</> | |
</Card> | |
<Modal | |
// eslint-disable-next-line sonarjs/no-duplicate-string | |
cancelText={t('btn.cancel')} | |
isOpen={isOpenAddTemplateModal} | |
onCancel={handleCancelAddTemplate} | |
onSubmit={handleSubmitAddTemplate} | |
submitText={t('btn.create')} | |
title={t('createTemplate')} | |
> | |
<> | |
<SimpleInput | |
id="name" | |
label={t('name')} | |
name="name" | |
onChange={value => handleInputChange('name', value)} | |
placeholder={t('name')} | |
requiredAlert={addModalNameRequiredAlert} | |
requiredField | |
type="text" | |
value={newTemplate?.name ?? ''} | |
/> | |
<FileInput | |
id="template" | |
label={t('file')} | |
name="template" | |
onFileSelect={file => | |
handleFileSelect(file.name.split('.').pop() ?? '', file.content) | |
} | |
requiredAlert={addModalFileRequiredAlert} | |
requiredField | |
/> | |
</> | |
</Modal> | |
<Modal | |
cancelText={t('btn.cancel')} | |
isOpen={isOpenEditTemplateModal} | |
onCancel={handleCancelEditTemplate} | |
onSubmit={handleSubmitEditTemplate} | |
submitText={t('btn.update')} | |
title={t('editTemplate')} | |
> | |
<> | |
<SimpleInput | |
id="name" | |
label={t('name')} | |
name="name" | |
onChange={value => handleInputChange('name', value)} | |
placeholder={newTemplate?.name ?? t('name')} | |
requiredAlert={editModalNameRequiredAlert} | |
requiredField | |
type="text" | |
value={newTemplate?.name ?? ''} | |
/> | |
<FileInput | |
id="template" | |
name="template" | |
onFileSelect={file => | |
handleFileSelect(file.name.split('.').pop() ?? '', file.content) | |
} | |
/> | |
</> | |
</Modal> | |
<Modal | |
cancelText={t('btn.cancel')} | |
isOpen={isOpenDeleteTemplateModal} | |
onCancel={handleCancelDeleteTemplate} | |
onSubmit={handleSubmitDeleteTemplate} | |
submitText={t('btn.confirm')} | |
title={t('msg.confirmSuppression')} | |
> | |
<p> | |
{t('template') + | |
` <<${selectedTemplate?.name}>> ` + | |
t('msg.deleteNotice') + | |
'!'} | |
</p> | |
</Modal> | |
</> | |
); | |
}; | |