added edit

This commit is contained in:
suryacp23 2026-07-16 12:45:18 +05:30
parent da013c6bac
commit f92d47ded3
5 changed files with 193 additions and 36 deletions

View File

@ -30,6 +30,15 @@ export const ORDER_BOOKING = {
totalKgs: 'total_kgs', // number totalKgs: 'total_kgs', // number
}, },
}, },
EDIT_ORDER: {
uid: '296e418e-5b31-43ad-aba4-4e9a1027ccd9',
fields: {
dateOfOrder: 'date_of_order', // date
orderDetails: 'order_details', // grid
totalBags: 'total_bags', // number
totalKgs: 'total_kgs', // number
},
},
PRODUCTIVITY_OF_VISIT: { PRODUCTIVITY_OF_VISIT: {
uid: '11bd10f9-a001-470e-867f-33dee8eabe4b', uid: '11bd10f9-a001-470e-867f-33dee8eabe4b',
fields: { fields: {

View File

@ -16,15 +16,17 @@ export function OrderCard({ row, fields }: { row: Record<string, any>; fields: a
const userObj = userKey ? row[userKey] as Record<string, unknown> : null; const userObj = userKey ? row[userKey] as Record<string, unknown> : null;
const userVal = formatValue(userObj?.name || userObj?.user_name || '—'); const userVal = formatValue(userObj?.name || userObj?.user_name || '—');
const dateVal = row.date_of_order ? formatValue(row.date_of_order) : '—'; // Extract date
const dateKey = Object.keys(row).find(k => k.includes('date_of_order'));
const dateVal = dateKey && row[dateKey] ? formatValue(row[dateKey]) : '—';
const stateName = String(row.current_state_name || ''); const stateName = String(row.current_state_name || '');
const isProductive = stateName.toLowerCase().includes('productive') || stateName.toLowerCase().includes('closed'); const isProductive = stateName.toLowerCase().includes('productive') || stateName.toLowerCase().includes('closed') || stateName.toLowerCase().includes('ordered');
const productiveLabel = stateName || 'Pending'; const productiveLabel = stateName || 'Pending';
// Order Details Grid // Order Details Grid
const gridField = fields.find(f => f.data_type === 'grid' || f.field_key === 'order_details'); const gridField = fields.find(f => f.data_type === 'grid' || String(f.field_key).includes('order_details'));
const gridValRaw = gridField ? row[gridField.field_key] : row.order_details; const gridValRaw = gridField ? row[gridField.field_key] : (row.order_details || row.order_details_2 || row.order_details_3);
const gridVal = Array.isArray(gridValRaw) ? gridValRaw : []; const gridVal = Array.isArray(gridValRaw) ? gridValRaw : [];
return ( return (
@ -96,9 +98,16 @@ export function OrderCard({ row, fields }: { row: Record<string, any>; fields: a
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">
{gridVal.map((item, i) => { {gridVal.map((item, i) => {
const productName = formatValue(item.product_name || item.product_category || 'Unknown Product'); const getVal = (key: string) => {
const sku = formatValue(item.sku_code || item.sku || 'N/A'); if (item[key] !== undefined) return item[key];
const bags = formatValue(item.bags || item.total_bags || item.quantity || 0); const keyPattern = new RegExp(`^${key}(_\\d+)?$`);
const match = Object.keys(item).find(k => keyPattern.test(k) || k.includes(key));
return match ? item[match] : undefined;
};
const productName = formatValue(getVal('product_name') || getVal('product_category') || 'Unknown Product');
const sku = formatValue(getVal('sku_code') || getVal('sku') || 'N/A');
const bags = formatValue(getVal('bags') || getVal('total_bags') || getVal('quantity') || 0);
return ( return (
<div key={i} className="flex items-center justify-between gap-4 p-2.5 rounded-xl bg-slate-50/80 border border-slate-100 transition-colors"> <div key={i} className="flex items-center justify-between gap-4 p-2.5 rounded-xl bg-slate-50/80 border border-slate-100 transition-colors">

View File

@ -75,15 +75,55 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
res.fields.filter(f => f.data_type === 'image' || f.data_type === 'file').map(f => f.id) res.fields.filter(f => f.data_type === 'image' || f.data_type === 'file').map(f => f.id)
); );
const mapPrefillData = (sourceData: Record<string, unknown>) => {
res.fields.forEach(f => {
if (imageFieldIds.has(f.id)) return;
const getBaseId = (id: string) => id.replace(/_\d+$/, '');
if (sourceData[f.id] !== undefined) {
defaultValues[f.id] = sourceData[f.id];
} else if (f.mapped_workflow_field && sourceData[f.mapped_workflow_field] !== undefined) {
defaultValues[f.id] = sourceData[f.mapped_workflow_field];
} else if (sourceData[getBaseId(f.id)] !== undefined) {
defaultValues[f.id] = sourceData[getBaseId(f.id)];
} else {
const matchingDataKey = Object.keys(sourceData).find(k => getBaseId(k) === f.id || getBaseId(k) === getBaseId(f.id) || k === f.mapped_workflow_field);
if (matchingDataKey) {
defaultValues[f.id] = sourceData[matchingDataKey];
}
}
// Special logic for Grid: we must map the keys inside each row to match the grid's column IDs!
if (f.data_type === 'grid' && Array.isArray(defaultValues[f.id])) {
defaultValues[f.id] = (defaultValues[f.id] as Record<string, unknown>[]).map(row => {
const newRow: Record<string, unknown> = { ...row };
f.columns?.forEach(col => {
const colBaseId = getBaseId(col.id);
if (row[col.id] !== undefined) {
newRow[col.id] = row[col.id];
} else if (col.mapped_workflow_field && row[col.mapped_workflow_field] !== undefined) {
newRow[col.id] = row[col.mapped_workflow_field];
} else if (row[colBaseId] !== undefined) {
newRow[col.id] = row[colBaseId];
} else {
const matchingRowKey = Object.keys(row).find(k => getBaseId(k) === col.id || getBaseId(k) === colBaseId || k === col.mapped_workflow_field);
if (matchingRowKey) {
newRow[col.id] = row[matchingRowKey];
}
}
});
return newRow;
});
}
});
};
if (!ignorePrefill) { if (!ignorePrefill) {
if (res.prefill_data) { if (res.prefill_data && Object.keys(res.prefill_data).length > 0) {
Object.entries(res.prefill_data).forEach(([k, v]) => { mapPrefillData(res.prefill_data);
if (!imageFieldIds.has(k)) defaultValues[k] = v;
});
} else if (res.data) { } else if (res.data) {
Object.entries(res.data).forEach(([k, v]) => { mapPrefillData(res.data);
if (!imageFieldIds.has(k)) defaultValues[k] = v;
});
} }
} }
@ -115,15 +155,37 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
const next = { ...prev, [fieldId]: newVal }; const next = { ...prev, [fieldId]: newVal };
// Auto-calculate order_details totals // Auto-calculate order_details totals
if (fieldId === 'order_details' && Array.isArray(newVal)) { const getBaseIdForField = (id: string) => id.replace(/_\d+$/, '');
const fieldDef = schema?.fields.find(f => f.id === fieldId);
const isOrderDetails = fieldId === 'order_details' || getBaseIdForField(fieldId) === 'order_details' || fieldDef?.mapped_workflow_field === 'order_details';
if (isOrderDetails && Array.isArray(newVal)) {
let totalBags = 0; let totalBags = 0;
let totalKgs = 0; let totalKgs = 0;
const getBaseId = (id: string) => id.replace(/_\d+$/, '');
const bagsColId = fieldDef?.columns?.find(c =>
c.id === 'bags' || getBaseId(c.id) === 'bags' || c.mapped_workflow_field === 'bags' || c.name.toLowerCase() === 'bags'
)?.id || 'bags';
const rowKgsColId = fieldDef?.columns?.find(c =>
c.id === 'row_kgs' || getBaseId(c.id) === 'row_kgs' || c.id === 'rowkgs' || getBaseId(c.id) === 'rowkgs' || c.mapped_workflow_field === 'row_kgs'
)?.id || 'row_kgs';
newVal.forEach(row => { newVal.forEach(row => {
totalBags += Number(row.bags) || 0; totalBags += Number(row[bagsColId]) || 0;
totalKgs += Number(row.row_kgs) || 0; totalKgs += Number(row[rowKgsColId]) || 0;
}); });
next['total_bags'] = totalBags;
next['total_kgs'] = totalKgs; const tbField = schema?.fields.find(f => f.id === 'total_bags' || getBaseId(f.id) === 'total_bags' || f.mapped_workflow_field === 'total_bags');
const tkField = schema?.fields.find(f => f.id === 'total_kgs' || getBaseId(f.id) === 'total_kgs' || f.mapped_workflow_field === 'total_kgs');
if (tbField) next[tbField.id] = totalBags;
else next['total_bags'] = totalBags;
if (tkField) next[tkField.id] = totalKgs;
else next['total_kgs'] = totalKgs;
} }
return next; return next;
@ -137,8 +199,7 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
return <div className="p-4 text-ruby-600">Failed to load form: {error}</div>; return <div className="p-4 text-ruby-600">Failed to load form: {error}</div>;
} }
// Filter out disabled fields (usually server-generated IDs) const fields = schema.fields;
const fields = schema.fields.filter(f => !f.properties?.disabled);
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
@ -226,7 +287,7 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
{fields.map(f => { {fields.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 || f.properties?.disabled;
const renderField = () => { const renderField = () => {
if (type === 'wf_lookup') { if (type === 'wf_lookup') {

View File

@ -22,9 +22,7 @@ export function SmartGridField({
const [editingIdx, setEditingIdx] = useState<number | null>(null); const [editingIdx, setEditingIdx] = useState<number | null>(null);
const visibleColumns = columns.filter(c => { const visibleColumns = columns.filter(c => {
const normalized = c.id.toLowerCase().replace(/[^a-z]/g, ''); return true; // Temporarily show all columns for debugging
// Use a blacklist so we don't accidentally hide important columns from other grids
return !['sku', 'skucode', 'rowkgs', 'brcode'].includes(normalized);
}); });
const removeRow = (idx: number) => { const removeRow = (idx: number) => {
@ -51,7 +49,7 @@ export function SmartGridField({
const colDef = columns.find(c => c.id === fieldId); const colDef = columns.find(c => c.id === fieldId);
// If product category changes, clear out the rest of the row's data // If product category changes, clear out the rest of the row's data
if (colDef && (colDef.id === 'product_category' || colDef.name === 'Product Category')) { if (colDef && (colDef.id === 'product_category' || colDef.name === 'Product Category' || colDef.mapped_workflow_field === 'product_category')) {
Object.keys(row).forEach(k => { Object.keys(row).forEach(k => {
if (k !== fieldId) { if (k !== fieldId) {
row[k] = ''; row[k] = '';
@ -63,19 +61,34 @@ export function SmartGridField({
if (colDef && (colDef.data_type === 'select' || colDef.data_type === 'multiselect')) { if (colDef && (colDef.data_type === 'select' || colDef.data_type === 'multiselect')) {
const option = colDef.properties?.options?.find(o => String(o.value) === String(val)); const option = colDef.properties?.options?.find(o => String(o.value) === String(val));
if (option && option._raw) { if (option && option._raw) {
const getBaseId = (id: string) => id.replace(/_\d+$/, '');
for (const key of Object.keys(option._raw)) { for (const key of Object.keys(option._raw)) {
const targetCol = columns.find(c => c.id === key || c.id.replace(/_/g, '') === key.replace(/_/g, '')); const targetCol = columns.find(c => c.id === key || c.mapped_workflow_field === key || getBaseId(c.id) === key || c.name.toLowerCase().replace(/\s+/g, '') === key.toLowerCase().replace(/_/g, ''));
if (targetCol && targetCol.id !== fieldId) { if (targetCol && targetCol.id !== fieldId) {
row[targetCol.id] = option._raw[key]; row[targetCol.id] = option._raw[key];
} else if (!targetCol && key !== fieldId) {
row[key] = option._raw[key];
} }
} }
} }
} }
// Auto-calculate row_kgs if sku and bags are present // Auto-calculate row_kgs if sku and bags are present
const skuVal = Number(row.sku) || 0; const getBaseId = (id: string) => id.replace(/_\d+$/, '');
const bagsVal = Number(row.bags) || 0; const getVal = (key: string) => {
row.row_kgs = skuVal * bagsVal; const c = columns.find(c => c.id === key || c.mapped_workflow_field === key || getBaseId(c.id) === key || c.name.toLowerCase().replace(/\s+/g, '') === key.toLowerCase().replace(/_/g, ''));
return c ? row[c.id] : row[key];
};
const skuVal = Number(getVal('sku')) || 0;
const bagsVal = Number(getVal('bags')) || 0;
const rowKgsCol = columns.find(c => c.id === 'row_kgs' || c.mapped_workflow_field === 'row_kgs' || getBaseId(c.id) === 'row_kgs' || getBaseId(c.id) === 'rowkgs');
if (rowKgsCol) {
row[rowKgsCol.id] = skuVal * bagsVal;
} else {
row['row_kgs'] = skuVal * bagsVal;
}
setNewRow(row); setNewRow(row);
}; };
@ -86,7 +99,38 @@ export function SmartGridField({
next[editingIdx] = newRow; next[editingIdx] = newRow;
onChange(next); onChange(next);
} else { } else {
onChange([...value, newRow]); const getBaseId = (id: string) => id.replace(/_\d+$/, '');
const prodNameCol = columns.find(c => c.id === 'product_name' || getBaseId(c.id) === 'product_name' || c.mapped_workflow_field === 'product_name');
let foundIdx = -1;
if (prodNameCol && newRow[prodNameCol.id]) {
foundIdx = value.findIndex(r => r[prodNameCol.id] === newRow[prodNameCol.id]);
}
if (foundIdx !== -1) {
const next = [...value];
const existingRow = { ...next[foundIdx] };
const bagsCol = columns.find(c => c.id === 'bags' || getBaseId(c.id) === 'bags' || c.mapped_workflow_field === 'bags' || c.name.toLowerCase() === 'bags');
const rowKgsCol = columns.find(c => c.id === 'row_kgs' || getBaseId(c.id) === 'row_kgs' || c.mapped_workflow_field === 'row_kgs' || getBaseId(c.id) === 'rowkgs');
const skuCol = columns.find(c => c.id === 'sku' || getBaseId(c.id) === 'sku' || c.mapped_workflow_field === 'sku');
const bagsId = bagsCol ? bagsCol.id : 'bags';
const rowKgsId = rowKgsCol ? rowKgsCol.id : 'row_kgs';
const skuId = skuCol ? skuCol.id : 'sku';
const existingBags = Number(existingRow[bagsId]) || 0;
const addedBags = Number(newRow[bagsId]) || 0;
existingRow[bagsId] = existingBags + addedBags;
const skuVal = Number(existingRow[skuId]) || 0;
existingRow[rowKgsId] = (existingBags + addedBags) * skuVal;
next[foundIdx] = existingRow;
onChange(next);
} else {
onChange([...value, newRow]);
}
} }
setIsModalOpen(false); setIsModalOpen(false);
setNewRow({}); setNewRow({});
@ -170,8 +214,8 @@ export function SmartGridField({
const allOpts = col.properties?.options || []; const allOpts = col.properties?.options || [];
let filteredOpts = allOpts; let filteredOpts = allOpts;
if (col.id === 'product_name' || col.name === 'Product Name') { if (col.id === 'product_name' || col.name === 'Product Name' || col.mapped_workflow_field === 'product_name') {
const catCol = columns.find(c => c.id === 'product_category' || c.name === 'Product Category'); const catCol = columns.find(c => c.id === 'product_category' || c.name === 'Product Category' || c.mapped_workflow_field === 'product_category');
if (catCol) { if (catCol) {
const selectedCategory = newRow[catCol.id] as string; const selectedCategory = newRow[catCol.id] as string;
if (selectedCategory) { if (selectedCategory) {

View File

@ -119,9 +119,43 @@ export function CallsPage() {
<Button size="sm" variant="secondary" onClick={handlePotentialMiningClick} disabled={miningLoading}> <Button size="sm" variant="secondary" onClick={handlePotentialMiningClick} disabled={miningLoading}>
{miningLoading ? 'Loading...' : 'Potential Mining'} {miningLoading ? 'Loading...' : 'Potential Mining'}
</Button> </Button>
<Button size="sm" onClick={() => { setActiveActivity({ id: ORDER_BOOKING.activities.PLACE_ORDER.uid, name: 'Place Order' }); setIsFabOpen(false); }}> {(() => {
Place Order const stateName = String(selectedRow?.current_state_name || selectedRow?.current_state_name_ || selectedRow?.current_state || selectedRow?.status || '').toLowerCase();
</Button> if (stateName.includes('ordered') || stateName === 'ordered') {
return (
<Button size="sm" onClick={(e) => {
e.stopPropagation();
e.preventDefault();
console.log("Clicked Edit Order, ID:", ORDER_BOOKING.activities.EDIT_ORDER?.uid);
setActiveActivity({ id: ORDER_BOOKING.activities.EDIT_ORDER.uid, name: 'Edit Order' });
setIsFabOpen(false);
}}>
Edit Order
</Button>
);
} else if (stateName.includes('productive')) {
return (
<Button size="sm" onClick={(e) => {
e.stopPropagation();
e.preventDefault();
setActiveActivity({ id: ORDER_BOOKING.activities.PLACE_ORDER.uid, name: 'Place Order' });
setIsFabOpen(false);
}}>
Place Order
</Button>
);
}
return (
<Button size="sm" onClick={(e) => {
e.stopPropagation();
e.preventDefault();
setActiveActivity({ id: ORDER_BOOKING.activities.PLACE_ORDER.uid, name: 'Place Order' });
setIsFabOpen(false);
}}>
Place Order
</Button>
);
})()}
</div> </div>
)} )}
<Button size='fab' <Button size='fab'