From b75950b0d6a465b8bafe9b6f2159c5ea8b00d797 Mon Sep 17 00:00:00 2001 From: Malini Date: Thu, 5 Feb 2026 08:42:40 +0530 Subject: [PATCH] added delete api in draft flow --- .../dashboard/SubmissionHistory.jsx | 45 +++- .../components/dashboard/SurveyCarousel.jsx | 1 + .../EstablishmentInfo/EstablishmentInfo.jsx | 65 ++++- .../survey/ProductData/ProductData.jsx | 64 +++-- .../survey/ReviewSubmit/ReviewSubmit.jsx | 241 ++++++++---------- .../src/pages/Overview/Overview.jsx | 25 +- .../services/submissions/submissionService.js | 78 ++---- 7 files changed, 287 insertions(+), 232 deletions(-) diff --git a/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx b/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx index 4199104..f775abe 100644 --- a/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx +++ b/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx @@ -4,6 +4,7 @@ import Table from '@/components/common/Table'; import Footer from '../common/Footer'; import HeaderBar from '@/components/layout/HeaderBar'; import DetailedOverview from '@/components/overview/DetailedOverview'; +import { deleteDraftSubmission } from '@/services/submissions/submissionService'; const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg'; const pencilIconSrc = '/assets/images/PencilSimple.svg'; @@ -142,6 +143,14 @@ export const SubmissionHistory = ({ history = [], loading = false, error = '' }) const [selectedSubmission, setSelectedSubmission] = React.useState(null); const [currentPage, setCurrentPage] = React.useState(1); const [hoveredDelete, setHoveredDelete] = React.useState(null); + const [toast, setToast] = React.useState({ show: false, message: '', type: 'success' }); + + const showToast = (message, type = 'success') => { + setToast({ show: true, message, type }); + setTimeout(() => { + setToast({ ...toast, show: false }); + }, 1000); + }; const pageSize = 10; const navigate = useNavigate(); @@ -171,14 +180,28 @@ export const SubmissionHistory = ({ history = [], loading = false, error = '' }) }; const handleDeleteDraft = async (e, submission) => { - e.preventDefault(); - e.stopPropagation(); - try { - - } catch (error) { - console.error('Error deleting submission:', error); + e.preventDefault(); + e.stopPropagation(); + try { + if (!submission?.id) { + throw new Error('No submission ID provided'); } - }; + + if (!window.confirm('Are you sure you want to delete this draft?')) { + return; + } + + await deleteDraftSubmission(submission.id); + showToast('Draft deleted successfully', 'success'); + + + // Optionally reload the page or refresh data + window.location.reload(); + } catch (error) { + console.error('Error deleting submission:', error); + alert(error.message || 'Failed to delete draft'); + } +}; const normalizedHistory = React.useMemo(() => { if (!Array.isArray(history)) return []; @@ -276,6 +299,14 @@ const handleDeleteDraft = async (e, submission) => { return ( <>
+ {/* Add this toast component */} + {toast.show && ( + setToast({ ...toast, show: false })} + /> + )}

diff --git a/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx b/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx index b68e0c2..c4cd61e 100644 --- a/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx +++ b/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx @@ -63,6 +63,7 @@ const SurveyCarousel = ({ - + */} +

{(loading || error) && ( diff --git a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx index c0f5315..ae0c26a 100644 --- a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx +++ b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx @@ -476,17 +476,28 @@ const handleSaveDraft = async () => { setIsSavingDraft(true); // Get current submission from localStorage + let currentSubmission; const currentSubmissionStr = localStorage.getItem('currentSubmission'); + const establishmentFormDataStr = localStorage.getItem('establishmentFormData'); + if (!currentSubmissionStr) { - throw new Error('Current submission data not found'); + // If no current submission, try to use establishmentFormData + if (!establishmentFormDataStr) { + throw new Error('No submission data found. Please complete the establishment information first.'); + } + currentSubmission = JSON.parse(establishmentFormDataStr); + } else { + currentSubmission = JSON.parse(currentSubmissionStr); } - const currentSubmission = JSON.parse(currentSubmissionStr); + // const currentSubmission = JSON.parse(currentSubmissionStr); const currentQuarter = localStorage.getItem('currentQuarter'); const currentYear = localStorage.getItem('currentYear') // Get establishment ID from current submission const submissionId = currentSubmission.id; // Changed this line to get ID from currentSubmission - const establishmentId = currentSubmission.establishment_id; + const establishmentId = currentSubmission.establishment_id || + (currentSubmission.establishment && currentSubmission.establishment.id) || + localStorage.getItem('establishment_id'); if (!establishmentId) { throw new Error('Establishment ID not found in submission'); } @@ -510,10 +521,29 @@ const handleSaveDraft = async () => { } // Get establishment data - const establishment = currentSubmission.establishment; - if (!establishment) { - throw new Error('Establishment data not found in submission'); - } + // Get establishment data +let establishment; +if (currentSubmission.establishment) { + establishment = currentSubmission.establishment; +} else { + // Try to get establishment data from establishmentFormData in localStorage + const establishmentFormDataStr = localStorage.getItem('establishmentFormData'); + if (establishmentFormDataStr) { + const establishmentFormData = JSON.parse(establishmentFormDataStr); + establishment = { + emirati_male: establishmentFormData.employeeInfo?.emiratiMale || 0, + emirati_female: establishmentFormData.employeeInfo?.emiratiFemale || 0, + non_emirati_male: establishmentFormData.employeeInfo?.nonEmiratiMale || 0, + non_emirati_female: establishmentFormData.employeeInfo?.nonEmiratiFemale || 0, + total_emirati: establishmentFormData.employeeInfo?.totalEmirati || 0, + total_employees: establishmentFormData.employeeInfo?.totalEmployees || 0 + }; + } +} + +if (!establishment) { + throw new Error('Establishment data not found in submission or localStorage'); +} // Prepare products data in the required format const formattedProducts = products.map(product => { @@ -585,14 +615,7 @@ const handleSaveDraft = async () => { if (submissionId) { // Update existing submission response = await resubmitSurvey(submissionId, payload); - toast.success('Draft updated successfully', { - position: "top-right", - autoClose: 3000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true - }); + alert('Draft updated successfully') } else { // Create new submission response = await submitSurvey(payload); @@ -603,19 +626,12 @@ const handleSaveDraft = async () => { localStorage.setItem('currentSubmission', JSON.stringify(updatedSubmission)); } - toast.success('Draft saved successfully', { - position: "top-right", - autoClose: 3000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true - }); + alert('Draft saved successfully') } } catch (error) { console.error('Error saving draft:', error); - toast.error(error.message || 'Failed to save draft'); + alert(error.message || 'Failed to save draft'); } finally { setIsSavingDraft(false); } diff --git a/ipi-survey-platform/src/components/survey/ReviewSubmit/ReviewSubmit.jsx b/ipi-survey-platform/src/components/survey/ReviewSubmit/ReviewSubmit.jsx index 1ffb246..f784f78 100644 --- a/ipi-survey-platform/src/components/survey/ReviewSubmit/ReviewSubmit.jsx +++ b/ipi-survey-platform/src/components/survey/ReviewSubmit/ReviewSubmit.jsx @@ -445,23 +445,33 @@ const ReviewSubmit = ({ return ''; }); - const handleSaveDraft = async () => { +const handleSaveDraft = async () => { try { setIsSavingDraft(true); // Get current submission from localStorage + let currentSubmission; const currentSubmissionStr = localStorage.getItem('currentSubmission'); + const establishmentFormDataStr = localStorage.getItem('establishmentFormData'); + if (!currentSubmissionStr) { - throw new Error('Current submission data not found'); + // If no current submission, try to use establishmentFormData + if (!establishmentFormDataStr) { + throw new Error('No submission data found. Please complete the establishment information first.'); + } + currentSubmission = JSON.parse(establishmentFormDataStr); + } else { + currentSubmission = JSON.parse(currentSubmissionStr); } - const currentSubmission = JSON.parse(currentSubmissionStr); + // const currentSubmission = JSON.parse(currentSubmissionStr); const currentQuarter = localStorage.getItem('currentQuarter'); - const currentYear = localStorage.getItem('currentYear'); - + const currentYear = localStorage.getItem('currentYear') // Get establishment ID from current submission - const submissionId = currentSubmission.id; - const establishmentId = currentSubmission.establishment_id; - + const submissionId = currentSubmission.id; // Changed this line to get ID from currentSubmission + + const establishmentId = currentSubmission.establishment_id || + (currentSubmission.establishment && currentSubmission.establishment.id) || + localStorage.getItem('establishment_id'); if (!establishmentId) { throw new Error('Establishment ID not found in submission'); } @@ -471,10 +481,8 @@ const ReviewSubmit = ({ if (!userProfileStr) { throw new Error('User profile not found'); } - const userProfile = JSON.parse(userProfileStr); const createdById = userProfile?.id; - if (!createdById) { throw new Error('User ID not found in profile'); } @@ -482,49 +490,85 @@ const ReviewSubmit = ({ // Get quarter and year from current submission const effectiveQuarter = currentQuarter; const effectiveYear = currentYear; - if (!effectiveQuarter || !effectiveYear) { throw new Error('Quarter and year are required in submission'); } // Get establishment data - const establishment = currentSubmission.establishment; - if (!establishment) { - throw new Error('Establishment data not found in submission'); - } + // Get establishment data +let establishment; +if (currentSubmission.establishment) { + establishment = currentSubmission.establishment; +} else { + // Try to get establishment data from establishmentFormData in localStorage + const establishmentFormDataStr = localStorage.getItem('establishmentFormData'); + if (establishmentFormDataStr) { + const establishmentFormData = JSON.parse(establishmentFormDataStr); + establishment = { + emirati_male: establishmentFormData.employeeInfo?.emiratiMale || 0, + emirati_female: establishmentFormData.employeeInfo?.emiratiFemale || 0, + non_emirati_male: establishmentFormData.employeeInfo?.nonEmiratiMale || 0, + non_emirati_female: establishmentFormData.employeeInfo?.nonEmiratiFemale || 0, + total_emirati: establishmentFormData.employeeInfo?.totalEmirati || 0, + total_employees: establishmentFormData.employeeInfo?.totalEmployees || 0 + }; + } +} - // Prepare products data - const formattedProducts = products.map(product => ({ - id: product.id || 0, - product_id: product.product_id || null, - unit_id: product.unit || '', - annual_installed_capacity: product.capacity || '0', - previous_quantity_period_one: product.octQuantity || '0', - previous_quantity_period_two: product.novQuantity || '0', - previous_quantity_period_three: product.decQuantity || '0', - previous_cost_period_one: product.octCost || '0', - previous_cost_period_two: product.novCost || '0', - previous_cost_period_three: product.decCost || '0', - current_quantity_period_one: product.janQuantity || '0', - current_quantity_period_two: product.febQuantity || '0', - current_quantity_period_three: product.marQuantity || '0', - current_cost_period_one: product.janCost || '0', - current_cost_period_two: product.febCost || '0', - current_cost_period_three: product.marCost || '0', - forecast_quantity_period_one: product.aprQuantity || '0', - forecast_quantity_period_two: product.mayQuantity || '0', - forecast_quantity_period_three: product.junQuantity || '0', - forecast_cost_period_one: product.aprCost || '0', - forecast_cost_period_two: product.mayCost || '0', - forecast_cost_period_three: product.junCost || '0', - variation_reason_master_id: product.variationReason || null, - other_variation_reason: product.otherVariationReason || '', - zero_target_reason_master_id: product.zeroTargetReason || null, - other_zero_target_reason: product.otherZeroTargetReason || '', - remarks: product.remarks || '' - })); +if (!establishment) { + throw new Error('Establishment data not found in submission or localStorage'); +} - // Prepare the complete payload + // Prepare products data in the required format + const formattedProducts = products.map(product => { + // Get the selected product option to access product_id + const selectedProduct = productOptions.find(p => p.value === product.product); + const existingProduct = currentSubmission.products?.find(p => + p.product_id === product.product_id || + p.product?.id === product.product_id + ); + return { + id: existingProduct?.id || 0, + product_id: selectedProduct?.product_id || product.product_id || null, + unit_id: product.unit?.toString() || '', // Ensure unit_id is a string + annual_installed_capacity: product.capacity || '0', + previous_quantity_period_one: product.octQuantity || '0', + previous_quantity_period_two: product.novQuantity || '0', + previous_quantity_period_three: product.decQuantity || '0', + previous_cost_period_one: product.octCost || '0', + previous_cost_period_two: product.novCost || '0', + previous_cost_period_three: product.decCost || '0', + current_quantity_period_one: product.janQuantity || '0', + current_quantity_period_two: product.febQuantity || '0', + current_quantity_period_three: product.marQuantity || '0', + current_cost_period_one: product.janCost || '0', + current_cost_period_two: product.febCost || '0', + current_cost_period_three: product.marCost || '0', + forecast_quantity_period_one: product.aprQuantity || '0', + forecast_quantity_period_two: product.mayQuantity || '0', + forecast_quantity_period_three: product.junQuantity || '0', + forecast_cost_period_one: product.aprCost || '0', + forecast_cost_period_two: product.mayCost || '0', + forecast_cost_period_three: product.junCost || '0', + // Previous quarter (Q4) - October + previous_quantity: product.octQuantity || '0', + previous_cost: product.octCost || '0', + // Current quarter (Q1) - Using November as current (as per previous implementation) + // If you want to use a different field for current, replace novQuantity/novCost with the appropriate field + current_quantity: product.novQuantity || '0', + current_cost: product.novCost || '0', + // Next quarter forecast (Q2) - December + forecast_quantity: product.decQuantity || '0', + forecast_cost: product.decCost || '0', + variation_reason_master_id: product.variationReason || '', + other_variation_reason: product.otherVariationReason || '', + zero_target_reason_master_id: product.zeroTargetReason || '', + other_zero_target_reason: product.otherZeroTargetReason || '', + remarks: product.remarks || remarks || '' // Use product.remarks if available, otherwise use the component's remarks state + }; + }); + + // Prepare the complete payload with values from currentSubmission const payload = { establishment_id: establishmentId, quarter: effectiveQuarter, @@ -539,95 +583,30 @@ const ReviewSubmit = ({ created_by: createdById, products: formattedProducts }; - let response; - try { - if (submissionId) { - // Update existing submission - response = await resubmitSurvey(submissionId, payload); - // Handle different response formats - const responseData = response?.data || response; - - if (responseData) { - // Update local storage with the updated submission - const updatedSubmission = { - ...currentSubmission, - ...responseData, - updated_at: new Date().toISOString() - }; - localStorage.setItem('currentSubmission', JSON.stringify(updatedSubmission)); - - toast.success('Draft updated successfully', { - position: "top-right", - autoClose: 3000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true - }); - return; // Success, exit the function - } - } else { - // Create new submission - response = await submitSurvey(payload); - // Handle different response formats - const responseData = response?.data || response; - - if (responseData && (responseData.id || responseData.submission_id)) { - // Update local storage with the new submission ID - const updatedSubmission = { - ...currentSubmission, - id: responseData.id || responseData.submission_id, - status: 'Draft', - created_at: new Date().toISOString() - }; - localStorage.setItem('currentSubmission', JSON.stringify(updatedSubmission)); - - toast.success('Draft saved successfully', { - position: "top-right", - autoClose: 3000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true - }); - return; // Success, exit the function - } + + // Example: const response = await api.saveDraft(payload); + let response; + if (submissionId) { + // Update existing submission + response = await resubmitSurvey(submissionId, payload); + alert('Draft updated successfully'); + + } else { + // Create new submission + response = await submitSurvey(payload); + + // Update local storage with the new submission ID if this was a create operation + if (response && response.id) { + const updatedSubmission = { ...currentSubmission, id: response.id }; + localStorage.setItem('currentSubmission', JSON.stringify(updatedSubmission)); } - // If we get here, the response wasn't in the expected format - throw new Error('Unexpected response format from server'); - - } catch (apiError) { - console.error('API Error details:', { - message: apiError.message, - response: apiError.response, - stack: apiError.stack - }); - - // If we have a response with error details, use that - if (apiError.response?.data) { - const errorMessage = apiError.response.data.message || apiError.response.data.error || 'Unknown server error'; - throw new Error(`Server error: ${errorMessage}`); - } - - // Otherwise, rethrow the original error - throw apiError; + alert('Draft saved successfully') } - } catch (error) { - console.error('Error in handleSaveDraft:', { - name: error.name, - message: error.message, - stack: error.stack - }); - toast.error(error.message || 'Failed to save draft. Please try again.', { - position: "top-right", - autoClose: 5000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true - }); + } catch (error) { + console.error('Error saving draft:', error); + alert(error.message || 'Failed to save draft'); } finally { setIsSavingDraft(false); } diff --git a/ipi-survey-platform/src/pages/Overview/Overview.jsx b/ipi-survey-platform/src/pages/Overview/Overview.jsx index bb96046..2ed0084 100644 --- a/ipi-survey-platform/src/pages/Overview/Overview.jsx +++ b/ipi-survey-platform/src/pages/Overview/Overview.jsx @@ -13,7 +13,7 @@ const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg'; // const deleteIconSrc = '/assets/images/delete.svg'; const deleteIconSrc = '/assets/images/Trash - active.svg'; const trashInactiveSrc = '/assets/images/Trash - Inactive.svg'; - +import { deleteDraftSubmission } from '@/services/submissions/submissionService'; const statusStyles = { approved: 'text-[#2F663C] bg-[#F3FAF4]', submitted: 'text-[#003CFF] bg-[#E7F5FF]', @@ -51,16 +51,29 @@ const Overview = () => { setSelectedSubmission(location.state.selectedSubmission); } }, [location.state]); - const handleDeleteDraft = async (e, record) => { +const handleDeleteDraft = async (e, record) => { e.preventDefault(); e.stopPropagation(); try { - // Add your delete logic here - // Example: await deleteSubmission(record.id); - // You might want to add a confirmation dialog before deleting + if (!record?.id) { + throw new Error('No submission ID provided'); + } + + if (!window.confirm('Are you sure you want to delete this draft?')) { + return; + } + + // Call the delete API + await deleteDraftSubmission(record.id); + + // Show success message + alert('Draft deleted successfully'); + + // Navigate back or refresh the page + window.location.reload(); } catch (error) { console.error('Error deleting submission:', error); - // Optionally show an error message to the user + alert(error.message || 'Failed to delete draft'); } }; diff --git a/ipi-survey-platform/src/services/submissions/submissionService.js b/ipi-survey-platform/src/services/submissions/submissionService.js index bc884be..1009b2e 100644 --- a/ipi-survey-platform/src/services/submissions/submissionService.js +++ b/ipi-survey-platform/src/services/submissions/submissionService.js @@ -84,67 +84,6 @@ export const getQuarterPeriods = async (currentYear, currentQuarter) => { } }; -// export const getPreviousForecastData = async ( -// establishmentId, -// quarter, -// year, -// productId -// ) => { -// try { -// const response = await getRequest( -// "/submissions/getPreviousForecastData", -// { -// params: { -// establishment_id: establishmentId, -// quarter, -// year, -// product_id: productId, -// }, -// } -// ); - -// // Always return only backend data -// return response?.data || null; - -// } catch (error) { -// console.error("Error fetching previous forecast data:", error); -// return null; -// } -// }; - - -// export const getBeforePreviousData = async ( -// establishmentId, -// quarter, -// year, -// productId -// ) => { -// try { -// if (!establishmentId || !quarter || !year || !productId) { -// throw new Error("Missing required parameters"); -// } - -// const response = await getRequest( -// "/submissions/getBeforePreviousData", -// { -// params: { -// establishment_id: establishmentId, -// current_quarter: quarter, -// current_year: year, -// product_id: productId, -// }, -// } -// ); - -// return response?.data ?? null; - -// } catch (error) { -// console.error("Error fetching data:", error); -// return null; -// } -// }; - - export const getPreviousForecastData = async ( establishmentId, quarter, @@ -280,6 +219,20 @@ export const getProductSubmissionHistory = async (establishmentId, productId, co throw error; } }; + +export const deleteDraftSubmission = async (submissionId, config = {}) => { + if (!submissionId) { + throw new Error('Submission ID is required to delete draft submission'); + } + const response = await getRequest(`${endpoint}/deleteDraftSubmissionData`, { + ...config, + params: { + id: submissionId, + ...(config.params || {}) + } + }); + return response.data; +}; export default { getSubmissions, @@ -293,7 +246,8 @@ export default { getSubmissionAuditHistory, getEstablishmentProducts, getProductSubmissionHistory, - getBeforePreviousData + getBeforePreviousData, + deleteDraftSubmission }; \ No newline at end of file