update params customer_phone on module notification

This commit is contained in:
rajaoktf
2025-10-02 22:12:53 +07:00
parent b1c25c6b4a
commit 3285faae4c
2 changed files with 132 additions and 6 deletions

View File

@ -26,9 +26,10 @@ import { Button } from '@/components/ui/button';
import { useManageNotificationContext } from '../hooks/useManageNotificationContext';
import { doSaveLogActivity } from '@/actions/GlobalActions';
import { CustomerProps } from '@/pages/master/provider/blocks/AddDialog';
import { Check, ChevronDown } from 'lucide-react';
import { Check, ChevronDown, X } from 'lucide-react';
import { initialStateNotification, selectedNotification, validateFormNotification } from './Types';
import { useDebounce } from './useDebounce';
import Papa from 'papaparse';
const API_URL_CUSTOMER = apiConfig.service_customer;
const API_URL_NOTIFICATION = apiConfig.service_notification;
@ -42,16 +43,23 @@ const AddDialog = () => {
const [errors, setErrors] = useState<Record<string, string>>({});
const [searchQuery, setSearchQuery] = useState('');
const debouncedSearchQuery = useDebounce(searchQuery, 500);
const fileInputRef = useRef<HTMLInputElement>(null);
const [formField, setFormField] = useState<selectedNotification>(initialStateNotification);
const [open, setOpen] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [customers, setCustomers] = useState<CustomerProps[]>([]);
const [uploadedFileName, setUploadedFileName] = useState<string>('');
const resetForm = () => {
setFormField({ ...initialStateNotification });
setIsSubmitting(false);
setAlert({ show: false, message: '' });
setErrors({});
setUploadedFileName('');
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
@ -79,7 +87,6 @@ const AddDialog = () => {
try {
const response = await PostData(`${API_URL_NOTIFICATION}/send`, formField);
// console.log('send response :', response);
if (response?.status) {
handleAddDialog(false);
@ -148,6 +155,90 @@ const AddDialog = () => {
}
}, [showAddDialog]);
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
// Validasi tipe file
if (!file.name.endsWith('.csv')) {
toast.error('Please upload a CSV file');
return;
}
setUploadedFileName(file.name);
Papa.parse(file, {
header: true,
skipEmptyLines: true,
dynamicTyping: false,
complete: (results) => {
try {
const phoneNumbers: string[] = [];
// Extract phone numbers from CSV
results.data.forEach((row: any) => {
// Cari kolom yang berisi nomor telepon (bisa MSISDN, phone, atau nama kolom lain)
const phone = row.MSISDN || row.msisdn || row.phone || row.Phone || row.PHONE;
if (phone) {
// Bersihkan nomor telepon dari karakter non-digit
const cleanPhone = String(phone).replace(/\D/g, '');
if (cleanPhone && cleanPhone.length >= 10) {
phoneNumbers.push(cleanPhone);
}
}
});
if (phoneNumbers.length === 0) {
toast.error('No valid phone numbers found in CSV. Please check column name (MSISDN)');
setUploadedFileName('');
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
return;
}
// Update form field dengan phone numbers
setFormField((prev) => ({
...prev,
customer_phone: phoneNumbers
}));
toast.success(`${phoneNumbers.length} phone numbers extracted successfully`);
} catch (error) {
console.error('Error parsing CSV:', error);
toast.error('Failed to parse CSV file');
setUploadedFileName('');
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
}
},
error: (error) => {
console.error('Error reading CSV:', error);
toast.error('Error reading CSV file');
setUploadedFileName('');
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
}
});
};
const handleRemoveFile = () => {
setFormField((prev) => ({
...prev,
customer_phone: []
}));
setUploadedFileName('');
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
toast.info('Phone numbers cleared');
};
return (
<Dialog open={showAddDialog} onOpenChange={handleAddDialog}>
<DialogContent className="container-fixed max-w-[768px] flex flex-col p-5 overflow-hidden">
@ -358,6 +449,7 @@ const AddDialog = () => {
checked={formField.via === 'whatsapp'}
onChange={handleChange}
className="accent-blue-600"
disabled
/>
<span>WhatsApp</span>
</label>
@ -372,6 +464,38 @@ const AddDialog = () => {
)}
</div>
<div className="w-full">
<div className="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label className="form-label flex items-center gap-1 max-w-56">
Upload MSISDN CSV
</label>
<div className="flex-1 flex flex-col gap-2">
<Input
ref={fileInputRef}
type="file"
accept=".csv"
onChange={handleFileUpload}
className="input col-span-6"
/>
{uploadedFileName && formField.customer_phone.length > 0 && (
<div className="flex items-center gap-2 text-sm text-green-600 bg-green-50 px-3 py-2 rounded-md">
<Check className="w-4 h-4" />
<span>
{uploadedFileName} - {formField.customer_phone.length} phone numbers
</span>
<button
type="button"
onClick={handleRemoveFile}
className="ml-auto text-red-500 hover:text-red-700"
>
<X className="w-4 h-4" />
</button>
</div>
)}
</div>
</div>
</div>
<div className="w-full">
<div className="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label className="form-label flex items-center gap-1 max-w-56">
@ -381,7 +505,7 @@ const AddDialog = () => {
className="input col-span-6"
name="content"
placeholder="Enter OTP (5 digits)"
value={formField.content}
// value={formField.content}
onChange={(e) => {
const value = e.target.value;
if (/^\d{0,5}$/.test(value)) {

View File

@ -7,6 +7,7 @@ export interface selectedNotification {
via: string;
subject: string;
content: string;
customer_phone: string[];
}
export const initialStateNotification: selectedNotification = {
@ -15,7 +16,8 @@ export const initialStateNotification: selectedNotification = {
type: '',
via: '',
subject: '',
content: ''
content: '',
customer_phone: []
};
export const validateFormNotification = (
@ -47,8 +49,8 @@ export const validateFormNotification = (
// Validasi khusus content
if (formField.via === 'whatsapp') {
if (!formField.content || !/^\d{5}$/.test(formField.content)) {
newErrors.content = 'Content harus berupa 5 digit angka (OTP)';
toast.error('Content harus berupa 5 digit angka (OTP)');
newErrors.content = 'Content must be a 5-digit number (OTP)';
toast.error('Content must be a 5-digit number (OTP)');
isValid = false;
}
} else {