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 SelectDropdown from '../../components/dropdown/SelectDropdown'; 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 { Client, createClient, deleteClient, getClients, getCompanies, NewClient, updateClient, } from '../../services/data'; type Company = { _id?: string; name: string; shortName: string; logo: string; }; type TableData = { _id: string; email: string; lastname: string; firstname: string; phone: string; cell: string; title: string; company: string; }; type ListItem = { id: number; _id?: string; name?: string; shortName?: string; logo?: string; value: string; }; export const Clients: React.FC = () => { const { t } = useTranslation(); const columns = [ { header: t('firstname'), accessor: 'firstname', sortable: true, filterable: true, }, { header: t('lastname'), accessor: 'lastname', sortable: true, filterable: true, }, { header: t('email'), accessor: 'email', sortable: true, filterable: true }, { header: t('company'), accessor: 'company', sortable: true, render: (data?: { name: string }) => data?.name ? {data.name} : -, }, ]; const [companies, setCompanies] = useState([]); const [apiCompanies, setApiCompanies] = useState([]); const [addModalFirstnameRequiredAlert, setAddModalFirstnameRequiredAlert] = useState(false); const [addModalLastnameRequiredAlert, setAddModalLastnameRequiredAlert] = useState(false); const [addModalEmailRequiredAlert, setAddModalEmailRequiredAlert] = useState(false); const [editModalFirstnameRequiredAlert, setEditModalFirstnameRequiredAlert] = useState(false); const [editModalLastnameRequiredAlert, setEditModalLastnameRequiredAlert] = useState(false); const [editModalEmailRequiredAlert, setEditModalEmailRequiredAlert] = useState(false); const [selectedCompany, setSelectedCompany] = useState({ id: 0, _id: '', value: '', }); const initialClientState = { company: null, firstname: '', lastname: '', email: '', title: '', phone: '', cell: '', }; const [newClient, setNewClient] = useState( initialClientState, ); const [clients, setClients] = useState([]); const [_loading, setLoading] = useState(true); const [_error, setError] = useState(null); const [selectedClient, setSelectedClient] = useState(null); const [tableData, handleSorting, setTableData] = useSortableTable( clients, columns, // error en useSortableTable o UITable ); const [isOpenAddClientModal, setIsOpenAddClientModal] = useState(false); const [isOpenEditClientModal, setIsOpenEditClientModal] = useState(false); const [isOpenDeleteClientModal, setIsOpenDeleteClientModal] = useState(false); const fetchClients = useCallback(async () => { try { const data = await getClients(); setClients(data.datas); setTableData(data.datas); setLoading(false); } catch (err) { setError('Error fetching clients'); setLoading(false); } }, [setTableData]); const fetchCompanies = async () => { try { const data: { datas: Company[] } = await getCompanies(); const filteredData = data.datas.map((item, index) => ({ id: index + 1, _id: item._id ?? '', value: item.name, })); setCompanies(filteredData); setApiCompanies(data.datas); setSelectedCompany(filteredData[0]); setLoading(false); } catch (err) { setError('Error fetching company'); setLoading(false); } }; useEffect(() => { void fetchClients(); void fetchCompanies(); }, [fetchClients]); const keyExtractor = (item: TableData) => item._id; const handleEditClientButton = (client: TableData) => { const matchingCompany = apiCompanies.find( company => company.name === client.company, ); setNewClient({ _id: client._id, email: client.email, lastname: client.lastname, firstname: client.firstname, phone: client.phone, cell: client.cell, title: client.title, company: matchingCompany ? { _id: matchingCompany._id, name: matchingCompany.name, shortName: matchingCompany.shortName, logo: matchingCompany.logo, } : null, }); setIsOpenEditClientModal(!isOpenEditClientModal); }; const handleDeleteClientButton = (client: TableData) => { setSelectedClient(client); setIsOpenDeleteClientModal(!isOpenDeleteClientModal); }; const rowActions = [ { label: 'Edit', onClick: (item: TableData) => handleEditClientButton(item), }, { label: 'Delete', onClick: (item: TableData) => handleDeleteClientButton(item), }, ]; const [filters, handleFilterChange] = useTableFiltering( clients, columns, // error en useSortableTable o UITable setTableData, ); const handleCancelAddClient = () => { setNewClient(initialClientState); setIsOpenAddClientModal(!isOpenAddClientModal); setAddModalFirstnameRequiredAlert(false); setAddModalLastnameRequiredAlert(false); setAddModalEmailRequiredAlert(false); }; const handleSubmitAddClient = async () => { if (!newClient) { return; } if ( selectedCompany.id === 0 && selectedCompany.value === '' && selectedCompany._id === '' ) { return; } let isValid = true; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!newClient.firstname || newClient.firstname.trim() === '') { setAddModalFirstnameRequiredAlert(true); isValid = false; } if (!newClient.lastname || newClient.lastname.trim() === '') { setAddModalLastnameRequiredAlert(true); isValid = false; } if (!newClient.email || newClient.email.trim() === '') { setAddModalEmailRequiredAlert(true); isValid = false; } if (!isValid) { toast.error(t('msg.fieldRequired')); return; } if (!emailRegex.test(newClient.email)) { toast.error(t('msg.invalidEmail')); return; } try { const matchingCompany = apiCompanies.find( company => company._id === selectedCompany._id, ); if (!matchingCompany) { setError('Selected company not found'); return; } const clientToCreate = { ...newClient, company: { _id: matchingCompany._id, name: matchingCompany.name, shortName: matchingCompany.shortName, logo: matchingCompany.logo, }, }; await createClient(clientToCreate); toast.success(t('msg.clientCreatedOk')); setIsOpenAddClientModal(!isOpenAddClientModal); setNewClient(initialClientState); void fetchClients(); } catch (error) { toast.error(t('msg.clientEmailError')); setError('Error creating client'); console.error('Error:', error); } }; const handleCancelEditClient = () => { setNewClient(initialClientState); setIsOpenEditClientModal(!isOpenEditClientModal); setEditModalFirstnameRequiredAlert(false); setEditModalLastnameRequiredAlert(false); setEditModalEmailRequiredAlert(false); }; const handleSubmitEditClient = async () => { if (!newClient) { return; } if ( selectedCompany.id === 0 && selectedCompany.value === '' && selectedCompany._id === '' ) { return; } let isValid = true; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!newClient.firstname || newClient.firstname.trim() === '') { setEditModalFirstnameRequiredAlert(true); isValid = false; } if (!newClient.lastname || newClient.lastname.trim() === '') { setEditModalLastnameRequiredAlert(true); isValid = false; } if (!newClient.email || newClient.email.trim() === '') { setEditModalEmailRequiredAlert(true); isValid = false; } if (!isValid) { toast.error(t('msg.fieldRequired')); return; } if (!emailRegex.test(newClient.email)) { toast.error(t('msg.invalidEmail')); return; } try { const matchingCompany = apiCompanies.find( company => company._id === selectedCompany._id, ); if (!matchingCompany) { setError('Selected company not found'); return; } const clientToUpdate = { ...newClient, company: { _id: matchingCompany._id, name: matchingCompany.name, shortName: matchingCompany.shortName, logo: matchingCompany.logo, }, }; await updateClient(clientToUpdate); toast.success(t('msg.clientUpdatedOk')); setIsOpenEditClientModal(!isOpenEditClientModal); setNewClient(initialClientState); void fetchClients(); } catch (error) { toast.error(t('msg.clientEmailError')); setError('Error updating client'); console.error('Error:', error); } }; const handleCancelDeleteClient = () => { setIsOpenDeleteClientModal(!isOpenDeleteClientModal); }; const handleSubmitDeleteClient = async () => { if (selectedClient?._id) { try { await deleteClient(selectedClient._id); toast.success(t('msg.clientDeletedOk')); } catch (error) { setError('Error deleting client'); console.error('Error:', error); } setSelectedClient(null); setIsOpenDeleteClientModal(!isOpenDeleteClientModal); void fetchClients(); } }; const handleInputChange = (name: string, value: string) => { setNewClient(prevState => { if (!prevState) { return null; } else { return { ...prevState, [name]: value, }; } }); }; const handleCompanyChange = (company: ListItem) => { setSelectedCompany(company); setNewClient(prevState => { if (!prevState) { return null; } else { return { ...prevState, company: { id: company.id, _id: company._id, name: company.name ?? '', shortName: company.shortName ?? '', logo: company.logo ?? '', }, }; } }); }; return ( <> <>
setIsOpenAddClientModal(!isOpenAddClientModal)} > {t('addClient')}
{t('err.noMatchingRecords')}} filters={filters} keyExtractor={keyExtractor} onFilter={handleFilterChange} onSort={handleSorting} rowActions={rowActions} />
<> handleInputChange('firstname', value)} placeholder={t('firstname')} requiredAlert={addModalFirstnameRequiredAlert} requiredField type="text" value={newClient?.firstname ?? ''} /> handleInputChange('lastname', value)} placeholder={t('lastname')} requiredAlert={addModalLastnameRequiredAlert} requiredField type="text" value={newClient?.lastname ?? ''} /> handleInputChange('email', value)} placeholder={t('email')} requiredAlert={addModalEmailRequiredAlert} requiredField type="text" value={newClient?.email ?? ''} /> handleInputChange('title', value)} placeholder={t('title')} type="text" value={newClient?.title ?? ''} /> handleInputChange('phone', value)} placeholder={t('phone')} type="text" value={newClient?.phone ?? ''} /> handleInputChange('cell', value)} placeholder={t('cell')} type="text" value={newClient?.cell ?? ''} /> <> handleInputChange('firstname', value)} placeholder={t('firstname')} requiredAlert={editModalFirstnameRequiredAlert} requiredField type="text" value={newClient?.firstname ?? ''} /> handleInputChange('lastname', value)} placeholder={t('lastname')} requiredAlert={editModalLastnameRequiredAlert} requiredField type="text" value={newClient?.lastname ?? ''} /> handleInputChange('email', value)} placeholder={t('email')} requiredAlert={editModalEmailRequiredAlert} requiredField type="text" value={newClient?.email ?? ''} /> handleInputChange('title', value)} placeholder={t('title')} type="text" value={newClient?.title ?? ''} /> handleInputChange('phone', value)} placeholder={t('phone')} type="text" value={newClient?.phone ?? ''} /> handleInputChange('cell', value)} placeholder={t('cell')} type="text" value={newClient?.cell ?? ''} />

{t('client') + ` <<${selectedClient?.firstname} ` + `${selectedClient?.lastname}>> ` + t('msg.deleteNotice') + '!'}

); };