diff --git a/src/api/client.ts b/src/api/client.ts index 3f1f9fa..8323094 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -127,7 +127,6 @@ export class ZinoClient { try { const p = JSON.parse(atob(this.token.split('.')[1])); - console.log('--- JWT PAYLOAD ---', p); return { id: String(p.user_id ?? p.sub ?? ''), org_id: String(p.org_id ?? ''), diff --git a/src/api/config.ts b/src/api/config.ts index ff193ea..3904e11 100644 --- a/src/api/config.ts +++ b/src/api/config.ts @@ -65,7 +65,7 @@ export const ORDER_BOOKING = { recordViews: { ORDERS: '1e424561-9a27-44f5-9b68-64d63296d837', CALLS: 'b4d7a710-24e7-416d-885a-31fd1e727aab', - ANALYTICS: '56b21b46-6d2c-4e10-b5a3-c63d058d0afa' + ANALYTICS: 'b4d7a710-24e7-416d-885a-31fd1e727aab' }, detailViews: { ORDERS: '0804c6c3-6cf9-4050-94bb-fa48dd5de87d', diff --git a/src/components/forms/fields/SmartGridField.tsx b/src/components/forms/fields/SmartGridField.tsx index 307663e..56ec727 100644 --- a/src/components/forms/fields/SmartGridField.tsx +++ b/src/components/forms/fields/SmartGridField.tsx @@ -159,61 +159,49 @@ export function SmartGridField({ {value.length === 0 ? ( No rows added. ) : ( -
- - - - {visibleColumns.map(col => ( - - ))} - - - - - {value.map((row, i) => ( - - {visibleColumns.map(col => ( - - ))} - - - ))} - -
- {col.name} -
- {(() => { - const val = row[col.id]; - let displayVal = String(val ?? '-'); +
+ {value.map((row, i) => { + let productName = 'Unknown Product'; + let bags = '0'; - if (col.data_type === 'select' || col.data_type === 'multiselect') { - const opt = col.properties?.options?.find(o => String(o.value) === String(val)); - if (opt) displayVal = opt.label; - } + visibleColumns.forEach(col => { + const isName = col.id.toLowerCase().includes('name') || col.name.toLowerCase().includes('name') || (col.id.toLowerCase().includes('category') && productName === 'Unknown Product'); + const isBags = col.id.toLowerCase().includes('bags') || col.name.toLowerCase().includes('bags') || col.id.toLowerCase().includes('quantity'); + + if (isName || isBags) { + const val = row[col.id]; + let displayVal = 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`; - } - } - } + if (col.data_type === 'select' || col.data_type === 'multiselect') { + const opt = col.properties?.options?.find(o => String(o.value) === String(val)); + if (opt) displayVal = opt.label; + } - return displayVal; - })()} -
- - -
+ if (isName && (productName === 'Unknown Product' || col.id.toLowerCase().includes('name'))) { + productName = displayVal; + } + if (isBags) bags = displayVal; + } + }); + + return ( +
+
+ {productName} + {bags} Bags +
+ +
+ + +
+
+ ); + })}
)} diff --git a/src/components/reusable/StatsTile.tsx b/src/components/reusable/StatsTile.tsx index 9e09a28..a80e6ed 100644 --- a/src/components/reusable/StatsTile.tsx +++ b/src/components/reusable/StatsTile.tsx @@ -27,7 +27,7 @@ export function StatsTile({ tile, idx = 0 }: StatsTileProps) { const isDanger = lowerKey.includes('no_order'); return ( -
+
{displayLabel} diff --git a/src/components/reusable/reusable.css b/src/components/reusable/reusable.css index 97184a0..f12c5e2 100644 --- a/src/components/reusable/reusable.css +++ b/src/components/reusable/reusable.css @@ -12,27 +12,24 @@ display: none; } -/* Horizontal Scroll Container */ +/* Vertical Layout Container */ .z-stats-container { display: flex; - overflow-x: auto; + flex-direction: column; gap: 12px; padding-bottom: 8px; - /* For box-shadow clipping */ - scroll-snap-type: x mandatory; } /* Base Tile */ .z-stats-tile { flex: 0 0 auto; - width: 160px; + width: 100%; height: 100px; border-radius: var(--z-border-radius-lg); padding: 16px; display: flex; flex-direction: column; justify-content: space-between; - scroll-snap-align: start; transition: transform 0.2s ease; box-shadow: var(--block-shadow); font-family: var(--font-sans); @@ -42,6 +39,7 @@ .z-stats-tile--secondary { background-color: var(--z-bg-neutral-100); border: 1px solid var(--z-border-neutral-300); + border-left: 4px solid var(--z-text-primary-400); color: var(--z-text-neutral-900); } @@ -93,6 +91,10 @@ color: var(--z-text-danger-400); } +.z-stats-tile--secondary.z-stats-tile--danger { + border-left-color: var(--z-text-danger-400); +} + .z-stats-footer { margin-top: auto; } diff --git a/src/screens/AnalyticsPage.tsx b/src/screens/AnalyticsPage.tsx index f4009ca..77b22fc 100644 --- a/src/screens/AnalyticsPage.tsx +++ b/src/screens/AnalyticsPage.tsx @@ -3,6 +3,7 @@ import { orderBookingClient } from '../api/clients'; import { ORDER_BOOKING } from '../api/config'; import { Spinner } from '../components/reusable/Spinner'; import { EmptyState } from '../components/reusable/EmptyState'; +import { StatsTiles } from '../components/reusable/StatsTiles'; import { Activity, Package, ShoppingBag, BarChart3, TrendingUp, Phone } from 'lucide-react'; import { formatValue } from '../lib/format'; import { @@ -63,18 +64,7 @@ export function AnalyticsPage() { if (loading) return
; if (error) return ; - // Tile Helper - const getTileLabelAndIcon = (key: string) => { - switch (key) { - case 'total_orders': return { label: 'Total Orders', icon: ShoppingBag, color: 'text-indigo-500', bg: 'bg-indigo-50' }; - case 'total_bags': return { label: 'Total Bags', icon: Package, color: 'text-amber-500', bg: 'bg-amber-50' }; - case 'total_kgs': return { label: 'Total KGs', icon: Activity, color: 'text-emerald-500', bg: 'bg-emerald-50' }; - case 'total_calls': return { label: 'Total Calls', icon: Phone, color: 'text-blue-500', bg: 'bg-blue-50' }; - case 'total_productive_calls': return { label: 'Productive Calls', icon: TrendingUp, color: 'text-green-500', bg: 'bg-green-50' }; - case 'no_order_calls': return { label: 'No Order Calls', icon: Activity, color: 'text-red-500', bg: 'bg-red-50' }; - default: return { label: key.replace(/_/g, ' '), icon: BarChart3, color: 'text-slate-500', bg: 'bg-slate-50' }; - } - }; + const renderChart = (chart: ChartData, index: number) => { const data = chart.rows.map(r => ({ @@ -149,24 +139,7 @@ export function AnalyticsPage() {
{/* Tiles Grid */} -
- {tiles.map((t) => { - const { label, icon: Icon, color, bg } = getTileLabelAndIcon(t.key); - return ( -
-
- -
-
- {label} - - {t.key === 'total_kgs' ? Number(t.value).toLocaleString(undefined, { maximumFractionDigits: 1 }) : formatValue(t.value)} - -
-
- ); - })} -
+ {/* Charts Grid */}
diff --git a/src/screens/CallsPage.tsx b/src/screens/CallsPage.tsx index e544d8f..06f963b 100644 --- a/src/screens/CallsPage.tsx +++ b/src/screens/CallsPage.tsx @@ -126,7 +126,6 @@ export function CallsPage() {