map addition

This commit is contained in:
suryacp23 2026-07-27 11:08:06 +05:30
parent c2c9ac39da
commit b1003de515
7 changed files with 77 additions and 8 deletions

View File

@ -31,16 +31,23 @@ export interface ChartConfig {
export interface AnalyticsChartProps { export interface AnalyticsChartProps {
data?: unknown[]; data?: unknown[];
gridCols?: number;
} }
export function AnalyticsChart({ data }: AnalyticsChartProps) { export function AnalyticsChart({ data, gridCols }: AnalyticsChartProps) {
if (!data || !Array.isArray(data) || data.length === 0) return null; if (!data || !Array.isArray(data) || data.length === 0) return null;
const charts = data as ChartConfig[]; const charts = data as ChartConfig[];
const colors = ['#3B82F6', '#10B981', '#F59E0B', '#8B5CF6', '#EC4899', '#14B8A6']; const colors = ['#3B82F6', '#10B981', '#F59E0B', '#8B5CF6', '#EC4899', '#14B8A6'];
const gridClass = gridCols === 1
? "grid grid-cols-1 gap-6 w-full"
: gridCols === 2
? "grid grid-cols-1 lg:grid-cols-2 gap-6 w-full"
: "grid grid-cols-1 lg:grid-cols-3 gap-6 w-full";
return ( return (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 w-full"> <div className={gridClass}>
{charts.map((chart, idx) => { {charts.map((chart, idx) => {
const title = (chart.key || `Chart ${idx + 1}`) const title = (chart.key || `Chart ${idx + 1}`)
.replace(/_/g, ' ') .replace(/_/g, ' ')

View File

@ -4,7 +4,7 @@ import { RecordView } from './RecordView';
import type { WiredRecordViewProps } from './OrdersView'; import type { WiredRecordViewProps } from './OrdersView';
/** Daily Logs record view (Daily Reports workflow). */ /** Daily Logs record view (Daily Reports workflow). */
export function DailyLogsView({ onRowClick, pageSize, headerActions, rowActions, refreshKey, presetAlias }: WiredRecordViewProps) { export function DailyLogsView({ onRowClick, pageSize, headerActions, rowActions, refreshKey, presetAlias, mapComponent }: WiredRecordViewProps) {
return ( return (
<RecordView <RecordView
client={dailyReportsClient} client={dailyReportsClient}
@ -16,6 +16,7 @@ export function DailyLogsView({ onRowClick, pageSize, headerActions, rowActions,
rowActions={rowActions} rowActions={rowActions}
refreshKey={refreshKey} refreshKey={refreshKey}
presetAlias={presetAlias} presetAlias={presetAlias}
mapComponent={mapComponent}
/> />
); );
} }

View File

@ -10,6 +10,7 @@ export interface WiredRecordViewProps {
refreshKey?: number; refreshKey?: number;
initialFilters?: Record<string, string>; initialFilters?: Record<string, string>;
presetAlias?: string; presetAlias?: string;
mapComponent?: React.ReactNode;
} }
/** Orders record view (Order Booking workflow). */ /** Orders record view (Order Booking workflow). */

View File

@ -43,6 +43,8 @@ export interface RecordViewProps {
initialFilters?: Record<string, string>; initialFilters?: Record<string, string>;
/** Custom preset alias to send with the request (e.g. preset_alias: my_orders) */ /** Custom preset alias to send with the request (e.g. preset_alias: my_orders) */
presetAlias?: string; presetAlias?: string;
/** Component to render next to charts (e.g., a map) */
mapComponent?: React.ReactNode;
} }
/** /**
@ -66,6 +68,7 @@ export function RecordView({
omitColumns, omitColumns,
initialFilters = {}, initialFilters = {},
presetAlias, presetAlias,
mapComponent,
}: RecordViewProps) { }: RecordViewProps) {
const [internalPageSize, setInternalPageSize] = useState(pageSize); const [internalPageSize, setInternalPageSize] = useState(pageSize);
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
@ -150,12 +153,26 @@ export function RecordView({
const tileValues = resp?.tile_values; const tileValues = resp?.tile_values;
const chartData = resp?.chart_data; const chartData = resp?.chart_data;
const hasChart = chartData && Array.isArray(chartData) && chartData.length > 0;
return ( return (
<div className="flex flex-col gap-6 w-full"> <div className="flex flex-col gap-6 w-full">
<StatsTiles tiles={tileValues} /> <StatsTiles tiles={tileValues} />
<AnalyticsChart data={chartData} /> {(hasChart || mapComponent) ? (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 w-full">
{hasChart && (
<div className={mapComponent ? "lg:col-span-1" : "lg:col-span-3"}>
<AnalyticsChart data={chartData} gridCols={mapComponent ? 1 : undefined} />
</div>
)}
{mapComponent && (
<div className={hasChart ? "lg:col-span-2" : "lg:col-span-3"}>
{mapComponent}
</div>
)}
</div>
) : null}
<Card <Card
title={title} title={title}

View File

@ -4,7 +4,7 @@ import { RecordView } from './RecordView';
import type { WiredRecordViewProps } from './OrdersView'; import type { WiredRecordViewProps } from './OrdersView';
/** Store record view (Store workflow). */ /** Store record view (Store workflow). */
export function StoresView({ onRowClick, pageSize, headerActions, rowActions, refreshKey }: WiredRecordViewProps & { headerActions?: React.ReactNode }) { export function StoresView({ onRowClick, pageSize, headerActions, rowActions, refreshKey, mapComponent }: WiredRecordViewProps & { headerActions?: React.ReactNode }) {
return ( return (
<RecordView <RecordView
client={storeClient} client={storeClient}
@ -15,6 +15,7 @@ export function StoresView({ onRowClick, pageSize, headerActions, rowActions, re
headerActions={headerActions} headerActions={headerActions}
rowActions={rowActions} rowActions={rowActions}
refreshKey={refreshKey} refreshKey={refreshKey}
mapComponent={mapComponent}
/> />
); );
} }

View File

@ -4,7 +4,7 @@ import { DailyLogsView } from '../components/rv';
import { DailyLogDetail } from '../components/dv'; import { DailyLogDetail } from '../components/dv';
import { useState } from 'react'; import { useState } from 'react';
import { Button } from '../components/buttons/Button'; import { Button } from '../components/buttons/Button';
import { Plus } from 'lucide-react'; import { Plus, MapPin } from 'lucide-react';
import { DynamicForm } from '../components/forms/DynamicForm'; import { DynamicForm } from '../components/forms/DynamicForm';
import { DAILY_REPORTS } from '../api/config'; import { DAILY_REPORTS } from '../api/config';
import { dailyReportsClient } from '../api/clients'; import { dailyReportsClient } from '../api/clients';
@ -19,10 +19,31 @@ export function DailyLogsPage() {
const [punchOutTitle, setPunchOutTitle] = useState('Punch Out'); const [punchOutTitle, setPunchOutTitle] = useState('Punch Out');
const [refreshKey, setRefreshKey] = useState(0); const [refreshKey, setRefreshKey] = useState(0);
const mapComponent = (
<div className="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden flex flex-col h-full min-h-[320px]">
<div className="p-4 border-b border-slate-100 flex items-center gap-2">
<MapPin size={18} className="text-slate-400" />
<h3 className="text-slate-800 font-bold">Activity Locations</h3>
</div>
<div className="flex-1 relative bg-slate-50">
<iframe
title="Logs Map"
width="100%"
height="100%"
style={{ border: 0, position: 'absolute', inset: 0 }}
loading="lazy"
allowFullScreen
src="https://maps.google.com/maps?q=activity&hl=en&z=10&output=embed"
></iframe>
</div>
</div>
);
return ( return (
<> <>
{instanceId == null && ( {instanceId == null && (
<DailyLogsView <DailyLogsView
mapComponent={mapComponent}
refreshKey={refreshKey} refreshKey={refreshKey}
presetAlias="my_logs" presetAlias="my_logs"
onRowClick={(row) => { onRowClick={(row) => {

View File

@ -1,9 +1,9 @@
import { useState } from 'react'; import { useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { StoresView } from '../components/rv'; import { StoresView } from '../components/rv';
import { StoreDetail } from '../components/dv'; import { StoreDetail } from '../components/dv';
import { Button } from '../components/buttons/Button'; import { Button } from '../components/buttons/Button';
import { Plus } from 'lucide-react'; import { Plus, MapPin } from 'lucide-react';
import { DynamicForm } from '../components/forms/DynamicForm'; import { DynamicForm } from '../components/forms/DynamicForm';
import { STORE } from '../api/config'; import { STORE } from '../api/config';
import { storeClient } from '../api/clients'; import { storeClient } from '../api/clients';
@ -55,9 +55,30 @@ export function StoresPage() {
); );
} }
const mapComponent = (
<div className="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden flex flex-col h-full min-h-[320px]">
<div className="p-4 border-b border-slate-100 flex items-center gap-2">
<MapPin size={18} className="text-slate-400" />
<h3 className="text-slate-800 font-bold">Location Spread</h3>
</div>
<div className="flex-1 relative bg-slate-50">
<iframe
title="Stores Map"
width="100%"
height="100%"
style={{ border: 0, position: 'absolute', inset: 0 }}
loading="lazy"
allowFullScreen
src="https://maps.google.com/maps?q=stores&hl=en&z=10&output=embed"
></iframe>
</div>
</div>
);
return ( return (
<> <>
<StoresView <StoresView
mapComponent={mapComponent}
refreshKey={refreshKey} refreshKey={refreshKey}
onRowClick={(row) => { onRowClick={(row) => {
const id = row.instance_id as number | string | undefined; const id = row.instance_id as number | string | undefined;