fixed the form table smart grid
This commit is contained in:
parent
95d0c00dd4
commit
3eb445d506
@ -2,8 +2,8 @@ import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|||||||
import { cn } from '../../lib/cn';
|
import { cn } from '../../lib/cn';
|
||||||
import './style.css'
|
import './style.css'
|
||||||
|
|
||||||
export type ButtonVariant = 'primary' | 'navy' | 'secondary' | 'ghost' | 'danger'|'outline';
|
export type ButtonVariant = 'primary' | 'navy' | 'secondary' | 'ghost' | 'danger' | 'outline';
|
||||||
export type ButtonSize = 'sm' | 'md' | 'lg';
|
export type ButtonSize = 'sm' | 'md' | 'lg' | 'fab';
|
||||||
|
|
||||||
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
/** Visual style. @default "primary" */
|
/** Visual style. @default "primary" */
|
||||||
@ -20,6 +20,7 @@ const SIZES: Record<ButtonSize, string> = {
|
|||||||
sm: 'h-[34px] px-3.5 text-[13px] rounded-sm',
|
sm: 'h-[34px] px-3.5 text-[13px] rounded-sm',
|
||||||
md: 'h-[42px] px-[18px] text-base rounded-md',
|
md: 'h-[42px] px-[18px] text-base rounded-md',
|
||||||
lg: 'h-[50px] px-6 text-md rounded-md',
|
lg: 'h-[50px] px-6 text-md rounded-md',
|
||||||
|
fab: 'h-[56px] w-[56px] text-sm rounded-full',
|
||||||
};
|
};
|
||||||
|
|
||||||
const VARIANTS: Record<ButtonVariant, string> = {
|
const VARIANTS: Record<ButtonVariant, string> = {
|
||||||
@ -28,7 +29,7 @@ const VARIANTS: Record<ButtonVariant, string> = {
|
|||||||
secondary: 'bg-card text-strong border border-border-default shadow-xs',
|
secondary: 'bg-card text-strong border border-border-default shadow-xs',
|
||||||
ghost: 'bg-transparent text-body border border-transparent',
|
ghost: 'bg-transparent text-body border border-transparent',
|
||||||
danger: 'bg-ruby-600 text-white border border-transparent shadow-sm',
|
danger: 'bg-ruby-600 text-white border border-transparent shadow-sm',
|
||||||
outline:'z-btn-outline'
|
outline: 'z-btn-outline'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,7 +55,7 @@ export function Button({
|
|||||||
'disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100',
|
'disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100',
|
||||||
SIZES[size],
|
SIZES[size],
|
||||||
VARIANTS[variant],
|
VARIANTS[variant],
|
||||||
full ? 'w-full' : 'w-auto',
|
full ? 'w-full' : '',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...rest}
|
{...rest}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
WfLookupField,
|
WfLookupField,
|
||||||
RadioField,
|
RadioField,
|
||||||
} from './fields';
|
} from './fields';
|
||||||
|
import { ORDER_BOOKING } from '../../api/config';
|
||||||
|
|
||||||
export interface DynamicFormProps {
|
export interface DynamicFormProps {
|
||||||
client: ZinoClient;
|
client: ZinoClient;
|
||||||
@ -172,12 +173,25 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
|
|||||||
}
|
}
|
||||||
|
|
||||||
let pending = [...chainQueue];
|
let pending = [...chainQueue];
|
||||||
const newActivities = (schema.activity_chain || []).filter(
|
let chainSource = (res as any).activity_chain || schema.activity_chain || [];
|
||||||
a => a.activity_uid !== currentActivityId
|
|
||||||
|
// Centralized activity chaining logic
|
||||||
|
if (currentActivityId === ORDER_BOOKING.activities.PRODUCTIVITY_OF_VISIT.uid) {
|
||||||
|
const actionValue = String(payload[ORDER_BOOKING.activities.PRODUCTIVITY_OF_VISIT.fields.action] || '').toLowerCase().trim();
|
||||||
|
const normalized = actionValue.replace(/[\s_]+/g, '');
|
||||||
|
if (normalized === 'order') {
|
||||||
|
chainSource = [{ activity_uid: ORDER_BOOKING.activities.PLACE_ORDER.uid, activity_name: 'Place Order' }];
|
||||||
|
} else if (normalized === 'noorder') {
|
||||||
|
chainSource = [{ activity_uid: ORDER_BOOKING.activities.POTENTIAL_MINING.uid, activity_name: 'Potential Mining' }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newActivities = chainSource.filter(
|
||||||
|
(a: any) => a.activity_uid !== currentActivityId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Remove any existing occurrences from pending to avoid duplicates
|
// Remove any existing occurrences from pending to avoid duplicates
|
||||||
pending = pending.filter(p => !newActivities.some(n => n.activity_uid === p.activity_uid));
|
pending = pending.filter(p => !newActivities.some((n: any) => n.activity_uid === p.activity_uid));
|
||||||
|
|
||||||
// Prepend the new activities for depth-first execution (nested chaining)
|
// Prepend the new activities for depth-first execution (nested chaining)
|
||||||
pending = [...newActivities, ...pending];
|
pending = [...newActivities, ...pending];
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
import { Button } from '../../buttons/Button';
|
import { Button } from '../../buttons/Button';
|
||||||
import { Select } from '../../reusable/Select';
|
import { Select } from '../../reusable/Select';
|
||||||
import { Input } from '../../reusable/Input';
|
import { Input } from '../../reusable/Input';
|
||||||
|
import { Modal } from '../../reusable/Modal';
|
||||||
|
import { Trash2, Pencil } from 'lucide-react';
|
||||||
import type { FormScreenField } from '../../../api/types';
|
import type { FormScreenField } from '../../../api/types';
|
||||||
|
|
||||||
export function SmartGridField({
|
export function SmartGridField({
|
||||||
@ -14,7 +17,14 @@ export function SmartGridField({
|
|||||||
value: Record<string, unknown>[];
|
value: Record<string, unknown>[];
|
||||||
onChange: (val: Record<string, unknown>[]) => void;
|
onChange: (val: Record<string, unknown>[]) => void;
|
||||||
}) {
|
}) {
|
||||||
const addRow = () => onChange([...value, {}]);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [newRow, setNewRow] = useState<Record<string, unknown>>({});
|
||||||
|
const [editingIdx, setEditingIdx] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const visibleColumns = columns.filter(c => {
|
||||||
|
const normalized = c.id.toLowerCase().replace(/[^a-z]/g, '');
|
||||||
|
return ['productcategory', 'productname', 'bags'].includes(normalized);
|
||||||
|
});
|
||||||
|
|
||||||
const removeRow = (idx: number) => {
|
const removeRow = (idx: number) => {
|
||||||
const next = [...value];
|
const next = [...value];
|
||||||
@ -22,9 +32,20 @@ export function SmartGridField({
|
|||||||
onChange(next);
|
onChange(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRow = (idx: number, fieldId: string, val: unknown) => {
|
const startEdit = (idx: number) => {
|
||||||
const next = [...value];
|
setEditingIdx(idx);
|
||||||
let row = { ...next[idx], [fieldId]: val };
|
setNewRow({ ...value[idx] });
|
||||||
|
setIsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const startAdd = () => {
|
||||||
|
setEditingIdx(null);
|
||||||
|
setNewRow({});
|
||||||
|
setIsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateNewRowField = (fieldId: string, val: unknown) => {
|
||||||
|
let row = { ...newRow, [fieldId]: val };
|
||||||
|
|
||||||
const colDef = columns.find(c => c.id === fieldId);
|
const colDef = columns.find(c => c.id === fieldId);
|
||||||
|
|
||||||
@ -42,7 +63,6 @@ export function SmartGridField({
|
|||||||
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) {
|
||||||
for (const key of Object.keys(option._raw)) {
|
for (const key of Object.keys(option._raw)) {
|
||||||
// Match column ID with or without underscores (e.g., brcode <-> br_code)
|
|
||||||
const targetCol = columns.find(c => c.id === key || c.id.replace(/_/g, '') === key.replace(/_/g, ''));
|
const targetCol = columns.find(c => c.id === key || c.id.replace(/_/g, '') === key.replace(/_/g, ''));
|
||||||
if (targetCol && targetCol.id !== fieldId) {
|
if (targetCol && targetCol.id !== fieldId) {
|
||||||
row[targetCol.id] = option._raw[key];
|
row[targetCol.id] = option._raw[key];
|
||||||
@ -56,90 +76,136 @@ export function SmartGridField({
|
|||||||
const bagsVal = Number(row.bags) || 0;
|
const bagsVal = Number(row.bags) || 0;
|
||||||
row.row_kgs = skuVal * bagsVal;
|
row.row_kgs = skuVal * bagsVal;
|
||||||
|
|
||||||
next[idx] = row;
|
setNewRow(row);
|
||||||
onChange(next);
|
};
|
||||||
|
|
||||||
|
const submitNewRow = () => {
|
||||||
|
if (editingIdx !== null) {
|
||||||
|
const next = [...value];
|
||||||
|
next[editingIdx] = newRow;
|
||||||
|
onChange(next);
|
||||||
|
} else {
|
||||||
|
onChange([...value, newRow]);
|
||||||
|
}
|
||||||
|
setIsModalOpen(false);
|
||||||
|
setNewRow({});
|
||||||
|
setEditingIdx(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2 font-sans border border-border-default rounded-md p-4 bg-slate-50">
|
<div className="flex flex-col gap-2 font-sans border border-border-default rounded-md p-4 bg-slate-50">
|
||||||
<span className="text-sm font-semibold text-strong mb-2">{label}</span>
|
<span className="text-sm font-semibold text-strong mb-2">{label}</span>
|
||||||
|
|
||||||
{value.length === 0 ? (
|
{value.length === 0 ? (
|
||||||
<span className="text-sm text-faint italic">No rows added.</span>
|
<span className="text-sm text-faint italic">No rows added.</span>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="overflow-x-auto">
|
||||||
{value.map((row, i) => (
|
<table className="w-full text-left border-collapse bg-white border border-border-subtle shadow-sm rounded">
|
||||||
<div key={i} className="flex flex-col gap-3 p-3 bg-white border border-border-subtle rounded relative shadow-sm">
|
<thead>
|
||||||
<div className="absolute top-2 right-2">
|
<tr className="bg-sunk border-b border-border-default">
|
||||||
<button type="button" onClick={() => removeRow(i)} className="text-xs text-ruby-600 font-medium hover:underline">
|
{visibleColumns.map(col => (
|
||||||
Remove
|
<th key={col.id} className="p-3 text-xs font-semibold text-muted uppercase tracking-wider whitespace-nowrap">
|
||||||
</button>
|
{col.name}
|
||||||
</div>
|
</th>
|
||||||
<span className="text-xs font-bold text-muted uppercase tracking-wider">Row {i + 1}</span>
|
))}
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<th className="p-3 text-xs font-semibold text-muted uppercase tracking-wider w-16"></th>
|
||||||
{columns.map(col => {
|
</tr>
|
||||||
const val = row[col.id];
|
</thead>
|
||||||
if (col.data_type === 'select' || col.data_type === 'multiselect') {
|
<tbody>
|
||||||
// Cascade filter options
|
{value.map((row, i) => (
|
||||||
const allOpts = col.properties?.options || [];
|
<tr key={i} className="border-b border-border-subtle last:border-b-0 hover:bg-slate-50/50">
|
||||||
let filteredOpts = allOpts;
|
{visibleColumns.map(col => (
|
||||||
|
<td key={col.id} className="p-3 text-sm text-strong whitespace-nowrap">
|
||||||
// Specific logic for product_name depending on product_category
|
{(() => {
|
||||||
if (col.id === 'product_name' || col.name === 'Product Name') {
|
const val = row[col.id];
|
||||||
const catCol = columns.find(c => c.id === 'product_category' || c.name === 'Product Category');
|
if (col.data_type === 'select' || col.data_type === 'multiselect') {
|
||||||
if (catCol) {
|
const opt = col.properties?.options?.find(o => String(o.value) === String(val));
|
||||||
const selectedCategory = row[catCol.id] as string;
|
return opt ? opt.label : String(val ?? '-');
|
||||||
if (selectedCategory) {
|
|
||||||
filteredOpts = allOpts.filter(opt => {
|
|
||||||
const labelStr = String(opt.label || opt.value || '');
|
|
||||||
return labelStr.startsWith(selectedCategory);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
return String(val ?? '-');
|
||||||
} else {
|
})()}
|
||||||
// Generic _raw cascading for other fields just in case
|
</td>
|
||||||
filteredOpts = allOpts.filter(opt => {
|
))}
|
||||||
if (!opt._raw) return true;
|
<td className="p-2 align-middle text-center flex items-center justify-end gap-1">
|
||||||
for (const [rowKey, rowVal] of Object.entries(row)) {
|
<button type="button" onClick={() => startEdit(i)} className="text-blue-600 hover:bg-blue-50 p-1.5 rounded transition-colors" title="Edit row">
|
||||||
if (rowKey === col.id || rowVal == null || rowVal === '') continue;
|
<Pencil size={16} />
|
||||||
const rawKey = Object.keys(opt._raw).find(rk => rk === rowKey || rk.replace(/_/g, '') === rowKey.replace(/_/g, ''));
|
</button>
|
||||||
if (rawKey && String(opt._raw[rawKey]) !== String(rowVal)) {
|
<button type="button" onClick={() => removeRow(i)} className="text-ruby-600 hover:bg-ruby-50 p-1.5 rounded transition-colors" title="Remove row">
|
||||||
return false;
|
<Trash2 size={16} />
|
||||||
}
|
</button>
|
||||||
}
|
</td>
|
||||||
return true;
|
</tr>
|
||||||
});
|
))}
|
||||||
}
|
</tbody>
|
||||||
|
</table>
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
key={col.id}
|
|
||||||
label={col.name}
|
|
||||||
required={col.mandatory}
|
|
||||||
value={(val as string) ?? ''}
|
|
||||||
onChange={(e) => updateRow(i, col.id, e.target.value)}
|
|
||||||
options={[{ value: '', label: 'Select...' }, ...filteredOpts.map((o: any) => ({ value: String(o.value), label: o.label }))]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
key={col.id}
|
|
||||||
label={col.name}
|
|
||||||
required={col.mandatory}
|
|
||||||
type={col.data_type === 'number' ? 'number' : col.data_type === 'email' ? 'email' : 'text'}
|
|
||||||
value={(val as string) ?? ''}
|
|
||||||
onChange={(e) => updateRow(i, col.id, col.data_type === 'number' ? Number(e.target.value) : e.target.value)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Button type="button" variant="secondary" size="sm" onClick={addRow} className="mt-2 self-start">
|
|
||||||
|
<Button type="button" variant="secondary" size="sm" onClick={startAdd} className="mt-2 self-start">
|
||||||
+ Add Row
|
+ Add Row
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Modal open={isModalOpen} onClose={() => setIsModalOpen(false)} title={editingIdx !== null ? "Edit Row" : "Add Row"} width="sm">
|
||||||
|
<form onSubmit={(e) => { e.preventDefault(); e.stopPropagation(); submitNewRow(); }} className="flex flex-col gap-4">
|
||||||
|
{visibleColumns.map(col => {
|
||||||
|
const val = newRow[col.id];
|
||||||
|
if (col.data_type === 'select' || col.data_type === 'multiselect') {
|
||||||
|
const allOpts = col.properties?.options || [];
|
||||||
|
let filteredOpts = allOpts;
|
||||||
|
|
||||||
|
if (col.id === 'product_name' || col.name === 'Product Name') {
|
||||||
|
const catCol = columns.find(c => c.id === 'product_category' || c.name === 'Product Category');
|
||||||
|
if (catCol) {
|
||||||
|
const selectedCategory = newRow[catCol.id] as string;
|
||||||
|
if (selectedCategory) {
|
||||||
|
filteredOpts = allOpts.filter(opt => {
|
||||||
|
const labelStr = String(opt.label || opt.value || '');
|
||||||
|
return labelStr.startsWith(selectedCategory);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filteredOpts = allOpts.filter(opt => {
|
||||||
|
if (!opt._raw) return true;
|
||||||
|
for (const [rowKey, rowVal] of Object.entries(newRow)) {
|
||||||
|
if (rowKey === col.id || rowVal == null || rowVal === '') continue;
|
||||||
|
const rawKey = Object.keys(opt._raw).find(rk => rk === rowKey || rk.replace(/_/g, '') === rowKey.replace(/_/g, ''));
|
||||||
|
if (rawKey && String(opt._raw[rawKey]) !== String(rowVal)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
key={col.id}
|
||||||
|
label={col.name}
|
||||||
|
required={col.mandatory}
|
||||||
|
value={(val as string) ?? ''}
|
||||||
|
onChange={(e) => updateNewRowField(col.id, e.target.value)}
|
||||||
|
options={[{ value: '', label: 'Select...' }, ...filteredOpts.map((o: any) => ({ value: String(o.value), label: o.label }))]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
key={col.id}
|
||||||
|
label={col.name}
|
||||||
|
required={col.mandatory}
|
||||||
|
type={col.data_type === 'number' ? 'number' : col.data_type === 'email' ? 'email' : 'text'}
|
||||||
|
value={(val as string) ?? ''}
|
||||||
|
onChange={(e) => updateNewRowField(col.id, col.data_type === 'number' ? Number(e.target.value) : e.target.value)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div className="flex justify-end gap-3 mt-4">
|
||||||
|
<Button type="button" variant="ghost" onClick={() => setIsModalOpen(false)}>Cancel</Button>
|
||||||
|
<Button type="submit" variant="primary">{editingIdx !== null ? "Save" : "Add"}</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,7 +52,7 @@ export function Modal({ open, onClose, title, subtitle, width = 'md', actions, c
|
|||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full bg-card rounded-t-2xl sm:rounded-lg border border-border-subtle shadow-lg sm:my-auto',
|
'relative w-full bg-card rounded-t-2xl sm:rounded-lg border border-border-subtle shadow-lg sm:my-auto',
|
||||||
'flex flex-col max-h-[92vh] sm:max-h-[85vh]',
|
'flex flex-col max-h-[92vh] sm:max-h-[85vh]',
|
||||||
WIDTH[width],
|
WIDTH[width],
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -16,15 +16,16 @@ export function CallsPage() {
|
|||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
const [refreshKey, setRefreshKey] = useState(0);
|
const [refreshKey, setRefreshKey] = useState(0);
|
||||||
const [activeActivity, setActiveActivity] = useState<{ id: string; name: string } | null>(null);
|
const [activeActivity, setActiveActivity] = useState<{ id: string; name: string } | null>(null);
|
||||||
|
const [isFabOpen, setIsFabOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CallsView
|
<CallsView
|
||||||
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;
|
||||||
if (id != null) navigate(`/calls/${id}`);
|
if (id != null) navigate(`/calls/${id}`);
|
||||||
}}
|
}}
|
||||||
headerActions={
|
headerActions={
|
||||||
<Button size="sm" iconLeft={<Plus size={14} />} onClick={() => setIsCreating(true)}>
|
<Button size="sm" iconLeft={<Plus size={14} />} onClick={() => setIsCreating(true)}>
|
||||||
Log Visit
|
Log Visit
|
||||||
@ -38,8 +39,8 @@ export function CallsPage() {
|
|||||||
title="Log Visit"
|
title="Log Visit"
|
||||||
width="md"
|
width="md"
|
||||||
>
|
>
|
||||||
<DynamicForm
|
<DynamicForm
|
||||||
client={orderBookingClient}
|
client={orderBookingClient}
|
||||||
activityId={ORDER_BOOKING.activities.LOG_VISIT.uid}
|
activityId={ORDER_BOOKING.activities.LOG_VISIT.uid}
|
||||||
onSuccess={() => {
|
onSuccess={() => {
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
@ -51,21 +52,33 @@ export function CallsPage() {
|
|||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
open={instanceId != null}
|
open={instanceId != null}
|
||||||
onClose={() => navigate(`/calls`)}
|
onClose={() => { navigate(`/calls`); setIsFabOpen(false); }}
|
||||||
title={instanceId != null ? `Call #${instanceId}` : undefined}
|
title={instanceId != null ? `Call #${instanceId}` : undefined}
|
||||||
width="lg"
|
width="lg"
|
||||||
actions={
|
|
||||||
<>
|
|
||||||
<Button size="sm" variant="secondary" onClick={() => setActiveActivity({ id: ORDER_BOOKING.activities.POTENTIAL_MINING.uid, name: 'Potential Mining' })}>
|
|
||||||
Potential Mining
|
|
||||||
</Button>
|
|
||||||
<Button size="sm" onClick={() => setActiveActivity({ id: ORDER_BOOKING.activities.PLACE_ORDER.uid, name: 'Place Order' })}>
|
|
||||||
Place Order
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{instanceId != null && <CallDetail instanceId={instanceId} />}
|
{instanceId != null && (
|
||||||
|
<>
|
||||||
|
<CallDetail instanceId={instanceId} />
|
||||||
|
<div className="absolute bottom-6 right-6 flex flex-col items-end gap-3 z-50">
|
||||||
|
{isFabOpen && (
|
||||||
|
<div className="flex flex-col gap-2 bg-white p-3 rounded-sm shadow-xl border border-border-subtle animate-in fade-in slide-in-from-bottom-2">
|
||||||
|
<Button size="sm" variant="secondary" onClick={() => { setActiveActivity({ id: ORDER_BOOKING.activities.POTENTIAL_MINING.uid, name: 'Potential Mining' }); setIsFabOpen(false); }}>
|
||||||
|
Potential Mining
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" onClick={() => { setActiveActivity({ id: ORDER_BOOKING.activities.PLACE_ORDER.uid, name: 'Place Order' }); setIsFabOpen(false); }}>
|
||||||
|
Place Order
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button size='fab'
|
||||||
|
className="rounded-full shadow-xl flex items-center justify-center !p-0"
|
||||||
|
onClick={() => setIsFabOpen(!isFabOpen)}
|
||||||
|
>
|
||||||
|
<Plus size={24} className={`transition-transform duration-200 ${isFabOpen ? "rotate-45" : ""}`} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@ -54,16 +54,6 @@ export function OrdersPage() {
|
|||||||
onClose={() => navigate(`/orders`)}
|
onClose={() => navigate(`/orders`)}
|
||||||
title={instanceId != null ? `Order #${instanceId}` : undefined}
|
title={instanceId != null ? `Order #${instanceId}` : undefined}
|
||||||
width="lg"
|
width="lg"
|
||||||
actions={
|
|
||||||
<>
|
|
||||||
<Button size="sm" variant="secondary" onClick={() => setActiveActivity({ id: ORDER_BOOKING.activities.POTENTIAL_MINING.uid, name: 'Potential Mining' })}>
|
|
||||||
Potential Mining
|
|
||||||
</Button>
|
|
||||||
<Button size="sm" onClick={() => setActiveActivity({ id: ORDER_BOOKING.activities.PLACE_ORDER.uid, name: 'Place Order' })}>
|
|
||||||
Place Order
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{instanceId != null && <OrderDetail instanceId={instanceId} />}
|
{instanceId != null && <OrderDetail instanceId={instanceId} />}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user