From 7835cd36300cf0bfbc2884beb1e73e6bdb24b720 Mon Sep 17 00:00:00 2001 From: suryac Date: Thu, 6 Aug 2026 15:44:09 +0530 Subject: [PATCH] added graph and potentialmining --- src/components/dv/CallDetail.tsx | 7 +- src/components/dv/OrderDetail.tsx | 21 ++--- src/components/reusable/AnalyticsChart.tsx | 98 ++++++++++++---------- src/components/rv/CallsView.tsx | 2 +- src/components/rv/RecordView.tsx | 35 +++++--- 5 files changed, 90 insertions(+), 73 deletions(-) diff --git a/src/components/dv/CallDetail.tsx b/src/components/dv/CallDetail.tsx index 2931563..7d42bbb 100644 --- a/src/components/dv/CallDetail.tsx +++ b/src/components/dv/CallDetail.tsx @@ -60,6 +60,7 @@ export interface CallDetailProps { placeOrderAction?: ReactNode; refreshKey?: number; onBack?: () => void; + onDataLoad?: (data: Record) => void; } export function CallDetail({ @@ -69,6 +70,7 @@ export function CallDetail({ placeOrderAction, refreshKey, onBack, + onDataLoad, }: CallDetailProps) { const [data, setData] = useState | null>(null); const [potentialData, setPotentialData] = useState(null); @@ -84,8 +86,9 @@ export function CallDetail({ const r = await orderBookingClient.detailView(ORDER_BOOKING.detailViews.CALLS, instanceId); if (live) { setData(r.data || {}); + if (onDataLoad) onDataLoad(r.data || {}); - const storeCode = (r.data?.select_store as any)?.store_code || (r.data?.select_store as any)?.code; + const storeCode = (r.data?.select_store as any)?.store_code_2 || (r.data?.select_store as any)?.code || (r.data as any)?.store_code || (r.data as any)?.store?.store_code; if (storeCode) { orderBookingClient.request<{ potential: { potential: any[] } }>( 'POST', @@ -107,7 +110,7 @@ export function CallDetail({ return () => { live = false; }; - }, [instanceId, refreshKey]); + }, [instanceId, refreshKey, onDataLoad]); if (error) { return ( diff --git a/src/components/dv/OrderDetail.tsx b/src/components/dv/OrderDetail.tsx index 5f75672..a54791e 100644 --- a/src/components/dv/OrderDetail.tsx +++ b/src/components/dv/OrderDetail.tsx @@ -41,7 +41,7 @@ export function OrderDetail({ instanceId }: WiredDetailViewProps) { ); } - + if (loading) { return ( @@ -49,10 +49,10 @@ export function OrderDetail({ instanceId }: WiredDetailViewProps) { ); } - + if (!data || Object.keys(data).length === 0) { return ( - + ); @@ -76,9 +76,9 @@ export function OrderDetail({ instanceId }: WiredDetailViewProps) { const orderId = extract('order_id', remainingData) || '-'; let dateOfOrder = extract('date_of_order_3', remainingData); if (dateOfOrder) { - dateOfOrder = new Date(dateOfOrder as string).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); + dateOfOrder = new Date(dateOfOrder as string).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); } else { - dateOfOrder = '-'; + dateOfOrder = '-'; } // SO Info @@ -92,7 +92,7 @@ export function OrderDetail({ instanceId }: WiredDetailViewProps) { soEmail = (soRaw as any).email || '-'; soId = (soRaw as any).user_id || (soRaw as any).id || (soRaw as any).uid || '-'; } - const soInitials = soName.length > 2 ? soName.substring(0,2).toUpperCase() : 'SO'; + const soInitials = soName.length > 2 ? soName.substring(0, 2).toUpperCase() : 'SO'; // Store Info const storeRaw = extract('select_store', remainingData); @@ -110,20 +110,13 @@ export function OrderDetail({ instanceId }: WiredDetailViewProps) { // Line Items const orderDetailsGrid = extract('order_details_3', remainingData); const itemsArray = Array.isArray(orderDetailsGrid) ? orderDetailsGrid : []; - + // Totals const totalBags = extract('total_bags_3', remainingData) || 0; const totalKgs = extract('total_kgs_3', remainingData) || 0; return (
- {/* Header */} -
-
-

Order Detail

-

#{orderId}

-
-
{/* Status + Date ribbon */}
diff --git a/src/components/reusable/AnalyticsChart.tsx b/src/components/reusable/AnalyticsChart.tsx index aac3ca0..8e0f734 100644 --- a/src/components/reusable/AnalyticsChart.tsx +++ b/src/components/reusable/AnalyticsChart.tsx @@ -47,7 +47,7 @@ export function AnalyticsChart({ data, gridCols }: AnalyticsChartProps) { : "grid grid-cols-1 lg:grid-cols-3 gap-6 w-full"; return ( -
+
{charts.map((chart, idx) => { const title = (chart.key || `Chart ${idx + 1}`) .replace(/_/g, ' ') @@ -93,10 +93,20 @@ export function AnalyticsChart({ data, gridCols }: AnalyticsChartProps) { chartType = 4; // Donut } else if (lowerKey.includes('brand') || lowerKey.includes('product')) { chartType = 5; // Table - } else if (lowerKey.includes('monthly')) { + } else if (lowerKey.includes('monthly') || lowerKey.includes('yearly')) { chartType = 0; // Bar } + // Determine if it should span full width + const isFullWidth = (gridCols === 1) || (!gridCols && charts.length <= 2) || hasSeries || lowerKey.includes('monthly') || lowerKey.includes('yearly') || finalData.length > 8; + + const fullSpanClass = gridCols === 2 ? 'lg:col-span-2' : 'lg:col-span-3'; + + // Calculate a dynamic width if there's a lot of data to allow horizontal scrolling + const minChartWidth = chartType === 0 || chartType === 1 || chartType === 2 + ? Math.max(100, finalData.length * (hasSeries ? seriesKeys.length * 15 + 40 : 60)) + : 100; + const renderChartContent = () => { return ( <> @@ -177,8 +187,8 @@ export function AnalyticsChart({ data, gridCols }: AnalyticsChartProps) { }; return ( - -
+ +
100 ? 'overflow-x-auto scrollbar-slim' : ''}`}> {chartType === 5 ? (
@@ -203,45 +213,47 @@ export function AnalyticsChart({ data, gridCols }: AnalyticsChartProps) {
) : ( - - {chartType === 3 || chartType === 4 ? ( - - - - - {finalData.map((_, index) => ( - - ))} - - - ) : chartType === 1 ? ( - - {renderChartContent()} - - ) : chartType === 2 ? ( - - {renderChartContent()} - - ) : ( - - {renderChartContent()} - - )} - +
100 ? `${minChartWidth}px` : '100%', height: '100%' }}> + + {chartType === 3 || chartType === 4 ? ( + + + + + {finalData.map((_, index) => ( + + ))} + + + ) : chartType === 1 ? ( + + {renderChartContent()} + + ) : chartType === 2 ? ( + + {renderChartContent()} + + ) : ( + + {renderChartContent()} + + )} + +
)}
diff --git a/src/components/rv/CallsView.tsx b/src/components/rv/CallsView.tsx index 93c7267..43cea34 100644 --- a/src/components/rv/CallsView.tsx +++ b/src/components/rv/CallsView.tsx @@ -15,7 +15,7 @@ export function CallsView({ onRowClick, pageSize, headerActions, rowActions, ref headerActions={headerActions} rowActions={rowActions} refreshKey={refreshKey} - sortBy="instance_id" + sortBy="visit_date" sortDir="desc" omitColumns={['instance_id']} initialFilters={initialFilters} diff --git a/src/components/rv/RecordView.tsx b/src/components/rv/RecordView.tsx index 8329d56..fc12c40 100644 --- a/src/components/rv/RecordView.tsx +++ b/src/components/rv/RecordView.tsx @@ -98,21 +98,21 @@ export function RecordView({ setPage(1); }; + const initialFiltersStr = JSON.stringify(initialFilters || {}); const initialFiltersNormalized = useMemo(() => { const res: Record = {}; - if (initialFilters) { - Object.entries(initialFilters).forEach(([k, v]) => { - if (Array.isArray(v)) { - res[k] = v; - } else if (v) { - res[k] = [v]; - } - }); - } + const parsed = JSON.parse(initialFiltersStr); + Object.entries(parsed).forEach(([k, v]) => { + if (Array.isArray(v)) { + res[k] = v as string[]; + } else if (v) { + res[k] = [v as string]; + } + }); return res; - }, [initialFilters]); + }, [initialFiltersStr]); - const [activeFilters, setActiveFilters] = useState>(initialFiltersNormalized); + const [activeFilters, setActiveFilters] = useState>({}); const [resp, setResp] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -134,14 +134,23 @@ export function RecordView({ const filtersParam = useMemo(() => { const parsed = JSON.parse(activeFiltersStr) as Record; - return Object.entries(parsed) + + // Merge user active filters on top of initial prefilters + const merged = { ...initialFiltersNormalized }; + Object.entries(parsed).forEach(([k, v]) => { + if (v && v.length > 0) { + merged[k] = v; + } + }); + + return Object.entries(merged) .filter(([_, vals]) => vals && vals.length > 0) .map(([key, vals]) => ({ field_key: key, values: vals, data_type: 'character varying', })); - }, [activeFiltersStr]); + }, [activeFiltersStr, initialFiltersNormalized]); useEffect(() => { let live = true;