diff --git a/src/api/client.ts b/src/api/client.ts index 3f28527..c0b9f7f 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -47,8 +47,8 @@ export class ZinoClient { return this.token; } - private async request(method: string, path: string, body?: unknown): Promise { - const headers: Record = { 'Content-Type': 'application/json' }; + async request(method: string, path: string, body?: unknown, customHeaders?: Record): Promise { + const headers: Record = { 'Content-Type': 'application/json', ...customHeaders }; if (this.token) headers['Authorization'] = `Bearer ${this.token}`; return this.send(method, path, { diff --git a/src/components/cards/CallCard.tsx b/src/components/cards/CallCard.tsx index e275163..bc3c326 100644 --- a/src/components/cards/CallCard.tsx +++ b/src/components/cards/CallCard.tsx @@ -2,33 +2,33 @@ import { formatValue } from '../../lib/format'; export function CallCard({ row }: { row: Record }) { const instanceId = row.instance_id || '—'; - + // Status const stateName = String(row.status || row.current_state_name || 'Pending'); const isProductive = stateName.toLowerCase().includes('productive') || stateName.toLowerCase().includes('completed') || stateName.toLowerCase().includes('success'); - + // Store Details const storeName = formatValue(row.store || row.store_name || row.customer_name || 'Unknown Store'); const storeCode = formatValue(row.store_code || '—'); - + // Grid Details const totalWeight = formatValue(row.total_kgs || row.total_weight || row.weight || 0); const totalQuantity = formatValue(row.total_bags || row.total_quantity || row.quantity || 0); const totalOrders = formatValue(row.order_count || row.total_orders || 0); - + // Route & Assignment const routeName = formatValue(row.route_name || row.route || '—'); const areaName = formatValue(row.area || row.area_name || '—'); - + // User const userName = formatValue(row.sales_officer || row.user_name || '—'); const userEmail = formatValue(row.performed_by_email || row.user_email || '—'); const initials = userName !== '—' ? String(userName).substring(0, 2).toUpperCase() : 'SO'; - + // Date & Time let dateStr = '—'; let timeStr = '—'; - + if (row.visit_date) { try { const d = new Date(row.visit_date as string); @@ -65,9 +65,6 @@ export function CallCard({ row }: { row: Record }) { {stateName} - - ID: {instanceId} - {/* Main Content */} diff --git a/src/components/forms/DynamicForm.tsx b/src/components/forms/DynamicForm.tsx index 04b4d06..d2c2474 100644 --- a/src/components/forms/DynamicForm.tsx +++ b/src/components/forms/DynamicForm.tsx @@ -26,9 +26,10 @@ export interface DynamicFormProps { onSuccess?: () => void; onCancel?: () => void; ignorePrefill?: boolean; + customPrefillData?: Record; } -export function DynamicForm({ client, activityId: initialActivityId, instanceId: initialInstanceId, onSuccess, onCancel, ignorePrefill }: DynamicFormProps) { +export function DynamicForm({ client, activityId: initialActivityId, instanceId: initialInstanceId, onSuccess, onCancel, ignorePrefill, customPrefillData }: DynamicFormProps) { const [currentActivityId, setCurrentActivityId] = useState(initialActivityId); const [currentInstanceId, setCurrentInstanceId] = useState(initialInstanceId); const [chainQueue, setChainQueue] = useState>([]); @@ -84,6 +85,12 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId: }); } } + + if (customPrefillData) { + Object.entries(customPrefillData).forEach(([k, v]) => { + if (!imageFieldIds.has(k)) defaultValues[k] = v; + }); + } setValues(defaultValues); setLoading(false); diff --git a/src/components/forms/fields/SmartGridField.tsx b/src/components/forms/fields/SmartGridField.tsx index 21897af..dd9b71b 100644 --- a/src/components/forms/fields/SmartGridField.tsx +++ b/src/components/forms/fields/SmartGridField.tsx @@ -23,7 +23,8 @@ export function SmartGridField({ const visibleColumns = columns.filter(c => { const normalized = c.id.toLowerCase().replace(/[^a-z]/g, ''); - return ['productcategory', 'productname', 'bags'].includes(normalized); + // Use a blacklist so we don't accidentally hide important columns from other grids + return !['sku', 'rowkgs', 'brcode'].includes(normalized); }); const removeRow = (idx: number) => { @@ -118,11 +119,27 @@ export function SmartGridField({ {(() => { const val = row[col.id]; + let displayVal = String(val ?? '-'); + if (col.data_type === 'select' || col.data_type === 'multiselect') { const opt = col.properties?.options?.find(o => String(o.value) === String(val)); - return opt ? opt.label : String(val ?? '-'); + if (opt) displayVal = opt.label; } - return String(val ?? '-'); + + if ((col.id.toLowerCase().includes('difference') || col.name?.toLowerCase().includes('difference')) && val != null && val !== '') { + const numVal = Number(val); + if (!isNaN(numVal)) { + if (numVal < 0) { + displayVal = `${Math.abs(numVal)} kgs less`; + } else if (numVal > 0) { + displayVal = `${numVal} kgs more`; + } else { + displayVal = `0 kgs`; + } + } + } + + return displayVal; })()} ))} diff --git a/src/screens/CallsPage.tsx b/src/screens/CallsPage.tsx index 620ee1d..374d561 100644 --- a/src/screens/CallsPage.tsx +++ b/src/screens/CallsPage.tsx @@ -17,12 +17,61 @@ export function CallsPage() { const [refreshKey, setRefreshKey] = useState(0); const [activeActivity, setActiveActivity] = useState<{ id: string; name: string } | null>(null); const [isFabOpen, setIsFabOpen] = useState(false); + const [miningLoading, setMiningLoading] = useState(false); + const [miningPrefill, setMiningPrefill] = useState | undefined>(); + const [selectedRow, setSelectedRow] = useState | null>(null); + + const handlePotentialMiningClick = async () => { + setMiningLoading(true); + setMiningPrefill(undefined); + try { + const storeCode = selectedRow?.store_code || selectedRow?.code || selectedRow?.store?.store_code; + + if (!storeCode) { + console.warn("Store code not found on selected row, proceeding anyway."); + } + + const payload = { + store_code: storeCode, + instance_id: String(instanceId) + }; + + const response = await orderBookingClient.request<{ potential: { potential: any[] } }>( + 'POST', + '/api/papi2/potential-mining', + payload, + { 'TemplateID': '146' } + ); + + const rawPotential = response.potential?.potential || []; + const mappedPotential = rawPotential.map((row: any) => { + const cat = row.product_category || row.product_category_ || row.category; + return { + ...row, + product_category_: cat, + product_category: cat, + productcategory: cat, + category: cat, + product_category_1: cat + }; + }); + + setMiningPrefill({ potential: mappedPotential }); + setActiveActivity({ id: ORDER_BOOKING.activities.POTENTIAL_MINING.uid, name: 'Potential Mining' }); + } catch (e: any) { + alert("Failed to fetch potential mining data: " + (e.message || "Unknown error")); + } finally { + setMiningLoading(false); + setIsFabOpen(false); + } + }; return ( <> { + setSelectedRow(row); const id = row.instance_id as number | string | undefined; if (id != null) navigate(`/calls/${id}`); }} @@ -62,8 +111,8 @@ export function CallsPage() {
{isFabOpen && (
-