update
This commit is contained in:
@ -27,6 +27,7 @@ import { useManageNotificationContext } from '../hooks/useManageNotificationCont
|
||||
import { doSaveLogActivity } from '@/actions/GlobalActions';
|
||||
import { CustomerProps } from '@/pages/master/provider/blocks/AddDialog';
|
||||
import { Check, ChevronDown } from 'lucide-react';
|
||||
import { initialStateNotification, selectedNotification, validateFormNotification } from './Types';
|
||||
|
||||
const API_URL_CUSTOMER = apiConfig.service_customer;
|
||||
const API_URL_NOTIFICATION = apiConfig.service_notification;
|
||||
@ -37,32 +38,34 @@ const AddDialog = () => {
|
||||
const { GetData, PostData } = useCallApi();
|
||||
const [alert, setAlert] = useState({ show: false, message: '' });
|
||||
const isSubmittingRef = useRef(false);
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
|
||||
const initialState = {
|
||||
customers: [] as string[],
|
||||
all_customer: '',
|
||||
type: '',
|
||||
via: '',
|
||||
subject: '',
|
||||
content: ''
|
||||
};
|
||||
|
||||
const [formField, setFormField] = useState(initialState);
|
||||
const [formField, setFormField] = useState<selectedNotification>(initialStateNotification);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [customers, setCustomers] = useState<CustomerProps[]>([]);
|
||||
const resetForm = () => {
|
||||
setFormField({ ...initialState });
|
||||
setFormField({ ...initialStateNotification });
|
||||
setIsSubmitting(false);
|
||||
setAlert({ show: false, message: '' });
|
||||
setErrors({});
|
||||
};
|
||||
|
||||
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: [] }));
|
||||
}
|
||||
|
||||
if (errors[name]) {
|
||||
setErrors((prevErrors) => {
|
||||
const updatedErrors = { ...prevErrors };
|
||||
delete updatedErrors[name];
|
||||
return updatedErrors;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const doCreateNotification = useCallback(
|
||||
@ -120,32 +123,8 @@ const AddDialog = () => {
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
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);
|
||||
if (!validateFormNotification(formField, setErrors)) return;
|
||||
doCreateNotification(e);
|
||||
// console.log(formField);
|
||||
setAlert({ show: false, message: '' });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -179,7 +158,11 @@ const AddDialog = () => {
|
||||
<label className="form-label flex items-center gap-1 max-w-56">
|
||||
Send To<span className="text-red-500">*</span>
|
||||
</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">
|
||||
<input
|
||||
type="radio"
|
||||
@ -204,6 +187,13 @@ const AddDialog = () => {
|
||||
</label>
|
||||
</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 className="w-full">
|
||||
@ -277,7 +267,11 @@ const AddDialog = () => {
|
||||
<label className="form-label flex items-center gap-1 max-w-56">
|
||||
Type<span className="text-red-500">*</span>
|
||||
</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) => (
|
||||
<label key={type} className="flex items-center space-x-2">
|
||||
<input
|
||||
@ -293,6 +287,13 @@ const AddDialog = () => {
|
||||
))}
|
||||
</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 className="w-full">
|
||||
@ -300,7 +301,11 @@ const AddDialog = () => {
|
||||
<label className="form-label flex items-center gap-1 max-w-56">
|
||||
Send Via<span className="text-red-500">*</span>
|
||||
</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">
|
||||
<input
|
||||
type="radio"
|
||||
@ -336,6 +341,13 @@ const AddDialog = () => {
|
||||
</label>
|
||||
</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 className="w-full">
|
||||
@ -358,13 +370,20 @@ const AddDialog = () => {
|
||||
Content<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<Textarea
|
||||
className="input col-span-6"
|
||||
className={`input col-span-6 ${errors.content ? 'border-red-500' : ''}`}
|
||||
name="content"
|
||||
placeholder="Enter Content Notification"
|
||||
value={formField.content}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</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 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 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 {
|
||||
showAddDialog: boolean;
|
||||
handleAddDialog: (show: boolean) => void;
|
||||
@ -197,4 +186,3 @@ const ManageNotifContextProvider = ({ children }: { children: React.ReactNode })
|
||||
};
|
||||
|
||||
export { ManageNotifContext, ManageNotifContextProvider };
|
||||
export type { SelectedNotification };
|
||||
|
||||
Reference in New Issue
Block a user