Enhance mailing functionality and update UI titles
- Added `@bounced_email_key` output parameter in `BouncedEmailRepository.cs`. - Updated dialog title in `BouncedEmailEdit.tsx` from "Add Bounced Email" to "Add Blocked Email". - Refactored validation schema in `MailingEdit.tsx`, removing old code and adding new validation rules. - Introduced `nameIsAvailable` and `getNextAvailableName` functions in `MailingEdit.tsx`. - Integrated `setupData` context in `ActiveMailings.tsx`, `CancelledMailings.tsx`, `NewMailings.tsx`, and `ScheduledMailings.tsx` to refresh setup data during mailing operations.
This commit is contained in:
parent
0e099bfd07
commit
7faac8b448
@ -67,6 +67,7 @@ namespace Surge365.MassEmailReact.Infrastructure.Repositories
|
|||||||
parameters.Add("@unsubscribe", bouncedEmail.Unsubscribe, DbType.Boolean);
|
parameters.Add("@unsubscribe", bouncedEmail.Unsubscribe, DbType.Boolean);
|
||||||
parameters.Add("@entered_by_admin", bouncedEmail.EnteredByAdmin, DbType.Boolean);
|
parameters.Add("@entered_by_admin", bouncedEmail.EnteredByAdmin, DbType.Boolean);
|
||||||
parameters.Add("@success", dbType: DbType.Boolean, direction: ParameterDirection.Output);
|
parameters.Add("@success", dbType: DbType.Boolean, direction: ParameterDirection.Output);
|
||||||
|
parameters.Add("@bounced_email_key", dbType: DbType.Int32, direction: ParameterDirection.Output);
|
||||||
|
|
||||||
await conn.ExecuteAsync("mem_save_bounced_email", parameters, commandType: CommandType.StoredProcedure);
|
await conn.ExecuteAsync("mem_save_bounced_email", parameters, commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
|||||||
@ -95,7 +95,7 @@ const BouncedEmailEdit = ({ open, bouncedEmail, onClose, onSave }: BouncedEmailE
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
|
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
|
||||||
<DialogTitle>{isNew ? "Add Bounced Email" : "Edit Bounced Email"}</DialogTitle>
|
<DialogTitle>{isNew ? "Add Blocked Email" : "Edit Blocked Email"}</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<TextField
|
<TextField
|
||||||
{...register("emailAddress")}
|
{...register("emailAddress")}
|
||||||
|
|||||||
@ -67,165 +67,6 @@ const recurringTypeOptions = [
|
|||||||
{ code: 'W', name: 'Weekly' },
|
{ code: 'W', name: 'Weekly' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const schema = yup.object().shape({
|
|
||||||
id: yup.number().nullable(),
|
|
||||||
name: yup.string().required("Name is required")
|
|
||||||
.test("unique-name", "Name must be unique", async function (value) {
|
|
||||||
if (value.length === 0)
|
|
||||||
return true;
|
|
||||||
return await nameIsAvailable(this.parent.id, value);
|
|
||||||
}),
|
|
||||||
description: yup.string().default(""),
|
|
||||||
templateId: yup.number().typeError("Template is required").required("Template is required").test("valid-template", "Invalid template", function (value) {
|
|
||||||
const setupData = this.options.context?.setupData as SetupData;
|
|
||||||
return setupData.templates.some(t => t.id === value);
|
|
||||||
}),
|
|
||||||
targetId: yup.number().typeError("Target is required").required("Target is required").test("valid-target", "Invalid target", function (value) {
|
|
||||||
const setupData = this.options.context?.setupData as SetupData;
|
|
||||||
return setupData.targets.some(t => t.id === value);
|
|
||||||
}),
|
|
||||||
statusCode: yup.string().default("ED"),
|
|
||||||
scheduleDate: yup.string()
|
|
||||||
.nullable()
|
|
||||||
.when("$scheduleForLater", (scheduleForLater, schema) => {
|
|
||||||
const isScheduledForLater = scheduleForLater[0] ?? false;
|
|
||||||
return isScheduledForLater
|
|
||||||
? schema
|
|
||||||
.required("Schedule date is required when scheduled for later")
|
|
||||||
.matches(
|
|
||||||
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,
|
|
||||||
"Schedule date must be a valid UTC ISO string (e.g., 'YYYY-MM-DDTHH:mm:ssZ')"
|
|
||||||
)
|
|
||||||
.test("is-future", "Schedule date must be in the future", (value) => {
|
|
||||||
if (!value) return true; // Nullable when not required
|
|
||||||
return dayjs(value).isAfter(dayjs());
|
|
||||||
})
|
|
||||||
: schema.nullable();
|
|
||||||
}),
|
|
||||||
|
|
||||||
//scheduleDate: yup.date().nullable(),
|
|
||||||
|
|
||||||
// .when("statusCode", {
|
|
||||||
// is: (value: string) => value === "SC" || value === "SD", // String comparison
|
|
||||||
// then: (schema) => schema.required("Schedule date is required for scheduled or sending status"),
|
|
||||||
// otherwise: (schema) => schema.nullable(),
|
|
||||||
//}),
|
|
||||||
sentDate: yup.date().nullable().default(null),
|
|
||||||
sessionActivityId: yup.string().nullable(),
|
|
||||||
recurringTypeCode: yup
|
|
||||||
.string()
|
|
||||||
.nullable()
|
|
||||||
.when("$recurring", (recurring, schema) => { // Use context variable
|
|
||||||
const isRecurring = recurring[0] ?? false;
|
|
||||||
return isRecurring
|
|
||||||
? schema.oneOf(recurringTypeOptions.map((r) => r.code), "Invalid recurring type")
|
|
||||||
: schema.nullable();
|
|
||||||
}),
|
|
||||||
|
|
||||||
recurringStartDate: yup.string()
|
|
||||||
.nullable()
|
|
||||||
.when("$recurring", (recurring, schema) => {
|
|
||||||
const isRecurring = recurring[0] ?? false;
|
|
||||||
return isRecurring
|
|
||||||
? schema
|
|
||||||
.required("Recurring start date is required when recurring")
|
|
||||||
.matches(
|
|
||||||
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,
|
|
||||||
"Recurring start date must be a valid UTC ISO string (e.g., 'YYYY-MM-DDTHH:mm:ssZ')"
|
|
||||||
)
|
|
||||||
.test("is-future", "Recurring start date must be in the future", (value) => {
|
|
||||||
if (!value) return true; // Nullable when not required
|
|
||||||
return dayjs(value).isAfter(dayjs());
|
|
||||||
})
|
|
||||||
: schema.nullable();
|
|
||||||
}),
|
|
||||||
template: yup.object().shape({
|
|
||||||
id: yup.number().nullable().default(0),
|
|
||||||
mailingId: yup.number().default(0),
|
|
||||||
name: yup.string().default(""),
|
|
||||||
domainId: yup
|
|
||||||
.number()
|
|
||||||
.typeError("Domain is required")
|
|
||||||
.required("Domain is required")
|
|
||||||
.test("valid-domain", "Invalid domain", function (value) {
|
|
||||||
const setupData = this.options.context?.setupData as SetupData;
|
|
||||||
return setupData.emailDomains.some((d) => d.id === value);
|
|
||||||
}),
|
|
||||||
description: yup.string().default(""),
|
|
||||||
htmlBody: yup.string().default(""),
|
|
||||||
subject: yup.string().required("Subject is required").default(""),
|
|
||||||
toName: yup.string().default(""),
|
|
||||||
fromName: yup.string().required("From Name is required").default(""),
|
|
||||||
fromEmail: yup.string().default(""),
|
|
||||||
replyToEmail: yup.string().default(""),
|
|
||||||
clickTracking: yup.boolean().default(false),
|
|
||||||
openTracking: yup.boolean().default(false),
|
|
||||||
categoryXml: yup.string().default(""),
|
|
||||||
}),
|
|
||||||
target: yup.object().shape({
|
|
||||||
id: yup.number().nullable().default(0),
|
|
||||||
mailingId: yup.number().default(0),
|
|
||||||
serverId: yup.number().default(0),
|
|
||||||
name: yup.string().default(""),
|
|
||||||
databaseName: yup.string().default(""),
|
|
||||||
viewName: yup.string().default(""),
|
|
||||||
filterQuery: yup.string().default(""),
|
|
||||||
allowWriteBack: yup.boolean().default(false),
|
|
||||||
}).nullable(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const nameIsAvailable = async (id: number, name: string) => {
|
|
||||||
const response = await customFetch(`/api/mailings/available?${id > 0 ? "id=" + id + "&" : ""}name=${name}`);
|
|
||||||
const data = await response.json();
|
|
||||||
return data.available;
|
|
||||||
};
|
|
||||||
const getNextAvailableName = async (id: number, name: string) => {
|
|
||||||
const response = await customFetch(`/api/mailings/nextavailablename?${id > 0 ? "id=" + id + "&" : ""}name=${name}`);
|
|
||||||
const data = await response.json();
|
|
||||||
return data.name;
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultMailing: Mailing = {
|
|
||||||
id: 0,
|
|
||||||
name: "",
|
|
||||||
description: "",
|
|
||||||
templateId: 0,
|
|
||||||
targetId: 0,
|
|
||||||
statusCode: "ED",
|
|
||||||
scheduleDate: null,
|
|
||||||
sentDate: null,
|
|
||||||
sessionActivityId: null,
|
|
||||||
recurringTypeCode: null,
|
|
||||||
recurringStartDate: null,
|
|
||||||
template: {
|
|
||||||
id: 0,
|
|
||||||
mailingId: 0,
|
|
||||||
name: "",
|
|
||||||
domainId: 0,
|
|
||||||
description: "",
|
|
||||||
htmlBody: "",
|
|
||||||
subject: "",
|
|
||||||
toName: "",
|
|
||||||
fromName: "",
|
|
||||||
fromEmail: "",
|
|
||||||
replyToEmail: "",
|
|
||||||
clickTracking: false,
|
|
||||||
openTracking: false,
|
|
||||||
categoryXml: ""
|
|
||||||
},
|
|
||||||
target: {
|
|
||||||
id: 0,
|
|
||||||
mailingId: 0,
|
|
||||||
serverId: 0,
|
|
||||||
name: "",
|
|
||||||
databaseName: "",
|
|
||||||
viewName: "",
|
|
||||||
filterQuery: "",
|
|
||||||
allowWriteBack: false,
|
|
||||||
}
|
|
||||||
,
|
|
||||||
};
|
|
||||||
|
|
||||||
const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
||||||
const customFetch = useCustomFetch();
|
const customFetch = useCustomFetch();
|
||||||
const isNew = !mailing || mailing.id === 0;
|
const isNew = !mailing || mailing.id === 0;
|
||||||
@ -242,6 +83,166 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
|||||||
const [targetSample, setTargetSample] = useState<TargetSample | null>(null);
|
const [targetSample, setTargetSample] = useState<TargetSample | null>(null);
|
||||||
const [targetSampleLoading, setTargetSampleLoading] = useState(false);
|
const [targetSampleLoading, setTargetSampleLoading] = useState(false);
|
||||||
|
|
||||||
|
const defaultMailing: Mailing = {
|
||||||
|
id: 0,
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
templateId: 0,
|
||||||
|
targetId: 0,
|
||||||
|
statusCode: "ED",
|
||||||
|
scheduleDate: null,
|
||||||
|
sentDate: null,
|
||||||
|
sessionActivityId: null,
|
||||||
|
recurringTypeCode: null,
|
||||||
|
recurringStartDate: null,
|
||||||
|
template: {
|
||||||
|
id: 0,
|
||||||
|
mailingId: 0,
|
||||||
|
name: "",
|
||||||
|
domainId: 0,
|
||||||
|
description: "",
|
||||||
|
htmlBody: "",
|
||||||
|
subject: "",
|
||||||
|
toName: "",
|
||||||
|
fromName: "",
|
||||||
|
fromEmail: "",
|
||||||
|
replyToEmail: "",
|
||||||
|
clickTracking: false,
|
||||||
|
openTracking: false,
|
||||||
|
categoryXml: ""
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
id: 0,
|
||||||
|
mailingId: 0,
|
||||||
|
serverId: 0,
|
||||||
|
name: "",
|
||||||
|
databaseName: "",
|
||||||
|
viewName: "",
|
||||||
|
filterQuery: "",
|
||||||
|
allowWriteBack: false,
|
||||||
|
}
|
||||||
|
,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const nameIsAvailable = async (id: number, name: string) => {
|
||||||
|
const response = await customFetch(`/api/mailings/available?${id > 0 ? "id=" + id + "&" : ""}name=${name}`);
|
||||||
|
const data = await response.json();
|
||||||
|
return data.available;
|
||||||
|
};
|
||||||
|
const getNextAvailableName = async (id: number, name: string) => {
|
||||||
|
const response = await customFetch(`/api/mailings/nextavailablename?${id > 0 ? "id=" + id + "&" : ""}name=${name}`);
|
||||||
|
const data = await response.json();
|
||||||
|
return data.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
const schema = yup.object().shape({
|
||||||
|
id: yup.number().nullable(),
|
||||||
|
name: yup.string().required("Name is required")
|
||||||
|
.test("unique-name", "Name must be unique", async function (value) {
|
||||||
|
if (value.length === 0)
|
||||||
|
return true;
|
||||||
|
return await nameIsAvailable(this.parent.id, value);
|
||||||
|
}),
|
||||||
|
description: yup.string().default(""),
|
||||||
|
templateId: yup.number().typeError("Template is required").required("Template is required").test("valid-template", "Invalid template", function (value) {
|
||||||
|
const setupData = this.options.context?.setupData as SetupData;
|
||||||
|
return setupData.templates.some(t => t.id === value);
|
||||||
|
}),
|
||||||
|
targetId: yup.number().typeError("Target is required").required("Target is required").test("valid-target", "Invalid target", function (value) {
|
||||||
|
const setupData = this.options.context?.setupData as SetupData;
|
||||||
|
return setupData.targets.some(t => t.id === value);
|
||||||
|
}),
|
||||||
|
statusCode: yup.string().default("ED"),
|
||||||
|
scheduleDate: yup.string()
|
||||||
|
.nullable()
|
||||||
|
.when("$scheduleForLater", (scheduleForLater, schema) => {
|
||||||
|
const isScheduledForLater = scheduleForLater[0] ?? false;
|
||||||
|
return isScheduledForLater
|
||||||
|
? schema
|
||||||
|
.required("Schedule date is required when scheduled for later")
|
||||||
|
.matches(
|
||||||
|
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,
|
||||||
|
"Schedule date must be a valid UTC ISO string (e.g., 'YYYY-MM-DDTHH:mm:ssZ')"
|
||||||
|
)
|
||||||
|
.test("is-future", "Schedule date must be in the future", (value) => {
|
||||||
|
if (!value) return true; // Nullable when not required
|
||||||
|
return dayjs(value).isAfter(dayjs());
|
||||||
|
})
|
||||||
|
: schema.nullable();
|
||||||
|
}),
|
||||||
|
|
||||||
|
//scheduleDate: yup.date().nullable(),
|
||||||
|
|
||||||
|
// .when("statusCode", {
|
||||||
|
// is: (value: string) => value === "SC" || value === "SD", // String comparison
|
||||||
|
// then: (schema) => schema.required("Schedule date is required for scheduled or sending status"),
|
||||||
|
// otherwise: (schema) => schema.nullable(),
|
||||||
|
//}),
|
||||||
|
sentDate: yup.date().nullable().default(null),
|
||||||
|
sessionActivityId: yup.string().nullable(),
|
||||||
|
recurringTypeCode: yup
|
||||||
|
.string()
|
||||||
|
.nullable()
|
||||||
|
.when("$recurring", (recurring, schema) => { // Use context variable
|
||||||
|
const isRecurring = recurring[0] ?? false;
|
||||||
|
return isRecurring
|
||||||
|
? schema.oneOf(recurringTypeOptions.map((r) => r.code), "Invalid recurring type")
|
||||||
|
: schema.nullable();
|
||||||
|
}),
|
||||||
|
|
||||||
|
recurringStartDate: yup.string()
|
||||||
|
.nullable()
|
||||||
|
.when("$recurring", (recurring, schema) => {
|
||||||
|
const isRecurring = recurring[0] ?? false;
|
||||||
|
return isRecurring
|
||||||
|
? schema
|
||||||
|
.required("Recurring start date is required when recurring")
|
||||||
|
.matches(
|
||||||
|
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,
|
||||||
|
"Recurring start date must be a valid UTC ISO string (e.g., 'YYYY-MM-DDTHH:mm:ssZ')"
|
||||||
|
)
|
||||||
|
.test("is-future", "Recurring start date must be in the future", (value) => {
|
||||||
|
if (!value) return true; // Nullable when not required
|
||||||
|
return dayjs(value).isAfter(dayjs());
|
||||||
|
})
|
||||||
|
: schema.nullable();
|
||||||
|
}),
|
||||||
|
template: yup.object().shape({
|
||||||
|
id: yup.number().nullable().default(0),
|
||||||
|
mailingId: yup.number().default(0),
|
||||||
|
name: yup.string().default(""),
|
||||||
|
domainId: yup
|
||||||
|
.number()
|
||||||
|
.typeError("Domain is required")
|
||||||
|
.required("Domain is required")
|
||||||
|
.test("valid-domain", "Invalid domain", function (value) {
|
||||||
|
const setupData = this.options.context?.setupData as SetupData;
|
||||||
|
return setupData.emailDomains.some((d) => d.id === value);
|
||||||
|
}),
|
||||||
|
description: yup.string().default(""),
|
||||||
|
htmlBody: yup.string().default(""),
|
||||||
|
subject: yup.string().required("Subject is required").default(""),
|
||||||
|
toName: yup.string().default(""),
|
||||||
|
fromName: yup.string().required("From Name is required").default(""),
|
||||||
|
fromEmail: yup.string().default(""),
|
||||||
|
replyToEmail: yup.string().default(""),
|
||||||
|
clickTracking: yup.boolean().default(false),
|
||||||
|
openTracking: yup.boolean().default(false),
|
||||||
|
categoryXml: yup.string().default(""),
|
||||||
|
}),
|
||||||
|
target: yup.object().shape({
|
||||||
|
id: yup.number().nullable().default(0),
|
||||||
|
mailingId: yup.number().default(0),
|
||||||
|
serverId: yup.number().default(0),
|
||||||
|
name: yup.string().default(""),
|
||||||
|
databaseName: yup.string().default(""),
|
||||||
|
viewName: yup.string().default(""),
|
||||||
|
filterQuery: yup.string().default(""),
|
||||||
|
allowWriteBack: yup.boolean().default(false),
|
||||||
|
}).nullable(),
|
||||||
|
});
|
||||||
|
|
||||||
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",
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@ -253,6 +254,7 @@ const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
|
|||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initializeMailingEdit = async () => {
|
const initializeMailingEdit = async () => {
|
||||||
if (open) {
|
if (open) {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
|
import { useSetupData, SetupData } from "@/context/SetupDataContext";
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import { List, Card, CardContent, Typography, Box, useTheme, useMediaQuery, CircularProgress, IconButton, FormControlLabel } from '@mui/material';
|
import { List, Card, CardContent, Typography, Box, useTheme, useMediaQuery, CircularProgress, IconButton, FormControlLabel } from '@mui/material';
|
||||||
@ -9,6 +10,7 @@ import { useCustomFetch } from "@/utils/customFetch";
|
|||||||
function ActiveMailings() {
|
function ActiveMailings() {
|
||||||
const customFetch = useCustomFetch();
|
const customFetch = useCustomFetch();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const setupData: SetupData = useSetupData();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
|
|
||||||
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
@ -40,6 +42,7 @@ function ActiveMailings() {
|
|||||||
|
|
||||||
isFetchingRef.current = true;
|
isFetchingRef.current = true;
|
||||||
setMailingsLoading(true);
|
setMailingsLoading(true);
|
||||||
|
setupData.reloadSetupData();
|
||||||
try {
|
try {
|
||||||
const response = await customFetch("/api/mailings/status/SD/stats");
|
const response = await customFetch("/api/mailings/status/SD/stats");
|
||||||
const statsData = await response.json();
|
const statsData = await response.json();
|
||||||
|
|||||||
@ -53,6 +53,7 @@ function CancelledMailings() {
|
|||||||
|
|
||||||
const reloadMailings = async () => {
|
const reloadMailings = async () => {
|
||||||
setMailingsLoading(true);
|
setMailingsLoading(true);
|
||||||
|
setupData.reloadSetupData();
|
||||||
const mailingsResponse = await customFetch("/api/mailings/status/c");
|
const mailingsResponse = await customFetch("/api/mailings/status/c");
|
||||||
const mailingsData = await mailingsResponse.json();
|
const mailingsData = await mailingsResponse.json();
|
||||||
if (mailingsData) {
|
if (mailingsData) {
|
||||||
|
|||||||
@ -57,6 +57,7 @@ function NewMailings() {
|
|||||||
|
|
||||||
const reloadMailings = async () => {
|
const reloadMailings = async () => {
|
||||||
setMailingsLoading(true);
|
setMailingsLoading(true);
|
||||||
|
setupData.reloadSetupData();
|
||||||
|
|
||||||
const mailingsResponse = await customFetch("/api/mailings/status/ed");
|
const mailingsResponse = await customFetch("/api/mailings/status/ed");
|
||||||
const mailingsData = await mailingsResponse.json();
|
const mailingsData = await mailingsResponse.json();
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
|
import { useSetupData, SetupData } from "@/context/SetupDataContext";
|
||||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
@ -14,6 +15,7 @@ import { useCustomFetch } from "@/utils/customFetch";
|
|||||||
function ScheduleMailings() {
|
function ScheduleMailings() {
|
||||||
const customFetch = useCustomFetch();
|
const customFetch = useCustomFetch();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const setupData: SetupData = useSetupData();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
|
|
||||||
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
@ -81,6 +83,7 @@ function ScheduleMailings() {
|
|||||||
|
|
||||||
const reloadMailings = async () => {
|
const reloadMailings = async () => {
|
||||||
setMailingsLoading(true);
|
setMailingsLoading(true);
|
||||||
|
setupData.reloadSetupData();
|
||||||
const mailingsResponse = await customFetch("/api/mailings/status/sc"); // Adjust endpoint as needed
|
const mailingsResponse = await customFetch("/api/mailings/status/sc"); // Adjust endpoint as needed
|
||||||
const mailingsData = await mailingsResponse.json();
|
const mailingsData = await mailingsResponse.json();
|
||||||
if (mailingsData) {
|
if (mailingsData) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user