@apptimate/ui 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -9,8 +9,9 @@ import { CreditCard, Banknote, Building, Trash2, Loader2, Split, Check, AlertCir
|
|
|
9
9
|
export interface PaymentModeField {
|
|
10
10
|
key: string;
|
|
11
11
|
label: string;
|
|
12
|
-
type: "text" | "number" | "date" | "bank_account_select";
|
|
12
|
+
type: "text" | "number" | "date" | "bank_account_select" | "material_type_select";
|
|
13
13
|
required: boolean;
|
|
14
|
+
readonly?: boolean;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export interface PaymentMode {
|
|
@@ -56,11 +57,15 @@ export interface PaymentSectionProps {
|
|
|
56
57
|
fetchPaymentModes: () => Promise<{ is_success: boolean; result?: any }>;
|
|
57
58
|
/** Fetcher for bank accounts */
|
|
58
59
|
fetchBankAccounts: () => Promise<{ is_success: boolean; result?: any }>;
|
|
60
|
+
/** Optional array of material types for the material_type_select field */
|
|
61
|
+
materialTypes?: any[];
|
|
62
|
+
/** Special mode codes that are allowed (e.g. 'credit-gold') */
|
|
63
|
+
allowedSpecialModes?: string[];
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
/* ── Component ── */
|
|
62
67
|
|
|
63
|
-
export function PaymentSection({ totalAmount, payments, onPaymentsChange, compact, fetchPaymentModes, fetchBankAccounts }: PaymentSectionProps) {
|
|
68
|
+
export function PaymentSection({ totalAmount, payments, onPaymentsChange, compact, fetchPaymentModes, fetchBankAccounts, materialTypes = [], allowedSpecialModes = [] }: PaymentSectionProps) {
|
|
64
69
|
const [paymentModes, setPaymentModes] = useState<PaymentMode[]>([]);
|
|
65
70
|
const [bankAccounts, setBankAccounts] = useState<BankAccount[]>([]);
|
|
66
71
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -72,7 +77,9 @@ export function PaymentSection({ totalAmount, payments, onPaymentsChange, compac
|
|
|
72
77
|
setIsLoading(true);
|
|
73
78
|
try {
|
|
74
79
|
const [modesRes, bankRes] = await Promise.all([fetchPaymentModes(), fetchBankAccounts()]);
|
|
75
|
-
const
|
|
80
|
+
const modesRaw: PaymentMode[] = modesRes.is_success ? (modesRes.result || []) : [];
|
|
81
|
+
const SPECIAL_MODES = ["credit-gold"];
|
|
82
|
+
const modes = modesRaw.filter((m) => !SPECIAL_MODES.includes(m.code) || allowedSpecialModes.includes(m.code));
|
|
76
83
|
setPaymentModes(modes);
|
|
77
84
|
if (bankRes.is_success) setBankAccounts(bankRes.result || []);
|
|
78
85
|
|
|
@@ -98,12 +105,12 @@ export function PaymentSection({ totalAmount, payments, onPaymentsChange, compac
|
|
|
98
105
|
const balance = useMemo(() => totalAmount - totalPaid, [totalAmount, totalPaid]);
|
|
99
106
|
const formatCurrency = (v: number) => v.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
100
107
|
|
|
101
|
-
// ── Mode icon ──
|
|
102
108
|
const getModeIcon = useCallback((code: string, size = 14) => {
|
|
103
109
|
switch (code) {
|
|
104
110
|
case "cash": return <Banknote size={size} />;
|
|
105
111
|
case "card": return <CreditCard size={size} />;
|
|
106
112
|
case "bank_transfer": return <Building size={size} />;
|
|
113
|
+
case "credit-gold": return <AlertCircle size={size} />; // Fallback, better to use something else if available
|
|
107
114
|
default: return <CreditCard size={size} />;
|
|
108
115
|
}
|
|
109
116
|
}, []);
|
|
@@ -219,7 +226,7 @@ export function PaymentSection({ totalAmount, payments, onPaymentsChange, compac
|
|
|
219
226
|
{/* ── Single Mode: Entry with fields (no delete) ── */}
|
|
220
227
|
{selectionMode === "single" && payments.length === 1 && (
|
|
221
228
|
<PaymentEntryRow entry={payments[0]} mode={paymentModes.find((m) => m.id === payments[0].mode_id)}
|
|
222
|
-
bankAccounts={bankAccounts} onUpdate={(updates) => updatePayment(0, updates)} onRemove={() => {}} showRemove={false} />
|
|
229
|
+
bankAccounts={bankAccounts} materialTypes={materialTypes} onUpdate={(updates) => updatePayment(0, updates)} onRemove={() => {}} showRemove={false} />
|
|
223
230
|
)}
|
|
224
231
|
|
|
225
232
|
{/* ── Split Mode: Multi-entry UI ── */}
|
|
@@ -228,7 +235,7 @@ export function PaymentSection({ totalAmount, payments, onPaymentsChange, compac
|
|
|
228
235
|
{payments.map((entry, idx) => {
|
|
229
236
|
const mode = paymentModes.find((m) => m.id === entry.mode_id);
|
|
230
237
|
return (
|
|
231
|
-
<PaymentEntryRow key={idx} entry={entry} mode={mode} bankAccounts={bankAccounts}
|
|
238
|
+
<PaymentEntryRow key={idx} entry={entry} mode={mode} bankAccounts={bankAccounts} materialTypes={materialTypes}
|
|
232
239
|
onUpdate={(updates) => updatePayment(idx, updates)} onRemove={() => removePayment(idx)} />
|
|
233
240
|
);
|
|
234
241
|
})}
|
|
@@ -299,12 +306,13 @@ interface PaymentEntryRowProps {
|
|
|
299
306
|
entry: PaymentEntry;
|
|
300
307
|
mode?: PaymentMode;
|
|
301
308
|
bankAccounts: BankAccount[];
|
|
309
|
+
materialTypes?: any[];
|
|
302
310
|
onUpdate: (updates: Partial<PaymentEntry>) => void;
|
|
303
311
|
onRemove: () => void;
|
|
304
312
|
showRemove?: boolean;
|
|
305
313
|
}
|
|
306
314
|
|
|
307
|
-
function PaymentEntryRow({ entry, mode, bankAccounts, onUpdate, onRemove, showRemove = true }: PaymentEntryRowProps) {
|
|
315
|
+
function PaymentEntryRow({ entry, mode, bankAccounts, materialTypes = [], onUpdate, onRemove, showRemove = true }: PaymentEntryRowProps) {
|
|
308
316
|
const fields = mode?.field_config?.fields || [];
|
|
309
317
|
|
|
310
318
|
const getModeIcon = () => {
|
|
@@ -312,6 +320,7 @@ function PaymentEntryRow({ entry, mode, bankAccounts, onUpdate, onRemove, showRe
|
|
|
312
320
|
case "cash": return <Banknote size={13} />;
|
|
313
321
|
case "card": return <CreditCard size={13} />;
|
|
314
322
|
case "bank_transfer": return <Building size={13} />;
|
|
323
|
+
case "credit-gold": return <AlertCircle size={13} />;
|
|
315
324
|
default: return <CreditCard size={13} />;
|
|
316
325
|
}
|
|
317
326
|
};
|
|
@@ -352,15 +361,26 @@ function PaymentEntryRow({ entry, mode, bankAccounts, onUpdate, onRemove, showRe
|
|
|
352
361
|
{field.type === "bank_account_select" ? (
|
|
353
362
|
<select value={entry.metadata[field.key] || ""}
|
|
354
363
|
onChange={(e) => onUpdate({ metadata: { ...entry.metadata, [field.key]: e.target.value ? Number(e.target.value) : "" } })}
|
|
355
|
-
|
|
364
|
+
disabled={field.readonly}
|
|
365
|
+
className="w-full bg-surface-1 border-[1.5px] border-border-subtle rounded-[8px] px-2.5 py-2.5 text-[12px] text-foreground-1 outline-none focus:border-primary/40 transition-all disabled:opacity-50 disabled:cursor-not-allowed">
|
|
356
366
|
<option value="">Select...</option>
|
|
357
367
|
{bankAccounts.map((b) => (<option key={b.id} value={b.id}>{b.bank_name} - {b.account_number}</option>))}
|
|
358
368
|
</select>
|
|
369
|
+
) : field.type === "material_type_select" ? (
|
|
370
|
+
<select value={entry.metadata[field.key] || ""}
|
|
371
|
+
onChange={(e) => onUpdate({ metadata: { ...entry.metadata, [field.key]: e.target.value ? Number(e.target.value) : "" } })}
|
|
372
|
+
disabled={field.readonly}
|
|
373
|
+
className="w-full bg-surface-1 border-[1.5px] border-border-subtle rounded-[8px] px-2.5 py-2.5 text-[12px] text-foreground-1 outline-none focus:border-primary/40 transition-all disabled:opacity-50 disabled:cursor-not-allowed">
|
|
374
|
+
<option value="">Select Material...</option>
|
|
375
|
+
{materialTypes.map((m) => (<option key={m.id} value={m.id}>{m.name}</option>))}
|
|
376
|
+
</select>
|
|
359
377
|
) : (
|
|
360
378
|
<input type={field.type === "number" ? "number" : field.type === "date" ? "date" : "text"}
|
|
379
|
+
{...(field.type === "number" ? { step: "any" } : {})}
|
|
361
380
|
value={entry.metadata[field.key] || ""}
|
|
362
381
|
onChange={(e) => onUpdate({ metadata: { ...entry.metadata, [field.key]: e.target.value } })}
|
|
363
|
-
|
|
382
|
+
readOnly={field.readonly}
|
|
383
|
+
className={cn("w-full bg-surface-1 border-[1.5px] border-border-subtle rounded-[8px] px-2.5 py-2.5 text-[12px] text-foreground-1 outline-none focus:border-primary/40 transition-all [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none", field.readonly && "opacity-60 bg-surface-0 cursor-not-allowed border-border")} />
|
|
364
384
|
)}
|
|
365
385
|
</div>
|
|
366
386
|
))}
|