potential mining api error fixed

This commit is contained in:
suryacp23 2026-07-22 10:58:44 +05:30
parent 2754484155
commit 1357935ead
9 changed files with 110 additions and 31 deletions

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'; import { useState, useEffect, useRef } from 'react';
import type { ZinoClient } from '../../api/client'; import type { ZinoClient } from '../../api/client';
import type { FormScreenResponse } from '../../api/types'; import type { FormScreenResponse } from '../../api/types';
import { Button } from '../buttons/Button'; import { Button } from '../buttons/Button';
@ -17,7 +17,7 @@ import {
WfLookupField, WfLookupField,
RadioField, RadioField,
} from './fields'; } from './fields';
import { ORDER_BOOKING } from '../../api/config'; import { ORDER_BOOKING, STORE } from '../../api/config';
export interface DynamicFormProps { export interface DynamicFormProps {
client: ZinoClient; client: ZinoClient;
@ -122,9 +122,14 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [submitError, setSubmitError] = useState<string | null>(null); const [submitError, setSubmitError] = useState<string | null>(null);
const handleFieldChange = (fieldId: string, newVal: unknown) => { const clickedActionRef = useRef<string | null>(null);
const handleFieldChange = (fieldId: string, newVal: unknown, fullRow?: any) => {
setValues(prev => { setValues(prev => {
const next = { ...prev, [fieldId]: newVal }; const next = { ...prev, [fieldId]: newVal };
if (fullRow) {
next[`${fieldId}_row`] = fullRow;
}
// Auto-calculate order_details totals // Auto-calculate order_details totals
const getBaseIdForField = (id: string) => id.replace(/_\d+$/, ''); const getBaseIdForField = (id: string) => id.replace(/_\d+$/, '');
@ -174,15 +179,22 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
// Filter out disabled fields (usually server-generated IDs) // Filter out disabled fields (usually server-generated IDs)
const fields = schema.fields.filter(f => !f.properties?.disabled); const fields = schema.fields.filter(f => !f.properties?.disabled);
const actionField = fields.find(f => f.name.toLowerCase() === 'action' && f.data_type === 'radio');
const normalFields = fields.filter(f => f !== actionField);
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
setSubmitting(true); setSubmitting(true);
setSubmitError(null); setSubmitError(null);
try { try {
const payload: Record<string, unknown> = {}; const payload: Record<string, unknown> = {};
const finalValues = { ...values };
if (actionField && clickedActionRef.current) {
finalValues[actionField.id] = clickedActionRef.current;
}
for (const f of fields) { for (const f of fields) {
const val = values[f.id]; const val = finalValues[f.id];
if (val == null) continue; if (val == null) continue;
if (f.data_type === 'phone' && typeof val === 'string') { if (f.data_type === 'phone' && typeof val === 'string') {
@ -243,11 +255,52 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
if (nextActivity) { if (nextActivity) {
let nextPrefillData = undefined; let nextPrefillData = undefined;
if (nextActivity.activity_uid === ORDER_BOOKING.activities.POTENTIAL_MINING.uid) { if (nextActivity.activity_uid === ORDER_BOOKING.activities.POTENTIAL_MINING.uid) {
let storeCodeToSend = String((values['select_store_row'] as any)?.store_code || (chainedPrefillData?.['select_store_row'] as any)?.store_code || '');
if (!storeCodeToSend) {
let storeId = values['select_store'] || chainedPrefillData?.['select_store'] || (schema?.prefill_data as any)?.select_store || (schema?.data as any)?.select_store;
if (typeof storeId === 'object' && storeId !== null) {
storeCodeToSend = (storeId as any).store_code || storeCodeToSend;
storeId = (storeId as any).value || (storeId as any).instance_id || String(storeId);
}
if (!storeCodeToSend && storeId) {
try {
const detailRes = await client.detailView(STORE.detailViews.STORE, storeId);
if (detailRes.data && detailRes.data.store_code) {
storeCodeToSend = String(detailRes.data.store_code);
}
} catch(e) {
try {
const lookupRes = await client.wfLookupRecords({
activityId: ORDER_BOOKING.activities.LOG_VISIT.uid,
fieldId: ORDER_BOOKING.activities.LOG_VISIT.fields.selectStore,
formData: { ...(chainedPrefillData as any || {}), ...values, ...(schema?.prefill_data as any || {}) },
limit: 500
});
const arr = Array.isArray(lookupRes) ? lookupRes : (lookupRes.data || lookupRes.records || []);
const row = arr.find((r: any) => String(r.instance_id || r.id) === String(storeId));
if (row && row.store_code) {
storeCodeToSend = String(row.store_code);
}
} catch (err) {
console.error("Failed to fetch store code:", err);
}
}
}
}
if (!storeCodeToSend) {
storeCodeToSend = String(values['select_store'] || chainedPrefillData?.['select_store'] || (schema?.prefill_data as any)?.select_store || '');
}
try { try {
const pmRes = await client.request<{ potential: { potential: any[] } }>( const pmRes = await client.request<{ potential: { potential: any[] } }>(
'POST', 'POST',
'/api/papi2/potential-mining', '/api/papi2/potential-mining',
{ instance_id: String(res.instance_id ?? currentInstanceId) }, {
instance_id: String(res.instance_id ?? currentInstanceId),
store_code: storeCodeToSend
},
{ 'TemplateID': '146' } { 'TemplateID': '146' }
); );
const rawPotential = pmRes.potential?.potential || []; const rawPotential = pmRes.potential?.potential || [];
@ -268,11 +321,11 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
} }
} }
if (nextPrefillData) { setChainedPrefillData(prev => ({
setChainedPrefillData(nextPrefillData); ...prev,
} else { ...values,
setChainedPrefillData(undefined); ...(nextPrefillData || {})
} }));
setChainQueue(pending); setChainQueue(pending);
setCurrentActivityId(nextActivity.activity_uid); setCurrentActivityId(nextActivity.activity_uid);
@ -290,7 +343,7 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
return ( return (
<form onSubmit={handleSubmit} className="flex flex-col gap-4"> <form onSubmit={handleSubmit} className="flex flex-col gap-4">
{fields.map(f => { {normalFields.map(f => {
const type = f.data_type; const type = f.data_type;
const val = values[f.id]; const val = values[f.id];
const isDisabled = schema.field_defaults?.[f.id]?.disabled; const isDisabled = schema.field_defaults?.[f.id]?.disabled;
@ -308,7 +361,7 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
activityId={currentActivityId} activityId={currentActivityId}
fieldId={f.id} fieldId={f.id}
formData={values} formData={values}
onChange={(newVal) => handleFieldChange(f.id, newVal)} onChange={(newVal, fullRow) => handleFieldChange(f.id, newVal, fullRow)}
/> />
); );
} }
@ -456,9 +509,23 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
Cancel Cancel
</Button> </Button>
)} )}
<Button type="submit" variant="primary" disabled={submitting}> {actionField && actionField.properties?.options ? (
{submitting ? 'Submitting...' : 'Submit'} actionField.properties.options.map((opt: any) => (
</Button> <Button
key={opt.value}
type="submit"
variant="primary"
disabled={submitting}
onClick={() => { clickedActionRef.current = opt.value; }}
>
{submitting && clickedActionRef.current === opt.value ? 'Submitting...' : opt.label}
</Button>
))
) : (
<Button type="submit" variant="primary" disabled={submitting}>
{submitting ? 'Submitting...' : 'Submit'}
</Button>
)}
</div> </div>
</form> </form>
); );

View File

@ -6,7 +6,7 @@ export interface WfLookupFieldProps {
label: string; label: string;
required?: boolean; required?: boolean;
value: string | number; value: string | number;
onChange: (val: string) => void; onChange: (val: string, fullRow?: any) => void;
client: ZinoClient; client: ZinoClient;
config: any; // wf_lookup_config config: any; // wf_lookup_config
properties?: any; // parent field properties properties?: any; // parent field properties
@ -17,14 +17,13 @@ export interface WfLookupFieldProps {
export function WfLookupField({ label, required, value, onChange, client, config, activityId, fieldId, formData }: WfLookupFieldProps) { export function WfLookupField({ label, required, value, onChange, client, config, activityId, fieldId, formData }: WfLookupFieldProps) {
const [options, setOptions] = useState<{ label: string; value: string }[]>([]); const [options, setOptions] = useState<{ label: string; value: string }[]>([]);
const [loading, setLoading] = useState(true); const [records, setRecords] = useState<any[]>([]);
const formDataStr = JSON.stringify(formData); const formDataStr = JSON.stringify(formData);
useEffect(() => { useEffect(() => {
let mounted = true; let mounted = true;
setLoading(true);
const timer = setTimeout(() => { const timer = setTimeout(() => {
client.wfLookupRecords({ client.wfLookupRecords({
activityId, activityId,
@ -36,6 +35,7 @@ export function WfLookupField({ label, required, value, onChange, client, config
if (!mounted) return; if (!mounted) return;
// The API might return { data: [...] } or { records: [...] } or just an array // The API might return { data: [...] } or { records: [...] } or just an array
const arr = Array.isArray(res) ? res : (res.data || res.records || []); const arr = Array.isArray(res) ? res : (res.data || res.records || []);
setRecords(arr);
const displayFields = config?.display_fields || []; const displayFields = config?.display_fields || [];
@ -59,9 +59,6 @@ export function WfLookupField({ label, required, value, onChange, client, config
}) })
.catch(err => { .catch(err => {
console.error("Failed to load wf_lookup records:", err); console.error("Failed to load wf_lookup records:", err);
})
.finally(() => {
if (mounted) setLoading(false);
}); });
}, 300); }, 300);
@ -76,7 +73,10 @@ export function WfLookupField({ label, required, value, onChange, client, config
label={label} label={label}
required={required} required={required}
value={String(value || '')} value={String(value || '')}
onChange={onChange} onChange={(val) => {
const row = records.find(r => String(r.instance_id || r.id) === val);
onChange(val, row);
}}
options={options} options={options}
/> />
); );

View File

@ -86,6 +86,8 @@ export function AnalyticsChart({ data }: AnalyticsChartProps) {
chartType = 4; // Donut chartType = 4; // Donut
} else if (lowerKey.includes('brand') || lowerKey.includes('product')) { } else if (lowerKey.includes('brand') || lowerKey.includes('product')) {
chartType = 5; // Table chartType = 5; // Table
} else if (lowerKey.includes('monthly')) {
chartType = 0; // Bar
} }
const renderChartContent = () => { const renderChartContent = () => {

View File

@ -26,10 +26,22 @@ export function formatValue(value: unknown, fieldKey?: string): string {
const isTimeOnly = lowerKey.includes('time'); const isTimeOnly = lowerKey.includes('time');
const isDateOnly = lowerKey.includes('date'); const isDateOnly = lowerKey.includes('date');
const isYearZero = typeof value === 'string' && value.startsWith('0000-01-01');
if (isTimeOnly && !isDateOnly) { if (isTimeOnly && !isDateOnly) {
return date.toLocaleTimeString('en-IN', { hour: 'numeric', minute: '2-digit', hour12: true }); return date.toLocaleTimeString('en-IN', {
hour: 'numeric',
minute: '2-digit',
hour12: true,
...(isYearZero && { timeZone: 'UTC' })
});
} else if (isDateOnly && !isTimeOnly) { } else if (isDateOnly && !isTimeOnly) {
return date.toLocaleDateString('en-IN', { day: 'numeric', month: 'short', year: 'numeric' }); return date.toLocaleDateString('en-IN', {
day: 'numeric',
month: 'short',
year: 'numeric',
...(isYearZero && { timeZone: 'UTC' })
});
} else { } else {
return date.toLocaleString('en-IN', { return date.toLocaleString('en-IN', {
day: 'numeric', day: 'numeric',
@ -37,7 +49,8 @@ export function formatValue(value: unknown, fieldKey?: string): string {
year: 'numeric', year: 'numeric',
hour: 'numeric', hour: 'numeric',
minute: '2-digit', minute: '2-digit',
hour12: true hour12: true,
...(isYearZero && { timeZone: 'UTC' })
}); });
} }
} }

View File

@ -6,7 +6,6 @@ import { useEffect, useState } from 'react';
import { Button } from '../components/buttons/Button'; import { Button } from '../components/buttons/Button';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { DynamicForm } from '../components/forms/DynamicForm'; import { DynamicForm } from '../components/forms/DynamicForm';
import { formatActivityName } from '../lib/format';
import { ORDER_BOOKING } from '../api/config'; import { ORDER_BOOKING } from '../api/config';
import { orderBookingClient } from '../api/clients'; import { orderBookingClient } from '../api/clients';
@ -139,7 +138,9 @@ export function CallsPage() {
placeOrderAction={ placeOrderAction={
(() => { (() => {
const stateName = String(selectedRow.current_state_name || selectedRow.current_state_name_ || selectedRow.current_state || selectedRow.status || '').toLowerCase(); const stateName = String(selectedRow.current_state_name || selectedRow.current_state_name_ || selectedRow.current_state || selectedRow.status || '').toLowerCase();
if (stateName.includes('ordered') || stateName === 'ordered' || stateName.includes('order')) { if (stateName === 'no order' || stateName === 'no_order') {
return null;
} else if (stateName.includes('ordered') || stateName === 'ordered' || stateName.includes('order')) {
return ( return (
<Button onClick={() => setActiveActivity({ id: ORDER_BOOKING.activities.EDIT_ORDER.uid, name: 'Edit Order' })}> <Button onClick={() => setActiveActivity({ id: ORDER_BOOKING.activities.EDIT_ORDER.uid, name: 'Edit Order' })}>
Edit Order Edit Order

View File

@ -6,7 +6,6 @@ import { useState } from 'react';
import { Button } from '../components/buttons/Button'; import { Button } from '../components/buttons/Button';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { DynamicForm } from '../components/forms/DynamicForm'; import { DynamicForm } from '../components/forms/DynamicForm';
import { formatActivityName } from '../lib/format';
import { DAILY_REPORTS } from '../api/config'; import { DAILY_REPORTS } from '../api/config';
import { dailyReportsClient } from '../api/clients'; import { dailyReportsClient } from '../api/clients';

View File

@ -6,7 +6,6 @@ import { useState } from 'react';
import { Button } from '../components/buttons/Button'; import { Button } from '../components/buttons/Button';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { DynamicForm } from '../components/forms/DynamicForm'; import { DynamicForm } from '../components/forms/DynamicForm';
import { formatActivityName } from '../lib/format';
import { ORDER_BOOKING } from '../api/config'; import { ORDER_BOOKING } from '../api/config';
import { orderBookingClient } from '../api/clients'; import { orderBookingClient } from '../api/clients';
import { useAuth } from '../auth/context'; import { useAuth } from '../auth/context';

View File

@ -6,7 +6,6 @@ import { useState } from 'react';
import { Button } from '../components/buttons/Button'; import { Button } from '../components/buttons/Button';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { DynamicForm } from '../components/forms/DynamicForm'; import { DynamicForm } from '../components/forms/DynamicForm';
import { formatActivityName } from '../lib/format';
import { ORDER_BOOKING } from '../api/config'; import { ORDER_BOOKING } from '../api/config';
import { orderBookingClient } from '../api/clients'; import { orderBookingClient } from '../api/clients';

View File

@ -6,7 +6,6 @@ import { StoreDetail } from '../components/dv';
import { Button } from '../components/buttons/Button'; import { Button } from '../components/buttons/Button';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { DynamicForm } from '../components/forms/DynamicForm'; import { DynamicForm } from '../components/forms/DynamicForm';
import { formatActivityName } from '../lib/format';
import { STORE } from '../api/config'; import { STORE } from '../api/config';
import { storeClient } from '../api/clients'; import { storeClient } from '../api/clients';