- Added new methods for creating mailings and testing targets. - Updated configuration files for JWT settings and connection strings. - Introduced new DTOs for target column updates and test targets. - Enhanced MailingStatistic with a new SentDate property. - Created new components for handling cancelled mailings and target samples. - Refactored authentication in Login.tsx to use fetch API. - Updated various services and repositories to support new functionalities.
178 lines
7.5 KiB
TypeScript
178 lines
7.5 KiB
TypeScript
import { useState, useRef, useEffect } from 'react';
|
|
import { useSetupData, SetupData } from "@/context/SetupDataContext";
|
|
import EditIcon from '@mui/icons-material/Edit';
|
|
import AddIcon from '@mui/icons-material/Add';
|
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
import { List, Card, CardContent, Typography, Box, useTheme, useMediaQuery, CircularProgress, IconButton } from '@mui/material';
|
|
import { DataGrid, GridColDef, GridRenderCellParams, GridRowModel, GridToolbarContainer, GridToolbarQuickFilter, GridToolbarExport, GridToolbarDensitySelector, GridToolbarColumnsButton } from '@mui/x-data-grid';
|
|
import Mailing from '@/types/mailing';
|
|
//import Template from '@/types/template';
|
|
import MailingEdit from "@/components/modals/MailingEdit";
|
|
|
|
function NewMailings() {
|
|
const theme = useTheme();
|
|
const setupData: SetupData = useSetupData();
|
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
|
|
|
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
|
const [mailingsLoading, setMailingsLoading] = useState<boolean>(false);
|
|
const [mailings, setMailings] = useState<Mailing[]>([]);
|
|
const [selectedRow, setSelectedRow] = useState<Mailing | null>(null);
|
|
const [open, setOpen] = useState<boolean>(false);
|
|
|
|
const columns: GridColDef<Mailing>[] = [
|
|
{
|
|
field: "actions",
|
|
headerName: "",
|
|
sortable: false,
|
|
width: 60,
|
|
renderCell: (params: GridRenderCellParams<Mailing>) => (
|
|
<IconButton color="primary" onClick={(e) => { e.stopPropagation(); handleEdit(params.row); }}>
|
|
<EditIcon />
|
|
</IconButton>
|
|
),
|
|
},
|
|
{ field: "id", headerName: "ID", width: 80 },
|
|
{ field: "name", headerName: "Name", flex: 1, minWidth: 160 },
|
|
{ field: "description", headerName: "Description", flex: 1, minWidth: 200 },
|
|
{
|
|
field: "templateId",
|
|
headerName: "Subject",
|
|
flex: 1,
|
|
minWidth: 160,
|
|
valueGetter: (_: number, row: Mailing) => setupData.templates.find(t => t.id === row.templateId)?.subject || 'Unknown',
|
|
},
|
|
];
|
|
|
|
const reloadMailings = async () => {
|
|
setMailingsLoading(true);
|
|
|
|
const mailingsResponse = await fetch("/api/mailings/status/ed");
|
|
const mailingsData = await mailingsResponse.json();
|
|
if (mailingsData) {
|
|
setMailings(mailingsData);
|
|
setMailingsLoading(false);
|
|
}
|
|
else {
|
|
console.error("Failed to fetch mailings");
|
|
setMailingsLoading(false);
|
|
}
|
|
}
|
|
|
|
const handleNew = () => {
|
|
setSelectedRow(null);
|
|
setOpen(true);
|
|
};
|
|
|
|
const handleEdit = (row: GridRowModel<Mailing>) => {
|
|
setSelectedRow(row);
|
|
setOpen(true);
|
|
};
|
|
|
|
const handleUpdateRow = (updatedRow: Mailing) => {
|
|
if (updatedRow.statusCode.toUpperCase() !== "ED")
|
|
removeMailing(updatedRow);
|
|
else
|
|
updateMailings(updatedRow);
|
|
};
|
|
|
|
useEffect(() => {
|
|
reloadMailings();
|
|
}, []);
|
|
|
|
const removeMailing = (mailing: Mailing) => {
|
|
setMailings((prevMailings) => {
|
|
return prevMailings.filter(el => el.id !== mailing.id);
|
|
});
|
|
}
|
|
const updateMailings = (updatedMailing: Mailing) => {
|
|
setMailings((prev) => {
|
|
const exists = prev.some((e) => e.id === updatedMailing.id);
|
|
|
|
return exists
|
|
? prev.map((server) => (server.id === updatedMailing.id ? updatedMailing : server))
|
|
: [...prev, updatedMailing];
|
|
});
|
|
};
|
|
return (
|
|
<Box ref={gridContainerRef} sx={{
|
|
position: 'relative', left: 0, right: 0, height: "calc(100vh - 124px)", overflow: "hidden",
|
|
transition: theme.transitions.create(['width', 'height'], {
|
|
easing: theme.transitions.easing.easeInOut,
|
|
duration: theme.transitions.duration.standard,
|
|
})
|
|
}}>
|
|
<Box sx={{ position: 'absolute', inset: 0 }}>
|
|
{isMobile ? (
|
|
<List>
|
|
{mailings.map((row) => (
|
|
<Card key={row.id} sx={{ marginBottom: 2 }}>
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
<CardContent>
|
|
<Typography variant="h6">{row.name}</Typography>
|
|
<Typography variant="body2">ID: {row.id}</Typography>
|
|
<Typography variant="body2">Description: {row.description}</Typography>
|
|
<Typography variant="body2">Subject: {setupData.templates.find(t => t.id === row.templateId)?.subject || 'Unknown'}</Typography>
|
|
</CardContent>
|
|
<IconButton onClick={(e) => { e.stopPropagation(); handleEdit(row); }}>
|
|
<EditIcon />
|
|
</IconButton>
|
|
</Box>
|
|
</Card>
|
|
))}
|
|
</List>
|
|
) : (
|
|
<DataGrid
|
|
rows={mailings}
|
|
columns={columns}
|
|
autoPageSize
|
|
sx={{ minWidth: "600px" }}
|
|
slots={{
|
|
toolbar: () => (
|
|
<GridToolbarContainer sx={{ display: "flex", alignItems: "center" }}>
|
|
<IconButton size="small" color="primary" onClick={handleNew} sx={{ marginLeft: 1 }}>
|
|
<AddIcon />
|
|
</IconButton>
|
|
<IconButton size="small" color="primary" onClick={() => reloadMailings()} sx={{ marginLeft: 1 }}>
|
|
{mailingsLoading ? <CircularProgress size={24} color="inherit" /> : <RefreshIcon />}
|
|
</IconButton>
|
|
<GridToolbarColumnsButton />
|
|
<GridToolbarDensitySelector />
|
|
<GridToolbarExport />
|
|
<GridToolbarQuickFilter sx={{ ml: "auto" }} />
|
|
</GridToolbarContainer>
|
|
),
|
|
}}
|
|
slotProps={{
|
|
toolbar: {
|
|
showQuickFilter: true,
|
|
},
|
|
}}
|
|
initialState={{
|
|
pagination: {
|
|
paginationModel: {
|
|
pageSize: 20,
|
|
},
|
|
},
|
|
sorting: {
|
|
sortModel: [{ field: 'id', sort: 'asc' }],
|
|
},
|
|
}}
|
|
pageSizeOptions={[10, 20, 50, 100]}
|
|
/>
|
|
)}
|
|
</Box>
|
|
|
|
{open && (
|
|
<MailingEdit
|
|
open={open}
|
|
mailing={selectedRow}
|
|
onClose={(reason) => { if (reason !== 'backdropClick') setOpen(false) }}
|
|
onSave={handleUpdateRow}
|
|
/>
|
|
)}
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
export default NewMailings; |