Add TotalRows to TargetSample and update related components
- Updated `TargetSample` class to include `TotalRows` property. - Set `TotalRows` in `TargetRepository` based on database query. - Added state management for `targetSample` and loading in `MailingEdit.tsx`. - Modified rendering logic in `MailingEdit.tsx` to display total rows. - Updated `TargetSampleModal` to accept `targetSample` as a prop. - Created new `targetSample.ts` file defining the `TargetSample` interface.
This commit is contained in:
parent
51c267e48f
commit
712dbb5046
@ -10,6 +10,7 @@ namespace Surge365.MassEmailReact.Application.DTOs
|
||||
{
|
||||
public Dictionary<string, TargetSampleColumn> Columns { get; set; } = new Dictionary<string, TargetSampleColumn>();
|
||||
public List<Dictionary<string, string>> Rows { get; set; } = new List<Dictionary<string, string>>();
|
||||
public int TotalRows { get; set; } = 0;
|
||||
}
|
||||
public class TargetSampleColumn
|
||||
{
|
||||
|
||||
@ -218,6 +218,7 @@ namespace Surge365.MassEmailReact.Infrastructure.Repositories
|
||||
|
||||
// Build TargetSample
|
||||
var targetSample = new TargetSample();
|
||||
targetSample.TotalRows = rowCount;
|
||||
bool emailFound = false;
|
||||
bool uniqueIDFound = false;
|
||||
bool bounceFound = false;
|
||||
|
||||
@ -13,12 +13,15 @@ import {
|
||||
Box,
|
||||
MenuItem,
|
||||
Select,
|
||||
InputLabel
|
||||
InputLabel,
|
||||
Typography,
|
||||
CircularProgress
|
||||
} from "@mui/material";
|
||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||
|
||||
import Template from "@/types/template";
|
||||
import Mailing from "@/types/mailing";
|
||||
import TargetSample from "@/types/targetSample";
|
||||
import Target from "@/types/target";
|
||||
//import MailingTemplate from "@/types/mailingTemplate";
|
||||
//import MailingTarget from "@/types/mailingTarget";
|
||||
@ -234,6 +237,8 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
||||
const [currentTemplate, setCurrentTemplate] = useState<Template | null>(null);
|
||||
const [TargetSampleModalOpen, setTargetSampleModalOpen] = useState<boolean>(false);
|
||||
const [currentTarget, setCurrentTarget] = useState<Target | null>(null);
|
||||
const [targetSample, setTargetSample] = useState<TargetSample | null>(null);
|
||||
const [targetSampleLoading, setTargetSampleLoading] = useState(false);
|
||||
|
||||
const { register, trigger, control, handleSubmit, reset, setValue, formState: { errors } } = useForm<Mailing>({
|
||||
mode: "onBlur",
|
||||
@ -374,6 +379,29 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const fetchSampleData = async () => {
|
||||
if (!currentTarget?.id)
|
||||
return;
|
||||
|
||||
setTargetSampleLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/api/targets/${currentTarget.id}/sample`);
|
||||
if (!response.ok) throw new Error("Failed to fetch sample data");
|
||||
const data: TargetSample = await response.json();
|
||||
setTargetSample(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching target sample:", error);
|
||||
setTargetSample(null);
|
||||
} finally {
|
||||
setTargetSampleLoading(false);
|
||||
}
|
||||
};
|
||||
fetchSampleData();
|
||||
}
|
||||
}, [open, currentTarget?.id]);
|
||||
|
||||
const handleTestEmailListChange = (list: TestEmailList | null) => {
|
||||
if (list) {
|
||||
setTestEmailListId(list.id);
|
||||
@ -521,7 +549,7 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
{...field}
|
||||
label="To Name"
|
||||
label="From Name"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
error={!!errors.template?.fromName}
|
||||
@ -562,14 +590,21 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
||||
)}
|
||||
/>
|
||||
{currentTarget && (
|
||||
<Button
|
||||
onClick={handleTargetSampleModalOpen}
|
||||
variant="outlined"
|
||||
startIcon={<VisibilityIcon />}
|
||||
sx={{ height: '100%', alignSelf: 'center' }}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 0 }}>
|
||||
{targetSampleLoading ? (
|
||||
<CircularProgress size={16} sx={{ mb: 1 }} color="inherit" />
|
||||
) : (
|
||||
<Typography sx={{}}>Rows: {targetSample?.totalRows}</Typography>
|
||||
)}
|
||||
<Button
|
||||
onClick={handleTargetSampleModalOpen}
|
||||
variant="outlined"
|
||||
startIcon={<VisibilityIcon />}
|
||||
sx={{ height: '100%', alignSelf: 'center' }}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
<Autocomplete
|
||||
@ -692,10 +727,11 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
||||
onClose={() => { setTemplateViewerOpen(false) }}
|
||||
/>
|
||||
)}
|
||||
{TargetSampleModalOpen && (
|
||||
<TargetSampleModal
|
||||
open={TargetSampleModalOpen}
|
||||
target={currentTarget!}
|
||||
{TargetSampleModalOpen && currentTarget && (
|
||||
<TargetSampleModal
|
||||
open={TargetSampleModalOpen}
|
||||
target={currentTarget}
|
||||
targetSample={targetSample}
|
||||
onClose={() => { setTargetSampleModalOpen(false) }}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -6,52 +6,54 @@ import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
import Target from "@/types/target";
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import TargetSample from "@/types/targetSample";
|
||||
import TargetSampleDataGrid from "@/components/shared/TargetSampleDataGrid";
|
||||
import { GridColDef } from '@mui/x-data-grid';
|
||||
|
||||
type TargetSampleModalProps = {
|
||||
open: boolean;
|
||||
target: Target;
|
||||
targetSample?: TargetSample | null;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
type TargetSampleColumn = {
|
||||
name: string;
|
||||
type: string;
|
||||
};
|
||||
type TargetSample = {
|
||||
columns: { [key: string]: TargetSampleColumn }[];
|
||||
rows: { [key: string]: string }[];
|
||||
};
|
||||
|
||||
const TargetSampleModal = ({ open, target, onClose }: TargetSampleModalProps) => {
|
||||
const [targetSample, setTargetSample] = useState<TargetSample | null>(null);
|
||||
const TargetSampleModal = ({ open, target, targetSample, onClose }: TargetSampleModalProps) => {
|
||||
const [localTargetSample, setLocalTargetSample] = useState<TargetSample | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const fetchSampleData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/api/targets/${target.id}/sample`);
|
||||
if (!response.ok) throw new Error("Failed to fetch sample data");
|
||||
const data: TargetSample = await response.json();
|
||||
setTargetSample(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching target sample:", error);
|
||||
setTargetSample(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
if (targetSample) {
|
||||
setLocalTargetSample(targetSample);
|
||||
}
|
||||
else if (target.id) {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/api/targets/${target.id}/sample`);
|
||||
if (!response.ok) throw new Error("Failed to fetch sample data");
|
||||
const data: TargetSample = await response.json();
|
||||
setLocalTargetSample(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching target sample:", error);
|
||||
setLocalTargetSample(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setLocalTargetSample(null);
|
||||
}
|
||||
};
|
||||
fetchSampleData();
|
||||
}
|
||||
}, [open, target.id]);
|
||||
}, [open, targetSample, target.id]);
|
||||
|
||||
const columns: GridColDef[] = Object.keys(targetSample?.columns ?? {}).map((colName) => ({
|
||||
const columns: GridColDef[] = Object.keys(localTargetSample?.columns ?? {}).map((colName) => ({
|
||||
field: colName,
|
||||
headerName: colName,
|
||||
minWidth: 150,
|
||||
@ -60,9 +62,9 @@ const TargetSampleModal = ({ open, target, onClose }: TargetSampleModalProps) =>
|
||||
sortable: true,
|
||||
})) || [];
|
||||
|
||||
const rows = targetSample?.rows?.map((row, index) => {
|
||||
const rows = localTargetSample?.rows?.map((row, index) => {
|
||||
const rowData: { [key: string]: string } = { id: index.toString() };
|
||||
Object.keys(targetSample?.columns || {}).forEach((key) => {
|
||||
Object.keys(localTargetSample?.columns || {}).forEach((key) => {
|
||||
rowData[key] = row[key] ?? "";
|
||||
});
|
||||
return rowData;
|
||||
@ -113,6 +115,7 @@ const TargetSampleModal = ({ open, target, onClose }: TargetSampleModalProps) =>
|
||||
</Box>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography sx={{ mb: 1, fontWeight: 'bold' }} >Total Rows: {localTargetSample?.totalRows}</Typography>
|
||||
<TargetSampleDataGrid columns={columns} rows={rows} />
|
||||
</DialogContent>
|
||||
</>
|
||||
|
||||
8
Surge365.MassEmailReact.Web/src/types/targetSample.ts
Normal file
8
Surge365.MassEmailReact.Web/src/types/targetSample.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { TargetSampleColumn } from './targetSampleColumn';
|
||||
export interface TargetSample {
|
||||
columns: { [key: string]: TargetSampleColumn }[];
|
||||
rows: { [key: string]: string }[];
|
||||
totalRows: number;
|
||||
}
|
||||
|
||||
export default TargetSample;
|
||||
Loading…
x
Reference in New Issue
Block a user