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 Dictionary<string, TargetSampleColumn> Columns { get; set; } = new Dictionary<string, TargetSampleColumn>();
|
||||||
public List<Dictionary<string, string>> Rows { get; set; } = new List<Dictionary<string, string>>();
|
public List<Dictionary<string, string>> Rows { get; set; } = new List<Dictionary<string, string>>();
|
||||||
|
public int TotalRows { get; set; } = 0;
|
||||||
}
|
}
|
||||||
public class TargetSampleColumn
|
public class TargetSampleColumn
|
||||||
{
|
{
|
||||||
|
|||||||
@ -218,6 +218,7 @@ namespace Surge365.MassEmailReact.Infrastructure.Repositories
|
|||||||
|
|
||||||
// Build TargetSample
|
// Build TargetSample
|
||||||
var targetSample = new TargetSample();
|
var targetSample = new TargetSample();
|
||||||
|
targetSample.TotalRows = rowCount;
|
||||||
bool emailFound = false;
|
bool emailFound = false;
|
||||||
bool uniqueIDFound = false;
|
bool uniqueIDFound = false;
|
||||||
bool bounceFound = false;
|
bool bounceFound = false;
|
||||||
|
|||||||
@ -13,12 +13,15 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Select,
|
Select,
|
||||||
InputLabel
|
InputLabel,
|
||||||
|
Typography,
|
||||||
|
CircularProgress
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||||
|
|
||||||
import Template from "@/types/template";
|
import Template from "@/types/template";
|
||||||
import Mailing from "@/types/mailing";
|
import Mailing from "@/types/mailing";
|
||||||
|
import TargetSample from "@/types/targetSample";
|
||||||
import Target from "@/types/target";
|
import Target from "@/types/target";
|
||||||
//import MailingTemplate from "@/types/mailingTemplate";
|
//import MailingTemplate from "@/types/mailingTemplate";
|
||||||
//import MailingTarget from "@/types/mailingTarget";
|
//import MailingTarget from "@/types/mailingTarget";
|
||||||
@ -234,6 +237,8 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
|||||||
const [currentTemplate, setCurrentTemplate] = useState<Template | null>(null);
|
const [currentTemplate, setCurrentTemplate] = useState<Template | null>(null);
|
||||||
const [TargetSampleModalOpen, setTargetSampleModalOpen] = useState<boolean>(false);
|
const [TargetSampleModalOpen, setTargetSampleModalOpen] = useState<boolean>(false);
|
||||||
const [currentTarget, setCurrentTarget] = useState<Target | null>(null);
|
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>({
|
const { register, trigger, control, handleSubmit, reset, setValue, formState: { errors } } = useForm<Mailing>({
|
||||||
mode: "onBlur",
|
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) => {
|
const handleTestEmailListChange = (list: TestEmailList | null) => {
|
||||||
if (list) {
|
if (list) {
|
||||||
setTestEmailListId(list.id);
|
setTestEmailListId(list.id);
|
||||||
@ -521,7 +549,7 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<TextField
|
<TextField
|
||||||
{...field}
|
{...field}
|
||||||
label="To Name"
|
label="From Name"
|
||||||
fullWidth
|
fullWidth
|
||||||
margin="dense"
|
margin="dense"
|
||||||
error={!!errors.template?.fromName}
|
error={!!errors.template?.fromName}
|
||||||
@ -562,6 +590,12 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{currentTarget && (
|
{currentTarget && (
|
||||||
|
<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
|
<Button
|
||||||
onClick={handleTargetSampleModalOpen}
|
onClick={handleTargetSampleModalOpen}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@ -570,6 +604,7 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
|||||||
>
|
>
|
||||||
View
|
View
|
||||||
</Button>
|
</Button>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
@ -692,10 +727,11 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
|||||||
onClose={() => { setTemplateViewerOpen(false) }}
|
onClose={() => { setTemplateViewerOpen(false) }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{TargetSampleModalOpen && (
|
{TargetSampleModalOpen && currentTarget && (
|
||||||
<TargetSampleModal
|
<TargetSampleModal
|
||||||
open={TargetSampleModalOpen}
|
open={TargetSampleModalOpen}
|
||||||
target={currentTarget!}
|
target={currentTarget}
|
||||||
|
targetSample={targetSample}
|
||||||
onClose={() => { setTargetSampleModalOpen(false) }}
|
onClose={() => { setTargetSampleModalOpen(false) }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -6,52 +6,54 @@ import {
|
|||||||
Dialog,
|
Dialog,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
Typography
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import Target from "@/types/target";
|
import Target from "@/types/target";
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
import TargetSample from "@/types/targetSample";
|
||||||
import TargetSampleDataGrid from "@/components/shared/TargetSampleDataGrid";
|
import TargetSampleDataGrid from "@/components/shared/TargetSampleDataGrid";
|
||||||
import { GridColDef } from '@mui/x-data-grid';
|
import { GridColDef } from '@mui/x-data-grid';
|
||||||
|
|
||||||
type TargetSampleModalProps = {
|
type TargetSampleModalProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
target: Target;
|
target: Target;
|
||||||
|
targetSample?: TargetSample | null;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TargetSampleColumn = {
|
const TargetSampleModal = ({ open, target, targetSample, onClose }: TargetSampleModalProps) => {
|
||||||
name: string;
|
const [localTargetSample, setLocalTargetSample] = useState<TargetSample | null>(null);
|
||||||
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 [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
const fetchSampleData = async () => {
|
const fetchSampleData = async () => {
|
||||||
|
if (targetSample) {
|
||||||
|
setLocalTargetSample(targetSample);
|
||||||
|
}
|
||||||
|
else if (target.id) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/targets/${target.id}/sample`);
|
const response = await fetch(`/api/targets/${target.id}/sample`);
|
||||||
if (!response.ok) throw new Error("Failed to fetch sample data");
|
if (!response.ok) throw new Error("Failed to fetch sample data");
|
||||||
const data: TargetSample = await response.json();
|
const data: TargetSample = await response.json();
|
||||||
setTargetSample(data);
|
setLocalTargetSample(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching target sample:", error);
|
console.error("Error fetching target sample:", error);
|
||||||
setTargetSample(null);
|
setLocalTargetSample(null);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setLocalTargetSample(null);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
fetchSampleData();
|
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,
|
field: colName,
|
||||||
headerName: colName,
|
headerName: colName,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
@ -60,9 +62,9 @@ const TargetSampleModal = ({ open, target, onClose }: TargetSampleModalProps) =>
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
})) || [];
|
})) || [];
|
||||||
|
|
||||||
const rows = targetSample?.rows?.map((row, index) => {
|
const rows = localTargetSample?.rows?.map((row, index) => {
|
||||||
const rowData: { [key: string]: string } = { id: index.toString() };
|
const rowData: { [key: string]: string } = { id: index.toString() };
|
||||||
Object.keys(targetSample?.columns || {}).forEach((key) => {
|
Object.keys(localTargetSample?.columns || {}).forEach((key) => {
|
||||||
rowData[key] = row[key] ?? "";
|
rowData[key] = row[key] ?? "";
|
||||||
});
|
});
|
||||||
return rowData;
|
return rowData;
|
||||||
@ -113,6 +115,7 @@ const TargetSampleModal = ({ open, target, onClose }: TargetSampleModalProps) =>
|
|||||||
</Box>
|
</Box>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
<Typography sx={{ mb: 1, fontWeight: 'bold' }} >Total Rows: {localTargetSample?.totalRows}</Typography>
|
||||||
<TargetSampleDataGrid columns={columns} rows={rows} />
|
<TargetSampleDataGrid columns={columns} rows={rows} />
|
||||||
</DialogContent>
|
</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