//REPLAN POPUP import { useEffect, useRef, useMemo } from "react"; import closeRound from "../../assets/closeRound.svg"; import { useDispatch, useSelector } from "react-redux"; import { SendConfirmationEmail as transporterSendConfirmationEmail, fetchTransporterData, } from "@/store/transporter/transporterSlice"; import { poService } from "@/services/axiosInstance"; import { SendConfirmationEmail } from "@/store/confirm/confirm"; import { toast } from "@/hooks/use-toast"; import { getMailHistory } from "@/store/replanOrder/getMailHistory"; import { useLocation } from "react-router-dom"; import { jsPDF } from "jspdf"; import html2canvas from "html2canvas"; import { useFileDropzone } from "@/lib/utils"; import { AnimatePresence } from "framer-motion"; import AnimatedBackdrop from "@/Animation/AnimatedBackdrop"; import AnimatedPopup from "@/Animation/AnimatedPopup"; import CancelConfirmPopup from "./CancelConfirmPopup"; import ReplanCustomerContent from "./ReplanCustomerContent"; import ReplanErrorPage from "./ReplanErrorPage"; import ReplanTransporterContent from "./ReplanTransporterContent"; import ReplanTransporterCancelContent from "./ReplanTransporterCancelContent"; import { formatData, generateCustomerHtml, generateTransporterHtml, generateCancelTransporterHtml, } from "./utils/emailTemplates"; import { TABS, resolveInitialTab } from "./utils/tabConfig"; import { useReplanPopupState } from "./hooks/useReplanPopupState"; const ReplanPopup = ({ productArticleCode, showPopup, setShowPopup, openSendPopup, setOpenSendPopup, changedFields, orderData, setIsMailsSent, onTrigger, initialOrderData, userClickedConfirm, }) => { const createNewList = useSelector((state) => state?.saveOrder?.createNewList); const extraCostNote = createNewList?.extra_cost_note; const extraCostBorneBy = createNewList?.extra_cost_borne_by; const { formData, setFormData, updateFormData, addRecipient, removeRecipient, addCC, removeCC, setActiveTab, setActiveSubTab, setLoadingState, TAB_TYPES, SUB_TAB_TYPES, RECIPIENT_TYPES, } = useReplanPopupState(); const product = productArticleCode ? productArticleCode : orderData?.product_article_code; // const isPS3 = product === "50000"; const isPS3 = orderData?.need_mdgd === true; const dispatch = useDispatch(); const location = useLocation(); const isShowSimilarOrder = location.search.includes( "&showSimilarOrders=true", ); const searchParams = new URLSearchParams(location.search); const orderId = searchParams.get("id"); const exactOrderNo = orderData?.exact_order_no; const userId = useSelector((state) => state?.auth?.user?.Id); const changedKeys = Object.keys(changedFields); const pdfRef = useRef(); let formattedDate; const customerLoadingDate = initialOrderData?.loading_date ? new Date(initialOrderData?.loading_date) : null; const customerFileInputRef = useRef(null); const transportFileInputRef = useRef(null); useEffect(() => { formattedDate = customerLoadingDate instanceof Date && !isNaN(customerLoadingDate) ? customerLoadingDate.toLocaleDateString("en-GB") : ""; }, [customerLoadingDate]); const transporterId = Number(orderData?.transporter_id); useEffect(() => { dispatch(getMailHistory(orderId)); }, [userClickedConfirm]); const mailHistory = useSelector( (state) => state?.mailHistory?.mailHistoryList, ); const transporterInfo = useSelector((state) => state.transporterInfo); const transportData = transporterInfo?.transporter; const instructions = transportData?.instructions; const deliveryCity = transportData?.delivery_city; const isTransporterIdChangedFromEmpty = changedFields?.transporter_id?.from === ""; const showTransporterTabOnly = !formData.transporterMailOnly && transporterId !== 0; const transporterMailNotSended = !formData.isTransportMailSent || isTransporterIdChangedFromEmpty; const isTransporterCancelled = changedFields.transporter_name && changedFields.transporter_name.from !== ""; useEffect(() => { let isMounted = true; if (mailHistory) { const transporterIds = mailHistory ?.filter((item) => item.type === "transporter") .map((item) => item.receipient_id); const customerIds = mailHistory ?.filter((item) => item.type === "customer") .map((item) => item.receipient_id); if (transporterIds.includes(orderData?.transporter_id)) { setFormData((prev) => ({ ...prev, isTransportMailSent: true })); } if (customerIds.includes(Number(orderData?.ordered_by))) { setFormData((prev) => ({ ...prev, isCustomerMailSent: true })); } } return () => { isMounted = false; }; }, [mailHistory, orderData]); const fetchCustomerEmailInfoAxios = async (orderId) => { try { const response = await poService.post( "/po_service/get_customer_mail_info/", { order_id: Number(orderId), }, ); if (response.status === 200) { const resData = response.data.data; setFormData((prev) => ({ ...prev, customerToEmail: resData?.to, customerCCList: resData?.cc, customerExactId: resData?.customer_exact_id, })); } } catch (error) { console.error(error); } }; useEffect(() => { if (orderId) { fetchCustomerEmailInfoAxios(orderId); } }, [orderId]); // }, [userClickedConfirm]); useEffect(() => { const rawCustomerName = orderData?.customer_name?.trim(); const rawProductName = orderData?.product_name?.trim(); const customerNameWithDash = rawCustomerName ? rawCustomerName + " - " : ""; const productNameWithDash = rawProductName ? rawProductName + " - " : ""; const customerSubject = `Change in Delivery: ${productNameWithDash} ${customerNameWithDash}O/Ref.${exactOrderNo}-Y/Ref.${orderData?.po_number}, Loading on ${formattedDate}`; const transporterSubject = `Change in Delivery: ${productNameWithDash} ${customerNameWithDash}O/Ref.${exactOrderNo}, Loading on ${formattedDate}`; const transporterCancelSubject = `Cancel Transport: ${productNameWithDash} ${customerNameWithDash}O/Ref.${exactOrderNo}, Loading on ${formattedDate} to ${deliveryCity}`; setFormData((prev) => ({ ...prev, customerSubject, transporterSubject, transporterCancelSubject, })); }, [exactOrderNo, formattedDate]); useEffect(() => { if (orderId) dispatch(fetchTransporterData(orderId)); if (transportData) { setFormData((prev) => ({ ...prev, transportToEmail: transportData?.to, transportCCList: transportData?.cc, })); } }, [userClickedConfirm]); // formatData moved to utils/emailTemplates const isFCAorEXW = ["EXW", "FCA"].includes(orderData?.incoterms); useEffect(() => { const formattedData = formatData(changedFields, orderData); const onlyLoadingAtChanged = Object.keys(formattedData).length === 2 && Object.keys(formattedData).includes("Loading At") && Object.keys(formattedData).includes("."); if ( Object.keys(formattedData).length === 2 && onlyLoadingAtChanged && !isFCAorEXW && transporterId === 0 ) { setOpenSendPopup(false); setShowPopup("orderUpdationPopUp"); } if (!formData.isBodyChanged) { let _latestOnlyOneCustomerRow = false; let customerBodyRowsCount = 0; Object.entries(formattedData).forEach(([key, value]) => { if (key === "Loading At" && !isFCAorEXW) return; if (key === "Loading" && !isFCAorEXW) return; if (key === "Delivery" && isFCAorEXW) return; if (typeof value === "object" && value !== null) { customerBodyRowsCount++; if (!isFCAorEXW && key !== "Delivery Quantity") { if (value.to.length !== 0) _latestOnlyOneCustomerRow = true; } } else { customerBodyRowsCount++; } }); const isOnlyOneCustomerRow = customerBodyRowsCount === 1; const customerHtml = generateCustomerHtml( formattedData, extraCostBorneBy, extraCostNote, isFCAorEXW, ); const transporterHtml = generateTransporterHtml( formattedData, exactOrderNo, formattedDate, extraCostBorneBy, extraCostNote, formData.removeInstructionsMail, instructions?.length || 0, ); const cancelTransporterHtml = generateCancelTransporterHtml( exactOrderNo, formattedDate, deliveryCity, ); const { tab: resolvedTab, transporterMailOnly: shouldSetTransporterMailOnly } = resolveInitialTab({ changedKeys, formData: { ...formData, latestOnlyOneCustomerRow: _latestOnlyOneCustomerRow, }, isOnlyOneCustomerRow, isFCAorEXW, }); setFormData((prev) => ({ ...prev, cancelTransporterBody: cancelTransporterHtml, customerBody: customerHtml, transporterBody: transporterHtml, latestOnlyOneCustomerRow: _latestOnlyOneCustomerRow, transporterMailOnly: shouldSetTransporterMailOnly, topHeadingTab: resolvedTab === TAB_TYPES.TRANSPORTER ? TAB_TYPES.TRANSPORTER : prev.topHeadingTab, })); } }, [ changedFields, formData.latestOnlyOneCustomerRow === true, formData.removeInstructionsMail, instructions, extraCostBorneBy, ]); const generateInstructionsPDF = async () => { try { const input = pdfRef.current; if (!input) return null; const canvas = await html2canvas(input, { scale: 2, logging: false, useCORS: true, allowTaint: true, }); const pdf = new jsPDF("p", "mm", "a4"); pdf.addImage(canvas, "JPEG", 0, 0, 210, 297); const pdfBytes = pdf.output("arraybuffer"); const pdfBase64 = btoa( new Uint8Array(pdfBytes).reduce( (data, byte) => data + String.fromCharCode(byte), "", ), ); return pdfBase64; } catch (error) { console.error("Error generating PDF:", error); throw error; } }; const sendCustomerEmail = async () => { setLoadingState(RECIPIENT_TYPES.CUSTOMER, true); try { const emailPayload = { emailList: formData.customerToEmail, ccList: formData.customerCCList, subject: formData.customerSubject, initiated_by: userId, order_id: [Number(orderId)], type: "customer_replan_sent", receipient_id: orderData?.order_id, customer_exact_id: formData.customerExactId, html: formData.customerBody?.length > 0 ? formData.customerBody .replace(/0\.8vw/g, "16px") .replace(/0\.66vw/g, "12px") : formData.customerBody, attachments: formData.customerAttachments, }; const response = await dispatch(SendConfirmationEmail(emailPayload)); if (response.type === "/customers/sendConfirmationEmail/fulfilled") { toast({ title: "Email sent successfully", description: "Email sent successfully", status: "success", className: "bg-green-500", }); } else { toast({ title: "Email sending failed", description: response?.payload?.message, status: "error", className: "bg-red-500", }); } } catch (error) { toast({ title: "Email sending failed", description: error?.message || "An error occurred", status: "error", className: "bg-red-500", }); } finally { setLoadingState(RECIPIENT_TYPES.CUSTOMER, false); } }; const sendTransporterEmail = async () => { updateFormData({ clickedSend: true, }); setLoadingState(RECIPIENT_TYPES.TRANSPORTER, true); try { const pdfBase64 = await generateInstructionsPDF(); const emailPayload = { emailList: formData.transportToEmail, ccList: formData.transportCCList, subject: formData.transporterSubject, initiated_by: userId, order_id: [Number(orderId)], type: "transporter_replan_sent", receipient_id: transporterId, html: formData.transporterBody?.length > 0 ? formData.transporterBody .replace(/0\.8vw/g, "16px") .replace(/0\.66vw/g, "12px") : formData.transporterBody, attachments: [ ...(!formData.removeInstructionsMail && instructions?.length > 0 ? [{ name: "UnloadingInstructions.pdf", data: pdfBase64 }] : []), ...formData.transportAttachments, ], }; const response = await dispatch( transporterSendConfirmationEmail(emailPayload), ); setLoadingState(RECIPIENT_TYPES.TRANSPORTER, false); if (response.type === "/customers/sendConfirmationEmail/fulfilled") { toast({ title: "Email sent successfully", description: "Email sent successfully", status: "success", className: "bg-green-500", }); } else { toast({ title: "Email sending failed", description: response?.payload?.message, status: "error", className: "bg-red-500", }); } } catch (error) { toast({ title: "Email sending failed", description: error?.message || "An error occurred", status: "error", className: "bg-red-500", }); } finally { updateFormData({ clickedSend: false, }); setLoadingState(RECIPIENT_TYPES.TRANSPORTER, false); } }; const sendCancelTransporterEmail = async () => { setLoadingState(RECIPIENT_TYPES.TRANSPORTER, true); try { const emailPayload = { emailList: formData.transportToEmail, ccList: formData.transportCCList, subject: formData.transporterCancelSubject, initiated_by: userId, order_id: [Number(orderId)], type: "transporter_cancelled", receipient_id: transporterId, html: formData.cancelTransporterBody?.length > 0 ? formData.cancelTransporterBody .replace(/0\.8vw/g, "16px") .replace(/0\.66vw/g, "12px") : formData.cancelTransporterBody, attachments: formData.transportAttachments, }; const response = await dispatch( transporterSendConfirmationEmail(emailPayload), ); if (response.type === "/customers/sendConfirmationEmail/fulfilled") { toast({ title: "Email sent successfully", description: "Email sent successfully", status: "success", className: "bg-green-500", }); } else { toast({ title: "Email sending failed", description: response?.payload?.message, status: "error", className: "bg-red-500", }); } } catch (error) { toast({ title: "Email sending failed", description: error?.message || "An error occurred", status: "error", className: "bg-red-500", }); } finally { setLoadingState(RECIPIENT_TYPES.TRANSPORTER, false); } }; const handleClosePopup = () => { setOpenSendPopup(false); window.location.reload(); }; const validateEmail = (email) => { const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailPattern.test(email); }; const handleCustomerEmailKeyDown = (event) => { if (event.key === "Enter" || event.key === ",") { event.preventDefault(); const email = formData.customerEmailInput.trim(); if (email && validateEmail(email)) { addRecipient(RECIPIENT_TYPES.CUSTOMER, email); updateFormData({ customerEmailInput: "" }); } } }; const handleTransporterEmailKeyDown = (event) => { if (event.key === "Enter" || event.key === ",") { event.preventDefault(); const email = formData.transportEmailInput.trim(); if (email && validateEmail(email)) { addRecipient(RECIPIENT_TYPES.TRANSPORTER, email); updateFormData({ transportEmailInput: "" }); } } }; const handleFileUpload = (e) => { const files = Array.from(e.target.files || []); const MAX_FILE_SIZE = 25 * 1024 * 1024; const oversizedFiles = files.filter((file) => file.size > MAX_FILE_SIZE); if (oversizedFiles.length > 0) { toast({ title: "File size exceeded", description: `Please upload a file smaller than 25 MB.`, status: "error", className: "bg-red-300", }); return; } files.forEach((file) => { const reader = new FileReader(); reader.onload = (event) => { const base64 = event.target?.result.split(",")[1]; setFormData((prev) => ({ ...prev, customerAttachments: [ ...(Array.isArray(prev.customerAttachments) ? prev.customerAttachments : []), { name: file.name, data: base64 }, ], })); }; reader.readAsDataURL(file); }); if (customerFileInputRef.current) customerFileInputRef.current.value = null; }; const { getRootProps: getCustomerRootProps, getInputProps: getCustomerInputProps, isDragActive: isCustomerDragActive, } = useFileDropzone({ attachments: Array.isArray(formData.customerAttachments) ? formData.customerAttachments : [], setAttachments: (updater) => setFormData((prev) => ({ ...prev, customerAttachments: typeof updater === "function" ? updater( Array.isArray(prev.customerAttachments) ? prev.customerAttachments : [], ) : Array.isArray(updater) ? updater : [], })), toast, maxFiles: 50, maxSizeMB: 25, acceptedFormats: {}, convertToBase64: true, }); const { getRootProps: getTransportRootProps, getInputProps: getTransportInputProps, isDragActive: isTransportDragActive, } = useFileDropzone({ attachments: Array.isArray(formData.transportAttachments) ? formData.transportAttachments : [], setAttachments: (updater) => setFormData((prev) => ({ ...prev, transportAttachments: typeof updater === "function" ? updater( Array.isArray(prev.transportAttachments) ? prev.transportAttachments : [], ) : Array.isArray(updater) ? updater : [], })), toast, maxFiles: 50, maxSizeMB: 25, acceptedFormats: {}, convertToBase64: true, }); const handleTransportFileUpload = (e) => { const files = Array.from(e.target.files || []); const MAX_FILE_SIZE = 25 * 1024 * 1024; const oversizedFiles = files.filter((file) => file.size > MAX_FILE_SIZE); if (oversizedFiles.length > 0) { toast({ title: "File size exceeded", description: `Please upload a file smaller than 25 MB.`, status: "error", className: "bg-red-300", }); return; } files.forEach((file) => { const reader = new FileReader(); reader.onload = (event) => { const base64 = event.target?.result.split(",")[1]; setFormData((prev) => ({ ...prev, transportAttachments: [ ...(Array.isArray(prev.transportAttachments) ? prev.transportAttachments : []), { name: file.name, data: base64 }, ], })); }; reader.readAsDataURL(file); }); if (transportFileInputRef.current) transportFileInputRef.current.value = null; }; function onChangeCustomerBody(e) { setFormData((prev) => ({ ...prev, customerBody: e.target.value, isBodyChanged: true, })); } function onChangeTransporterBody(e) { setFormData((prev) => ({ ...prev, transporterBody: e.target.value, isBodyChanged: true, })); } function onChangeCancelTransporterBody(e) { setFormData((prev) => ({ ...prev, cancelTransporterBody: e.target.value, isBodyChanged: true, })); } const handleCustomerMailSend = () => { setIsMailsSent(true); sendCustomerEmail(); setTimeout(() => { setShowPopup(""); }, 3000); }; const handleTransporterMailSend = () => { setIsMailsSent(true); if ( changedFields.transporter_name && changedFields.transporter_name.from !== "" ) { sendCancelTransporterEmail(); } else { sendTransporterEmail(); } setTimeout(() => { setShowPopup(""); }, 3000); }; const handleDocumentMailClick = () => { setOpenSendPopup(false); if (!isShowSimilarOrder) { window.location.reload(); } onTrigger(); }; const handleSendMail = () => { if (instructions?.length === 0 && !formData.removeInstructionsMail) { toast({ title: "Please add instructions or close the instructions tab to send the mail.", status: "error", className: "bg-red-400", duration: 3000, }); } else { setActiveSubTab(SUB_TAB_TYPES.INSTRUCTIONS); setTimeout(() => { setActiveSubTab(SUB_TAB_TYPES.BODY); }, 2000); setShowPopup("confirmTransportMailSendPopup"); } }; return ( <> {openSendPopup && (

close
{TABS.map((tab) => { const isVisible = tab.id === TAB_TYPES.CUSTOMER ? !formData.transporterMailOnly : transporterId !== 0; if (!isVisible) return null; const isActive = formData.topHeadingTab === tab.id; return (
{ if (tab.id === TAB_TYPES.CUSTOMER) { setActiveTab(TAB_TYPES.CUSTOMER); } else { setActiveTab(TAB_TYPES.TRANSPORTER); } }} className={`cursor-pointer text-sm font-semibold px-12 py-3 rounded-t text-center ${ isActive ? "text-[#00a5ad] bg-gray-300" : "text-[#7c7c7c] hover:bg-gray-200" }`} style={{ width: tab.width }} > {tab.label}
); })}
{showTransporterTabOnly && (
{TABS.map((tab) => (
))}
)} {formData.topHeadingTab === TAB_TYPES.CUSTOMER && ( <> {isPS3 ? ( <>

No need to send a confirmation email to the customer for PS3 orders.

) : !formData.isCustomerMailSent ? ( <> ) : ( <> updateFormData({ isBodyChanged: val || false }) } handleDocumentMailClick={handleDocumentMailClick} setShowPopup={setShowPopup} getCustomerRootProps={getCustomerRootProps} isCustomerDragActive={isCustomerDragActive} getCustomerInputProps={getCustomerInputProps} validateEmail={validateEmail} setFormData={setFormData} formData={formData} setCustomerBody={(val) => updateFormData({ customerBody: val || "" }) } setSelectedColor={(val) => updateFormData({ selectedColor: val || "" }) } /> )} )} {formData.topHeadingTab === TAB_TYPES.TRANSPORTER && (isFCAorEXW ? ( ) : ( <> {transporterMailNotSended ? ( <> ) : (
{isTransporterCancelled ? ( { setShowPopup("confirmTransportMailSendPopup"); }} /> ) : ( )}
)} ))} setFormData((prev) => ({ ...prev, removeInstructionsMail: val || false, })) } />
)}
); }; export default ReplanPopup;