diff --git a/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx b/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx index 4ed0e43..7af4932 100644 --- a/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx +++ b/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx @@ -1,108 +1,28 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Link, useNavigate, useParams, useLocation } from 'react-router-dom'; import AdminHeader from '@/components/admin/AdminHeader'; import { getSubmissionById } from '@/services/admin/submission'; -import { getProductSubmissionHistory } from '@/services/submissions/submissionService'; import apiClient from '@/services/api/apiClient'; +import { getBeforePreviousData, getQuarterPeriods } from '@/services/submissions/submissionService'; +import { getProductSubmissionHistory } from '@/services/submissions/submissionService'; import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend } from 'chart.js'; -import { Line, Bar } from 'react-chartjs-2'; +import { Line } from 'react-chartjs-2'; // Register ChartJS components ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend); -// Static Quarterly Data Component -const StaticQuarterlyChart = () => { - const staticChartData = { - labels: ['Q1 2023', 'Q2 2023', 'Q3 2023', 'Q4 2023', 'Q1 2024', 'Q2 2024', 'Q3 2024', 'Q4 2024', 'Q1 2025', 'Q2 2025', 'Q3 2025', 'Q4 2025'], - datasets: [ - { - label: 'Details', - data: [1200, 1300, 1250, 1400, 1350, 1450, 1500, 1550, 1600, 1650, 1700, 1750], - backgroundColor: 'rgba(75, 192, 192, 0.6)', - borderColor: 'rgba(75, 192, 192, 1)', - borderWidth: 1 - }, - { - label: 'Capacity', - data: [1500, 1500, 1500, 1500, 1600, 1600, 1600, 1600, 1700, 1700, 1700, 1700], - backgroundColor: 'rgba(54, 162, 235, 0.6)', - borderColor: 'rgba(54, 162, 235, 1)', - borderWidth: 1 - }, - { - label: 'Difference', - data: [300, 200, 250, 100, 250, 150, 100, 50, 100, 50, 0, -50], - backgroundColor: 'rgba(255, 99, 132, 0.6)', - borderColor: 'rgba(255, 99, 132, 1)', - borderWidth: 1 - } - ] +// Helper function to get months for quarter +const getMonthsForQuarter = (quarter, year) => { + const monthMap = { + 'Q1': ['Jan', 'Feb', 'Mar'], + 'Q2': ['Apr', 'May', 'Jun'], + 'Q3': ['Jul', 'Aug', 'Sep'], + 'Q4': ['Oct', 'Nov', 'Dec'] }; - - const options = { - responsive: true, - maintainAspectRatio: false, - scales: { - y: { - beginAtZero: true, - title: { - display: true, - text: 'Quantity', - font: { - weight: 'bold' - } - } - } - }, - plugins: { - legend: { - position: 'top', - }, - tooltip: { - callbacks: { - label: function(context) { - return `${context.dataset.label}: ${context.parsed.y.toLocaleString()}`; - } - } - } - } - }; - - return ( -
| - Metric - | -- {quarterPeriods?.previous_quarter}-{quarterPeriods?.previous_year}{' '} - (Previous Quarter) - | -- {quarterPeriods?.current_quarter}-{quarterPeriods?.current_year}{' '} - (Current Quarter) - | -- {quarterPeriods?.forecast_quarter}-{quarterPeriods?.forecast_year}{' '} - (Next Quarter) - | -||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| + Metric + | + + {showPreviousNext ? ( + <> + {/* 12 columns when showPreviousNext is true */} ++ {previousLabel || 'Q1 2024'} (PREVIOUS QUARTER) + | ++ {currentLabel || 'Q2 2024'} (CURRENT QUARTER) + | ++ {additionalForecastLabel || 'Q3 2023'} (PREVIOUS FORECAST) + | ++ {forecastLabel || 'Q3 2024'} (NEXT YEAR FORECAST) + | + > + ) : ( + <> + {/* 9 columns when showPreviousNext is false */} ++ {previousLabel || 'Q1 2024'} (PREVIOUS QUARTER) + | ++ {currentLabel || 'Q2 2024'} (CURRENT QUARTER) + | ++ {forecastLabel || 'Q3 2024'} (NEXT YEAR FORECAST) + | + > + )} +||||||||||||||||||||||||
| - {quarterPeriods?.previous_month?.previous_period_one} - | -- {quarterPeriods?.previous_month?.previous_period_two} - | -- {quarterPeriods?.previous_month?.previous_period_three} - | +|||||||||||||||||||||||||||||
| + {previousMonths?.previous_period_one || 'Jan'} + | ++ {previousMonths?.previous_period_two || 'Feb'} + | ++ {previousMonths?.previous_period_three || 'Mar'} + | -- {quarterPeriods?.current_month?.current_period_one} - | -- {quarterPeriods?.current_month?.current_period_two} - | -- {quarterPeriods?.current_month?.current_period_three} - | + {/* Current Quarter Months */} ++ {currentMonths?.current_period_one || 'Apr'} + | ++ {currentMonths?.current_period_two || 'May'} + | ++ {currentMonths?.current_period_three || 'Jun'} + | -- {quarterPeriods?.forecast_month?.forecast_period_one} - | -- {quarterPeriods?.forecast_month?.forecast_period_two} - | -- {quarterPeriods?.forecast_month?.forecast_period_three} - | -+ {additionalForecastMonths?.[0] || 'Jul'} + | ++ {additionalForecastMonths?.[1] || 'Aug'} + | ++ {additionalForecastMonths?.[2] || 'Sep'} + | + + {/* Next Year Forecast Months */} ++ {forecastMonths?.forecast_period_one || 'Oct'} + | ++ {forecastMonths?.forecast_period_two || 'Nov'} + | ++ {forecastMonths?.forecast_period_three || 'Dec'} + | + > + ) : ( + <> + {/* Previous Quarter Months */} ++ {previousMonths?.previous_period_one || 'Jan'} + | ++ {previousMonths?.previous_period_two || 'Feb'} + | ++ {previousMonths?.previous_period_three || 'Mar'} + | + + {/* Current Quarter Months */} ++ {currentMonths?.current_period_one || 'Apr'} + | ++ {currentMonths?.current_period_two || 'May'} + | ++ {currentMonths?.current_period_three || 'Jun'} + | + + {/* Next Year Forecast Months */} ++ {forecastMonths?.forecast_period_one || 'Jul'} + | ++ {forecastMonths?.forecast_period_two || 'Aug'} + | ++ {forecastMonths?.forecast_period_three || 'Sep'} + | + > + )} + + - {/* Quantity Row */}|||||
| + | Quantity ({product?.unit?.uom || 'units'}) | -{product.previous_quantity_period_one || '0'} | -{product.previous_quantity_period_two || '0'} | -{product.previous_quantity_period_three || '0'} | + + {showPreviousNext ? ( + <> + {/* Previous Quarter Data */} +
+
+ {product.previous_quantity_period_one || '0'}
+
+ |
+
+
+ {product.previous_quantity_period_two || '0'}
+ {getVarianceDisplay(product.previous_quantity_period_one, product.previous_quantity_period_two, true)}
+
+ |
+
+
+ {product.previous_quantity_period_three || '0'}
+ {getVarianceDisplay(product.previous_quantity_period_two, product.previous_quantity_period_three)}
+
+ |
- {product.current_quantity_period_one || '0'} | -{product.current_quantity_period_two || '0'} | -{product.current_quantity_period_three || '0'} | + {/* Current Quarter Data */} +
+
+ {product.current_quantity_period_one || '0'}
+ {getVarianceDisplay(product.previous_quantity_period_three, product.current_quantity_period_one)}
+
+ |
+
+
+ {product.current_quantity_period_two || '0'}
+ {getVarianceDisplay(product.current_quantity_period_one, product.current_quantity_period_two)}
+
+ |
+
+
+ {product.current_quantity_period_three || '0'}
+ {getVarianceDisplay(product.current_quantity_period_two, product.current_quantity_period_three)}
+
+ |
- {product.forecast_quantity_period_one || '0'} | -{product.forecast_quantity_period_two || '0'} | -{product.forecast_quantity_period_three || '0'} | + {/* HISTORICAL Data (from API) */} + {(() => { + const historicalData = getCurrentYearForecastData(product?.product?.id); + return ( + <> +
+
+ {historicalData.forecast_quantity_period_one || '0'}
+ {getVarianceDisplay(product.current_quantity_period_three, historicalData.forecast_quantity_period_one)}
+
+ |
+
+
+ {historicalData.forecast_quantity_period_two || '0'}
+ {getVarianceDisplay(historicalData.forecast_quantity_period_one, historicalData.forecast_quantity_period_two)}
+
+ |
+
+
+ {historicalData.forecast_quantity_period_three || '0'}
+ {getVarianceDisplay(historicalData.forecast_quantity_period_two, historicalData.forecast_quantity_period_three)}
+
+ |
+ >
+ );
+ })()}
+
+ {/* NEXT YEAR FORECAST Data (original from submission) */}
+
+
+ {product.forecast_quantity_period_one || '0'}
+ {getVarianceDisplay(product.current_quantity_period_three, product.forecast_quantity_period_one)}
+
+ |
+
+
+ {product.forecast_quantity_period_two || '0'}
+ {getVarianceDisplay(product.forecast_quantity_period_one, product.forecast_quantity_period_two)}
+
+ |
+
+
+ {product.forecast_quantity_period_three || '0'}
+ {getVarianceDisplay(product.forecast_quantity_period_two, product.forecast_quantity_period_three)}
+
+ |
+ >
+ ) : (
+ <>
+
+
+ {product.previous_quantity_period_one || '0'}
+
+ |
+
+
+ {product.previous_quantity_period_two || '0'}
+ {getVarianceDisplay(product.previous_quantity_period_one, product.previous_quantity_period_two, true)}
+
+ |
+
+
+ {product.previous_quantity_period_three || '0'}
+ {getVarianceDisplay(product.previous_quantity_period_two, product.previous_quantity_period_three)}
+
+ |
+
+
+
+ {product.current_quantity_period_one || '0'}
+ {getVarianceDisplay(product.previous_quantity_period_three, product.current_quantity_period_one)}
+
+ |
+
+
+ {product.current_quantity_period_two || '0'}
+ {getVarianceDisplay(product.current_quantity_period_one, product.current_quantity_period_two)}
+
+ |
+
+
+ {product.current_quantity_period_three || '0'}
+ {getVarianceDisplay(product.current_quantity_period_two, product.current_quantity_period_three)}
+
+ |
+
+
+
+ {product.forecast_quantity_period_one || '0'}
+ {getVarianceDisplay(product.current_quantity_period_three, product.forecast_quantity_period_one)}
+
+ |
+
+
+ {product.forecast_quantity_period_two || '0'}
+ {getVarianceDisplay(product.forecast_quantity_period_one, product.forecast_quantity_period_two)}
+
+ |
+
+
+ {product.forecast_quantity_period_three || '0'}
+ {getVarianceDisplay(product.forecast_quantity_period_two, product.forecast_quantity_period_three)}
+
+ |
+ >
+ )}
| + | Cost (AED) | -{product.previous_cost_period_one || '0'} | -{product.previous_cost_period_two || '0'} | -{product.previous_cost_period_three || '0'} | + + {showPreviousNext ? ( + <> + {/* Previous Quarter Cost */} +
+
+ {product.previous_cost_period_one || '0'}
+
+ |
+
+
+ {product.previous_cost_period_two || '0'}
+ {getVarianceDisplay(product.previous_cost_period_one, product.previous_cost_period_two, true)}
+
+ |
+
+
+ {product.previous_cost_period_three || '0'}
+ {getVarianceDisplay(product.previous_cost_period_two, product.previous_cost_period_three)}
+
+ |
- {product.current_cost_period_one || '0'} | -{product.current_cost_period_two || '0'} | -{product.current_cost_period_three || '0'} | + {/* Current Quarter Cost */} +
+
+ {product.current_cost_period_one || '0'}
+ {getVarianceDisplay(product.previous_cost_period_three, product.current_cost_period_one)}
+
+ |
+
+
+ {product.current_cost_period_two || '0'}
+ {getVarianceDisplay(product.current_cost_period_one, product.current_cost_period_two)}
+
+ |
+
+
+ {product.current_cost_period_three || '0'}
+ {getVarianceDisplay(product.current_cost_period_two, product.current_cost_period_three)}
+
+ |
- {product.forecast_cost_period_one || '0'} | -{product.forecast_cost_period_two || '0'} | -{product.forecast_cost_period_three || '0'} | + {/* HISTORICAL Cost (from API) */} + {(() => { + const historicalData = getCurrentYearForecastData(product?.product?.id); + return ( + <> +
+
+ {historicalData.forecast_cost_period_one || '0'}
+ {getVarianceDisplay(product.current_cost_period_three, historicalData.forecast_cost_period_one)}
+
+ |
+
+
+ {historicalData.forecast_cost_period_two || '0'}
+ {getVarianceDisplay(historicalData.forecast_cost_period_one, historicalData.forecast_cost_period_two)}
+
+ |
+
+
+ {historicalData.forecast_cost_period_three || '0'}
+ {getVarianceDisplay(historicalData.forecast_cost_period_two, historicalData.forecast_cost_period_three)}
+
+ |
+ >
+ );
+ })()}
+
+ {/* NEXT YEAR FORECAST Cost (original from submission) */}
+
+
+ {product.forecast_cost_period_one || '0'}
+ {getVarianceDisplay(product.current_cost_period_three, product.forecast_cost_period_one)}
+
+ |
+
+
+ {product.forecast_cost_period_two || '0'}
+ {getVarianceDisplay(product.forecast_cost_period_one, product.forecast_cost_period_two)}
+
+ |
+
+
+ {product.forecast_cost_period_three || '0'}
+ {getVarianceDisplay(product.forecast_cost_period_two, product.forecast_cost_period_three)}
+
+ |
+ >
+ ) : (
+ <>
+
+
+ {product.previous_cost_period_one || '0'}
+
+ |
+
+
+ {product.previous_cost_period_two || '0'}
+ {getVarianceDisplay(product.previous_cost_period_one, product.previous_cost_period_two, true)}
+
+ |
+
+
+ {product.previous_cost_period_three || '0'}
+ {getVarianceDisplay(product.previous_cost_period_two, product.previous_cost_period_three)}
+
+ |
+
+
+
+ {product.current_cost_period_one || '0'}
+ {getVarianceDisplay(product.previous_cost_period_three, product.current_cost_period_one)}
+
+ |
+
+
+ {product.current_cost_period_two || '0'}
+ {getVarianceDisplay(product.current_cost_period_one, product.current_cost_period_two)}
+
+ |
+
+
+ {product.current_cost_period_three || '0'}
+ {getVarianceDisplay(product.current_cost_period_two, product.current_cost_period_three)}
+
+ |
+
+
+
+ {product.forecast_cost_period_one || '0'}
+ {getVarianceDisplay(product.current_cost_period_three, product.forecast_cost_period_one)}
+
+ |
+
+
+ {product.forecast_cost_period_two || '0'}
+ {getVarianceDisplay(product.forecast_cost_period_one, product.forecast_cost_period_two)}
+
+ |
+
+
+ {product.forecast_cost_period_three || '0'}
+ {getVarianceDisplay(product.forecast_cost_period_two, product.forecast_cost_period_three)}
+
+ |
+ >
+ )}
| + Reason (Current) + | + {showPreviousNext ? ( + <> ++ – + | ++ {product.other_variation_reason || + (product?.variation_reason?.reason ? + (product.variation_reason.reason.startsWith('Other (specify)') ? '' : product.variation_reason.reason) + : 'No reason provided') + } + | + {/* Previous Forecast (colSpan 3) */} ++ – + | + {/* Next Year Forecast (colSpan 3) */} ++ – + | + > + ) : ( + <> + {/* Previous Quarter (colSpan 3) */} ++ – + | + {/* Current Quarter (colSpan 3) - இங்குதான் Reason (Current) இருக்க வேண்டும் */} ++ {product.other_variation_reason || + (product?.variation_reason?.reason ? + (product.variation_reason.reason.startsWith('Other (specify)') ? '' : product.variation_reason.reason) + : 'No reason provided') + } + | + {/* Next Year Forecast (colSpan 3) */} ++ – + | + > + )} +||||||||||||||||||||||||
| - Reason (Current) - | -- -- - | -- {product.other_variation_reason || - (product?.variation_reason?.reason ? - (product.variation_reason.reason.startsWith('Other (specify)') ? '' : product.variation_reason.reason) - : 'No reason provided') -} - | -- -- - | -||||||||||||||||||||||||||||
| + | Reason (Forecast) | -- -- - | -- -- - | -- {product.other_zero_target_reason || - (product?.zero_target_reason?.reason ? - (product.zero_target_reason.reason.startsWith('Other (specify)') ? '' : product.zero_target_reason.reason) - : 'No reason provided') - } - | + {showPreviousNext ? ( + <> ++ – + | ++ – + | ++ – + | ++ {product.other_zero_target_reason || + (product?.zero_target_reason?.reason ? + (product.zero_target_reason.reason.startsWith('Other (specify)') ? '' : product.zero_target_reason.reason) + : 'No reason provided') + } + | + > + ) : ( + <> ++ – + | ++ – + | ++ {product.other_zero_target_reason || + (product?.zero_target_reason?.reason ? + (product.zero_target_reason.reason.startsWith('Other (specify)') ? '' : product.zero_target_reason.reason) + : 'No reason provided') + } + | + > + )}||||||||||||||||||||
- You're about to approve {submissionData?.establishment?.factory_name|| 'this establishment'} for {submissionData?.quarter} {submissionData?.year}.
-
- This will lock the record for the establishment.
-
+ You're about to approve {submissionData?.establishment?.factory_name|| 'this establishment'} for {submissionData?.quarter} {submissionData?.year}.
+
+ This will lock the record for the establishment.
+
+ Monthly manufacturing indices are generated automatically on the 11th of each month using the finalized Laspeyres item indices. + Use this view to monitor trends and drill down into ISIC groups. +
++ Formula: Manufacturing index = Σ (sector weightᵢ × group indexᵢ) +
++ Filter by year and quickly jump to a month to see its ISIC breakdown. +
+ +Click a row to open its ISIC breakdown on the right.
+| REFERENCE MONTH | +MANUFACTURING INDEX | +MOM CHANGE | +YOY CHANGE | +GENERATED ON | +STATUS | +ACTIONS | +
|---|---|---|---|---|---|---|
|
+
+ {row.month}
+ {selectedMonth === row.month && (
+
+ Selected
+
+ )}
+
+ |
+ {row.index} (2022=100) | ++ + {row.mom}% + + | ++ + {row.yoy}% + + | +{row.generated} | ++ + {row.status} + + | +
+ |
+
+ Start from the manufacturing total, then drill down into ISIC 2-digit and 3 & 4-digit groups for the selected month. +
+ +MoM: +0.9%
+YoY: +3.2%
++ The manufacturing index increased by 0.9% compared to the previous month and 3.2% compared to the same month last year. +
+Food products (ISIC 10-12)
++0.24
+Chemicals (ISIC 20-21)
++0.18
+Basic metals (ISIC 24)
+-0.12
+