update
This commit is contained in:
@ -129,6 +129,7 @@ const AddDialog = () => {
|
|||||||
<Input
|
<Input
|
||||||
className={`input col-span-6 ${errors.name ? 'border-red-500' : ''}`}
|
className={`input col-span-6 ${errors.name ? 'border-red-500' : ''}`}
|
||||||
type="text"
|
type="text"
|
||||||
|
placeholder="Enter Name"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
value={formField.name}
|
value={formField.name}
|
||||||
onChange={({ target }) => {
|
onChange={({ target }) => {
|
||||||
@ -149,15 +150,15 @@ const AddDialog = () => {
|
|||||||
Description <span className="text-red-500">*</span>
|
Description <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
className="input col-span-6"
|
className={`input col-span-6 ${errors.name ? 'border-red-500' : ''}`}
|
||||||
name="description"
|
name="description"
|
||||||
placeholder="Enter Description"
|
placeholder="Enter Description"
|
||||||
value={formField.description}
|
value={formField.description}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
{errors.type && (
|
{errors.description && (
|
||||||
<span className="text-red-500 text-xs mt-1 col-span-8 ml-[calc(25%+0.5rem)]">
|
<span className="text-red-500 text-xs mt-1 col-span-8 ml-[calc(25%+0.5rem)]">
|
||||||
{errors.type}
|
{errors.description}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import { useManageNotificationContext } from '../hooks/useManageNotificationCont
|
|||||||
import { doSaveLogActivity } from '@/actions/GlobalActions';
|
import { doSaveLogActivity } from '@/actions/GlobalActions';
|
||||||
import { CustomerProps } from '@/pages/master/provider/blocks/AddDialog';
|
import { CustomerProps } from '@/pages/master/provider/blocks/AddDialog';
|
||||||
import { Check, ChevronDown } from 'lucide-react';
|
import { Check, ChevronDown } from 'lucide-react';
|
||||||
|
import { initialStateNotification, selectedNotification, validateFormNotification } from './Types';
|
||||||
|
|
||||||
const API_URL_CUSTOMER = apiConfig.service_customer;
|
const API_URL_CUSTOMER = apiConfig.service_customer;
|
||||||
const API_URL_NOTIFICATION = apiConfig.service_notification;
|
const API_URL_NOTIFICATION = apiConfig.service_notification;
|
||||||
@ -37,32 +38,34 @@ const AddDialog = () => {
|
|||||||
const { GetData, PostData } = useCallApi();
|
const { GetData, PostData } = useCallApi();
|
||||||
const [alert, setAlert] = useState({ show: false, message: '' });
|
const [alert, setAlert] = useState({ show: false, message: '' });
|
||||||
const isSubmittingRef = useRef(false);
|
const isSubmittingRef = useRef(false);
|
||||||
|
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
const initialState = {
|
const [formField, setFormField] = useState<selectedNotification>(initialStateNotification);
|
||||||
customers: [] as string[],
|
|
||||||
all_customer: '',
|
|
||||||
type: '',
|
|
||||||
via: '',
|
|
||||||
subject: '',
|
|
||||||
content: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
const [formField, setFormField] = useState(initialState);
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [customers, setCustomers] = useState<CustomerProps[]>([]);
|
const [customers, setCustomers] = useState<CustomerProps[]>([]);
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
setFormField({ ...initialState });
|
setFormField({ ...initialStateNotification });
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
setAlert({ show: false, message: '' });
|
setAlert({ show: false, message: '' });
|
||||||
|
setErrors({});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
setFormField({ ...formField, [e.target.name]: e.target.value });
|
const { name, value } = e.target;
|
||||||
|
setFormField({ ...formField, [name]: value });
|
||||||
|
|
||||||
if (e.target.name === 'all_customer' && e.target.value === 'true') {
|
if (name === 'all_customer' && value === 'true') {
|
||||||
setFormField((prev) => ({ ...prev, customers: [] }));
|
setFormField((prev) => ({ ...prev, customers: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errors[name]) {
|
||||||
|
setErrors((prevErrors) => {
|
||||||
|
const updatedErrors = { ...prevErrors };
|
||||||
|
delete updatedErrors[name];
|
||||||
|
return updatedErrors;
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const doCreateNotification = useCallback(
|
const doCreateNotification = useCallback(
|
||||||
@ -120,32 +123,8 @@ const AddDialog = () => {
|
|||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (!validateFormNotification(formField, setErrors)) return;
|
||||||
if (isSubmittingRef.current) return;
|
|
||||||
|
|
||||||
if (
|
|
||||||
formField.all_customer.trim() === '' ||
|
|
||||||
formField.via.trim() === '' ||
|
|
||||||
formField.content.trim() === ''
|
|
||||||
) {
|
|
||||||
setAlert({ show: true, message: 'Please fill all required fields.' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formField.via === 'email' && formField.subject.trim() === '') {
|
|
||||||
setAlert({ show: true, message: 'Subject is required for E-Mail' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formField.via === 'fcm' && formField.subject.trim() === '') {
|
|
||||||
setAlert({ show: true, message: 'Subject is required form FCM' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsSubmitting(true);
|
|
||||||
doCreateNotification(e);
|
doCreateNotification(e);
|
||||||
// console.log(formField);
|
|
||||||
setAlert({ show: false, message: '' });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -179,7 +158,11 @@ const AddDialog = () => {
|
|||||||
<label className="form-label flex items-center gap-1 max-w-56">
|
<label className="form-label flex items-center gap-1 max-w-56">
|
||||||
Send To<span className="text-red-500">*</span>
|
Send To<span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex gap-6 items-center">
|
<div
|
||||||
|
className={`flex gap-6 items-center border rounded-md px-3 py-1 ${
|
||||||
|
errors.all_customer ? 'border-red-500' : 'border-gray-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<label className="flex items-center space-x-2">
|
<label className="flex items-center space-x-2">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
@ -204,6 +187,13 @@ const AddDialog = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{errors.all_customer && (
|
||||||
|
<div className="w-full">
|
||||||
|
<span className="text-red-500 text-xs mt-3 ml-[calc(30%+2rem)] block">
|
||||||
|
{errors.all_customer}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
@ -277,7 +267,11 @@ const AddDialog = () => {
|
|||||||
<label className="form-label flex items-center gap-1 max-w-56">
|
<label className="form-label flex items-center gap-1 max-w-56">
|
||||||
Type<span className="text-red-500">*</span>
|
Type<span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex gap-6 items-center">
|
<div
|
||||||
|
className={`flex gap-6 items-center border rounded-md px-3 py-1 ${
|
||||||
|
errors.type ? 'border-red-500' : 'border-gray-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{['info', 'promo'].map((type) => (
|
{['info', 'promo'].map((type) => (
|
||||||
<label key={type} className="flex items-center space-x-2">
|
<label key={type} className="flex items-center space-x-2">
|
||||||
<input
|
<input
|
||||||
@ -293,6 +287,13 @@ const AddDialog = () => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{errors.type && (
|
||||||
|
<div className="w-full">
|
||||||
|
<span className="text-red-500 text-xs mt-3 ml-[calc(30%+2rem)] block">
|
||||||
|
{errors.type}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
@ -300,7 +301,11 @@ const AddDialog = () => {
|
|||||||
<label className="form-label flex items-center gap-1 max-w-56">
|
<label className="form-label flex items-center gap-1 max-w-56">
|
||||||
Send Via<span className="text-red-500">*</span>
|
Send Via<span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex gap-6 items-center">
|
<div
|
||||||
|
className={`flex gap-6 items-center border rounded-md px-3 py-1 ${
|
||||||
|
errors.via ? 'border-red-500' : 'border-gray-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<label className="flex items-center space-x-2">
|
<label className="flex items-center space-x-2">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
@ -336,6 +341,13 @@ const AddDialog = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{errors.via && (
|
||||||
|
<div className="w-full">
|
||||||
|
<span className="text-red-500 text-xs mt-3 ml-[calc(30%+2rem)] block">
|
||||||
|
{errors.via}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
@ -358,13 +370,20 @@ const AddDialog = () => {
|
|||||||
Content<span className="text-red-500">*</span>
|
Content<span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
className="input col-span-6"
|
className={`input col-span-6 ${errors.content ? 'border-red-500' : ''}`}
|
||||||
name="content"
|
name="content"
|
||||||
placeholder="Enter Content Notification"
|
placeholder="Enter Content Notification"
|
||||||
value={formField.content}
|
value={formField.content}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{errors.content && (
|
||||||
|
<div className="w-full">
|
||||||
|
<span className="text-red-500 text-xs mt-3 col-span-8 ml-[calc(30%+2rem)] block">
|
||||||
|
{errors.content}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end gap-4">
|
<div className="flex justify-end gap-4">
|
||||||
|
|||||||
55
src/pages/notification/blocks/Types.ts
Normal file
55
src/pages/notification/blocks/Types.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
|
export interface selectedNotification {
|
||||||
|
customers: string[];
|
||||||
|
all_customer: string;
|
||||||
|
type: string;
|
||||||
|
via: string;
|
||||||
|
subject: string;
|
||||||
|
content: string;
|
||||||
|
id: string;
|
||||||
|
created_by: string;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialStateNotification: selectedNotification = {
|
||||||
|
customers: [],
|
||||||
|
all_customer: '',
|
||||||
|
type: '',
|
||||||
|
via: '',
|
||||||
|
subject: '',
|
||||||
|
content: '',
|
||||||
|
id: '',
|
||||||
|
created_by: '',
|
||||||
|
created_at: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validateFormNotification = (
|
||||||
|
formField: typeof initialStateNotification,
|
||||||
|
setErrors: React.Dispatch<React.SetStateAction<Record<string, string>>>
|
||||||
|
) => {
|
||||||
|
const requiredFields = [
|
||||||
|
{ key: 'all_customer', label: 'Send To' },
|
||||||
|
{ key: 'type', label: 'Type' },
|
||||||
|
{ key: 'via', label: 'Via' },
|
||||||
|
{ key: 'content', label: 'Content' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const newErrors: Record<string, string> = {};
|
||||||
|
let isValid = true;
|
||||||
|
|
||||||
|
requiredFields.forEach(({ key, label }) => {
|
||||||
|
if (
|
||||||
|
formField[key as keyof typeof formField] === '' ||
|
||||||
|
formField[key as keyof typeof formField] === null ||
|
||||||
|
formField[key as keyof typeof formField] === undefined
|
||||||
|
) {
|
||||||
|
newErrors[key] = `${label} is required`;
|
||||||
|
toast.error(`${label} is required`);
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setErrors(newErrors);
|
||||||
|
return isValid;
|
||||||
|
};
|
||||||
@ -7,17 +7,6 @@ import { ListToolBar } from '../blocks/ListToolbar';
|
|||||||
import { useCallApi } from '@/hooks';
|
import { useCallApi } from '@/hooks';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
interface SelectedNotification {
|
|
||||||
all_customers: string;
|
|
||||||
customer_name: string;
|
|
||||||
id: string;
|
|
||||||
content: string;
|
|
||||||
subject: string;
|
|
||||||
type: string;
|
|
||||||
via: string;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ContextProps {
|
interface ContextProps {
|
||||||
showAddDialog: boolean;
|
showAddDialog: boolean;
|
||||||
handleAddDialog: (show: boolean) => void;
|
handleAddDialog: (show: boolean) => void;
|
||||||
@ -197,4 +186,3 @@ const ManageNotifContextProvider = ({ children }: { children: React.ReactNode })
|
|||||||
};
|
};
|
||||||
|
|
||||||
export { ManageNotifContext, ManageNotifContextProvider };
|
export { ManageNotifContext, ManageNotifContextProvider };
|
||||||
export type { SelectedNotification };
|
|
||||||
|
|||||||
Reference in New Issue
Block a user