added edit
This commit is contained in:
parent
da013c6bac
commit
f92d47ded3
@ -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: {
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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') {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user