EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
page.tsx
Go to the documentation of this file.
1'use client';
2
3import React, { useState, useEffect } from 'react';
4import { Icon } from '@/contexts/IconContext';
5
6interface PaymentType {
7 Code: number;
8 CustSpell: string;
9 OnlineFlags: number;
10 GlobalCode?: number;
11 RateBuy?: string;
12 ForeignChangeDt?: string;
13 Deleted?: number;
14 PrintOnReceipts?: number;
15 OpenCashDrawer?: number;
16 AffectsCash?: number;
17 IssuesChange?: number;
18 ObeysRounding?: number;
19 AccountDebit?: number;
20 AccountCredit?: number;
21 RewardLinked?: number;
22 SVC?: number;
23 NoLoyalty?: number;
24 ItemiseEOD?: number;
25 NegativeEffect?: number;
26 Invisible?: number;
27}
28
29interface Membership {
30 MembershipKey: string;
31 Name: string;
32 AmOwner: boolean;
33}
34
35interface PaymentSetting {
36 KeyName: string;
37 Value: string;
38 MembershipKey: string;
39}
40
41interface PredefinedPaymentType {
42 id: number;
43 name: string;
44 description?: string;
45 link?: string;
46 warning?: string;
47}
48
49export default function PaymentTypesPage() {
50 const [paymentTypes, setPaymentTypes] = useState<PaymentType[]>([]);
51 const [memberships, setMemberships] = useState<Membership[]>([]);
52 const [paymentSettings, setPaymentSettings] = useState<PaymentSetting[]>([]);
53 const [foreignEnabled, setForeignEnabled] = useState(false);
54 const [editingPaymentType, setEditingPaymentType] = useState<PaymentType | null>(null);
55 const [showEditModal, setShowEditModal] = useState(false);
56 const [showAddModal, setShowAddModal] = useState(false);
57 const [addingPaymentType, setAddingPaymentType] = useState<PredefinedPaymentType | null>(null);
58 const [laybuyMerchRef, setLaybuyMerchRef] = useState('');
59 const [laybuyApiKey, setLaybuyApiKey] = useState('');
60
61 useEffect(() => {
62 loadData();
63 }, []);
64
65 const loadData = async () => {
66 try {
67 // Load payment types
68 // const response = await fetch('/api/payment-types');
69 // const data = await response.json();
70 // setPaymentTypes(data);
71
72 // Mock data for demonstration
73 const mockPaymentTypes: PaymentType[] = [
74 { Code: 1, CustSpell: 'Cash', OnlineFlags: 0, GlobalCode: 1, PrintOnReceipts: 1, OpenCashDrawer: 1, AffectsCash: 1, IssuesChange: 1, ObeysRounding: 1 },
75 { Code: 2, CustSpell: 'Cheque', OnlineFlags: 0, GlobalCode: 2, PrintOnReceipts: 1, ItemiseEOD: 1 },
76 { Code: 3, CustSpell: 'EFTPOS', OnlineFlags: 0, GlobalCode: 3, PrintOnReceipts: 1, ItemiseEOD: 1 },
77 { Code: 4, CustSpell: 'Verified Cheque', OnlineFlags: 0, GlobalCode: 4, PrintOnReceipts: 1 },
78 { Code: 5, CustSpell: 'EFTPOS failure', OnlineFlags: 0, GlobalCode: 5 },
79 { Code: 6, CustSpell: 'Change', OnlineFlags: 0, GlobalCode: 6 },
80 { Code: 7, CustSpell: 'Rounding', OnlineFlags: 0, GlobalCode: 7 },
81 { Code: 8, CustSpell: 'Return Refund', OnlineFlags: 0, GlobalCode: 8 },
82 { Code: 9, CustSpell: 'Credit Card', OnlineFlags: 0, GlobalCode: 9, PrintOnReceipts: 1, ItemiseEOD: 1 },
83 { Code: 10, CustSpell: 'Credit Card failure', OnlineFlags: 0, GlobalCode: 10 },
84 { Code: 11, CustSpell: 'Sale discount', OnlineFlags: 0, GlobalCode: 11 },
85 { Code: 20, CustSpell: 'Account', OnlineFlags: 0, GlobalCode: 200, PrintOnReceipts: 1, AccountDebit: 1 },
86 { Code: 21, CustSpell: 'Voucher', OnlineFlags: 0 },
87 { Code: 22, CustSpell: 'Direct Debit', OnlineFlags: 0 },
88 ];
89 setPaymentTypes(mockPaymentTypes);
90
91 // Load memberships
92 const mockMemberships: Membership[] = [
93 { MembershipKey: 'membership1', Name: 'Agency', AmOwner: true }
94 ];
95 setMemberships(mockMemberships);
96
97 // Load payment settings
98 setPaymentSettings([]);
99
100 // Load foreign currency setting
101 setForeignEnabled(false);
102
103 } catch (error) {
104 console.error('Error loading payment types:', error);
105 }
106 };
107
108 const canEnableOnline = (paymentType: PaymentType): boolean => {
109 const disabledCodes = [5, 6, 7, 8, 10, 11];
110 const disabledGlobalCodes = [164001];
111
112 if (disabledCodes.includes(paymentType.Code)) return false;
113 if (paymentType.GlobalCode && disabledGlobalCodes.includes(paymentType.GlobalCode)) return false;
114
115 return true;
116 };
117
118 const handleToggleOnline = (index: number) => {
119 const paymentType = paymentTypes[index];
120 const newValue = paymentType.OnlineFlags ? 0 : 1;
121
122 console.log('Toggle online for payment type:', paymentType.Code, 'to', newValue);
123
124 // Update local state
125 const updated = [...paymentTypes];
126 updated[index] = { ...updated[index], OnlineFlags: newValue };
127 setPaymentTypes(updated);
128
129 // Save to API
130 // API call would go here
131 };
132
133 const handleSaveRate = (paymentTypeId: number, index: number, value: string) => {
134 const paymentType = paymentTypes[index];
135 if (paymentType.RateBuy === value) return;
136
137 console.log('Save rate for payment type:', paymentTypeId, 'value:', value);
138
139 // Update local state
140 const updated = [...paymentTypes];
141 updated[index] = { ...updated[index], RateBuy: value };
142 setPaymentTypes(updated);
143
144 // Save to API
145 };
146
147 const handleEditSettings = (index: number) => {
148 setEditingPaymentType(paymentTypes[index]);
149 setShowEditModal(true);
150 };
151
152 const handleSaveSettings = () => {
153 if (!editingPaymentType) return;
154
155 console.log('Saving payment type settings:', editingPaymentType);
156
157 // Update in list
158 const index = paymentTypes.findIndex(pt => pt.Code === editingPaymentType.Code);
159 if (index >= 0) {
160 const updated = [...paymentTypes];
161 updated[index] = editingPaymentType;
162 setPaymentTypes(updated);
163 }
164
165 // Save to API
166 setShowEditModal(false);
167 setEditingPaymentType(null);
168 };
169
170 const handleToggleMembership = (globalCode: number, membershipIndex: number, checked: boolean) => {
171 console.log('Toggle membership:', globalCode, membershipIndex, checked);
172 // Save to API
173 };
174
175 const handleAddPaymentType = (paymentType: PredefinedPaymentType) => {
176 if (paymentType.id === 164001) {
177 // Special handling for Laybuy
178 const existing = paymentTypes.find(pt => pt.GlobalCode === 164001);
179 if (existing) {
180 setLaybuyMerchRef(existing.Code.toString()); // This would be Interface1
181 setLaybuyApiKey(''); // This would be Interface2
182 }
183 setAddingPaymentType(paymentType);
184 setShowAddModal(true);
185 } else {
186 // Check if foreign currency and not enabled
187 if (!foreignEnabled && paymentType.id >= 300000 && paymentType.id <= 399999) {
188 alert('Please enable foreign currency handling before attempting to add foreign currency payment types');
189 return;
190 }
191
192 setAddingPaymentType(paymentType);
193 setShowAddModal(true);
194 }
195 };
196
197 const confirmAddPaymentType = () => {
198 if (!addingPaymentType) return;
199
200 console.log('Adding payment type:', addingPaymentType);
201
202 // Add to API
203 setShowAddModal(false);
204 setAddingPaymentType(null);
205
206 // Reload data
207 loadData();
208 };
209
210 const handleSaveLaybuy = () => {
211 if (laybuyMerchRef.length < 4) {
212 alert('A merchant reference is required');
213 return;
214 }
215 if (laybuyApiKey.length < 4) {
216 alert('An API Key is required');
217 return;
218 }
219
220 console.log('Saving Laybuy settings:', { laybuyMerchRef, laybuyApiKey });
221
222 // Save to API
223 setShowAddModal(false);
224 setLaybuyMerchRef('');
225 setLaybuyApiKey('');
226
227 // Reload data
228 loadData();
229 };
230
231 const predefinedPaymentTypes: PredefinedPaymentType[] = [
232 { id: 161001, name: 'ZipPay' },
233 { id: 164001, name: 'Laybuy.com', link: 'https://laybuy.com' },
234 { id: 164002, name: 'Farmlands Card' },
235 { id: 164003, name: 'Ruralco Card' },
236 { id: 164004, name: 'MTA Voucher' },
237 { id: 164005, name: 'C.R.T.' },
238 { id: 164006, name: 'TradeMe Ping' },
239 { id: 564000, name: 'Web Sale', description: 'Externally paid web sale' },
240 { id: 164007, name: 'Bartercard (NZ)' },
241 { id: 164008, name: 'Genoapay (NZ)' },
242 { id: 164009, name: 'Gem Finance (NZ)' },
243 { id: 200100, name: 'Direct Bank Transfer' },
244 { id: 200101, name: 'Manual Eftpos' },
245 { id: 200102, name: 'AMEX' },
246 { id: 200103, name: 'Diners' },
247 { id: 200104, name: 'Union Pay' },
248 { id: 200105, name: 'Agency Payment' },
249 { id: 200106, name: 'WeChat Pay' },
250 { id: 200107, name: 'Alipay' },
251 { id: 200108, name: 'PxPay' },
252 { id: 200114, name: 'PxFusion' },
253 { id: 200115, name: 'Store Discount Voucher', warning: 'This payment type has side effects with sales handling. Check documentation' },
254 { id: 200109, name: 'Windcave', description: 'Manual Entry' },
255 { id: 200111, name: 'Manual Customer Credit' },
256 { id: 200112, name: 'Shopify' },
257 { id: 200113, name: 'EAN-99 Coupon', description: 'Reserved for manufacturer cash off coupons' },
258 { id: 200120, name: 'Wise.com NZ$', link: 'https://wise.com' },
259 { id: 200121, name: 'Wise.com AU$', link: 'https://wise.com' },
260 { id: 200122, name: 'Wise.com UK£', link: 'https://wise.com' },
261 { id: 200123, name: 'Wise.com CAD$', link: 'https://wise.com' },
262 { id: 200124, name: 'Wise.com Euro €', link: 'https://wise.com' },
263 { id: 200125, name: 'Wise.com US$', link: 'https://wise.com' },
264 { id: 200130, name: 'PayPal' },
265 ];
266
267 const foreignCurrencyTypes: PredefinedPaymentType[] = [
268 { id: 300062, name: 'Australian Dollar' },
269 { id: 309001, name: 'Canadian Dollar' },
270 { id: 309997, name: 'Euro' },
271 { id: 300081, name: 'Japanese Yen' },
272 { id: 300044, name: 'UK Pound' },
273 { id: 300001, name: 'US Dollars' },
274 ];
275
276 const isPaymentTypeAdded = (id: number): boolean => {
277 return paymentTypes.some(pt => pt.GlobalCode === id || pt.Code === id);
278 };
279
280 const formatDateTime = (dateStr?: string) => {
281 if (!dateStr) return '';
282 const date = new Date(dateStr);
283 return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
284 };
285
286 return (
287 <div className="min-h-screen bg-bg">
288 {/* Header */}
289 <div className="bg-brand text-surface px-6 py-4 shadow-lg">
290 <div className="flex items-center gap-4">
291 <div className="text-sm">
292 <a href="/pages/settings" className="hover:underline">Settings</a>
293 <span className="mx-2">›</span>
294 <span>Payment Types</span>
295 </div>
296 </div>
297 </div>
298
299 <div className="max-w-[1600px] mx-auto p-6">
300 {/* Page Title */}
301 <div className="mb-6">
302 <h1 className="text-3xl font-bold text-text mb-2 flex items-center gap-3">
303 <Icon name="payments" size={32} className="text-brand" />
304 Configure Payment Types
305 </h1>
306 <div className="text-sm text-muted">
307 <a href="https://fieldpine.com/docs/database/db_r_paymenttypes.htm" target="_blank" className="text-brand hover:underline">
308 Database structure (technical)
309 </a>
310 </div>
311 </div>
312
313 {/* Current Payment Types */}
314 <div className="bg-surface rounded-lg shadow-md p-6 mb-8">
315 <h2 className="text-xl font-bold text-text mb-4">Current Payment Types</h2>
316
317 <div className="overflow-x-auto">
318 <table className="min-w-full border-collapse">
319 <thead>
320 <tr className="bg-surface-2 border-b-2 border-border">
321 <th className="px-4 py-3 text-left text-sm font-semibold text-text">ID</th>
322 <th className="px-4 py-3 text-left text-sm font-semibold text-text">Description</th>
323 <th className="px-4 py-3 text-left text-sm font-semibold text-text">Fieldpine Online Enabled</th>
324 {foreignEnabled && <th className="px-4 py-3 text-left text-sm font-semibold text-text">Rate Buy</th>}
325 <th className="px-4 py-3 text-left text-sm font-semibold text-text">Options</th>
326 <th className="px-4 py-3 text-left text-sm font-semibold text-text">Notes</th>
327 <th className="px-4 py-3 text-left text-sm font-semibold text-text">GlobalCode</th>
328 {memberships.map((membership, idx) => (
329 <th key={idx} className="px-4 py-3 text-left text-sm font-semibold text-text">
330 Publish to<br />Membership:<br />{membership.Name}
331 </th>
332 ))}
333 </tr>
334 </thead>
335 <tbody>
336 {paymentTypes.map((paymentType, index) => {
337 const canEnable = canEnableOnline(paymentType);
338 const notes: string[] = [];
339 if (paymentType.GlobalCode === 164001) notes.push('Not supported by Fieldpine Online');
340 if (paymentType.Deleted) notes.push('Deleted');
341
342 return (
343 <tr key={paymentType.Code} className="border-b border-border hover:bg-surface-2">
344 <td className="px-4 py-3 text-sm text-muted">{paymentType.Code}</td>
345 <td className="px-4 py-3 text-sm font-medium text-text">{paymentType.CustSpell}</td>
346 <td className="px-4 py-3">
347 {canEnable ? (
348 <label className="relative inline-flex items-center cursor-pointer">
349 <input
350 type="checkbox"
351 className="sr-only peer"
352 checked={paymentType.OnlineFlags === 1}
353 onChange={() => handleToggleOnline(index)}
354 />
355 <div className="w-11 h-6 bg-surface-2 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-surface after:border-border after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand"></div>
356 </label>
357 ) : null}
358 </td>
359 {foreignEnabled && (
360 <td className="px-4 py-3">
361 {paymentType.Code >= 300000 && paymentType.Code <= 399999 ? (
362 <div>
363 <input
364 type="text"
365 size={8}
366 value={paymentType.RateBuy || ''}
367 onChange={(e) => {
368 const updated = [...paymentTypes];
369 updated[index] = { ...updated[index], RateBuy: e.target.value };
370 setPaymentTypes(updated);
371 }}
372 onBlur={(e) => handleSaveRate(paymentType.Code, index, e.target.value)}
373 className="border border-border rounded px-2 py-1 text-sm"
374 />
375 <div className="text-xs text-muted mt-1">
376 {formatDateTime(paymentType.ForeignChangeDt)}
377 </div>
378 </div>
379 ) : null}
380 </td>
381 )}
382 <td className="px-4 py-3">
383 <button
384 onClick={() => handleEditSettings(index)}
385 className="px-3 py-1 bg-brand text-surface rounded hover:bg-brand2 text-sm"
386 >
387 Settings
388 </button>
389 </td>
390 <td className="px-4 py-3 text-sm text-muted">{notes.join('; ')}</td>
391 <td className="px-4 py-3 text-sm text-muted">{paymentType.GlobalCode || ''}</td>
392 {memberships.map((membership, mIdx) => (
393 <td key={mIdx} className="px-4 py-3">
394 {paymentType.GlobalCode ? (
395 <label className="flex items-center">
396 <input
397 type="checkbox"
398 onChange={(e) => handleToggleMembership(paymentType.GlobalCode!, mIdx, e.target.checked)}
399 className="w-4 h-4 text-brand border-border rounded focus:ring-brand"
400 />
401 <span className="ml-2 text-sm">Publish</span>
402 </label>
403 ) : null}
404 </td>
405 ))}
406 </tr>
407 );
408 })}
409 </tbody>
410 </table>
411 </div>
412 </div>
413
414 {/* Add New Payment Types */}
415 <div className="bg-surface rounded-lg shadow-md p-6 mb-8">
416 <h2 className="text-xl font-bold text-text mb-4">Enable New Payment Types</h2>
417
418 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
419 {predefinedPaymentTypes.filter(pt => !isPaymentTypeAdded(pt.id)).map(paymentType => (
420 <div key={paymentType.id} className="border border-border rounded-lg p-4 hover:shadow-md transition-shadow cursor-pointer">
421 <button
422 onClick={() => handleAddPaymentType(paymentType)}
423 className="text-[#00946b] hover:text-[#00543b] font-medium text-left w-full cursor-pointer"
424 >
425 {paymentType.name}
426 {paymentType.description && <div className="text-sm text-muted mt-1">{paymentType.description}</div>}
427 </button>
428 {paymentType.link && (
429 <div className="mt-2">
430 <a href={paymentType.link} target="_blank" className="text-xs text-[#00946b] hover:underline">
431 Visit {paymentType.name}
432 </a>
433 </div>
434 )}
435 <div className="text-xs text-muted mt-2">(#{paymentType.id})</div>
436 </div>
437 ))}
438 </div>
439
440 <p className="text-sm text-muted mt-6">
441 Need a new payment type added? Payment types are allocated by Fieldpine to ensure reports can properly classify them.
442 If you need a new payment type, please contact your Fieldpine agent to request it be added.
443 </p>
444 </div>
445
446 {/* Foreign Currency */}
447 <div className="bg-surface rounded-lg shadow-md p-6">
448 <h3 className="text-lg font-bold text-text mb-4">Foreign Currency</h3>
449
450 <p className="text-sm text-muted mb-4">
451 Enable foreign currency only when you accept these as <u>cash</u> and they are <em>not</em> the normal currency in your country
452 </p>
453
454 <div className="flex items-start gap-4 mb-6">
455 <label className="relative inline-flex items-center cursor-pointer">
456 <input
457 type="checkbox"
458 className="sr-only peer"
459 checked={foreignEnabled}
460 onChange={(e) => setForeignEnabled(e.target.checked)}
461 />
462 <div className="w-11 h-6 bg-surface-2 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-surface after:border-border after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand"></div>
463 </label>
464 <div>
465 <div className="font-medium text-text">Enable Foreign Currency Handling</div>
466 <div className="text-sm text-muted">You may need to manually maintain exchange rates for the POS to use.</div>
467 </div>
468 </div>
469
470 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
471 {foreignCurrencyTypes.filter(pt => !isPaymentTypeAdded(pt.id)).map(paymentType => (
472 <div key={paymentType.id} className="border border-border rounded-lg p-4 hover:shadow-md transition-shadow cursor-pointer">
473 <button
474 onClick={() => handleAddPaymentType(paymentType)}
475 className="text-[#00946b] hover:text-[#00543b] font-medium text-left w-full cursor-pointer"
476 disabled={!foreignEnabled}
477 >
478 {paymentType.name}
479 </button>
480 <div className="text-xs text-muted mt-2">(#{paymentType.id})</div>
481 </div>
482 ))}
483 </div>
484 </div>
485 </div>
486
487 {/* Edit Settings Modal */}
488 {showEditModal && editingPaymentType && (
489 <div className="fixed inset-0 bg-black/30 backdrop-blur-sm flex items-center justify-center z-50 p-4">
490 <div className="bg-surface/95 rounded-lg shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
491 <div className="sticky top-0 bg-brand text-surface px-6 py-4 flex items-center justify-between rounded-t-lg">
492 <h2 className="text-xl font-bold">{editingPaymentType.CustSpell}</h2>
493 <button onClick={() => setShowEditModal(false)} className="text-surface hover:text-muted/70">
494 <Icon name="close" size={24} />
495 </button>
496 </div>
497
498 <div className="p-6">
499 <table className="w-full">
500 <tbody>
501 {[
502 { key: 'PrintOnReceipts', label: 'Printed on receipts' },
503 { key: 'OpenCashDrawer', label: 'Open Cash drawer' },
504 { key: 'AffectsCash', label: 'Affects Cash' },
505 { key: 'IssuesChange', label: 'Issues Change' },
506 { key: 'ObeysRounding', label: 'Obeys rounding rules' },
507 { key: 'AccountDebit', label: 'Account debit' },
508 { key: 'AccountCredit', label: 'Account credit' },
509 { key: 'RewardLinked', label: 'Reward linked' },
510 { key: 'SVC', label: 'Prepay' },
511 { key: 'NoLoyalty', label: 'No loyalty' },
512 { key: 'ItemiseEOD', label: 'Itemise on end of day' },
513 { key: 'NegativeEffect', label: 'Negative sale effect' },
514 { key: 'Invisible', label: 'Hidden/Invisible' },
515 { key: 'Deleted', label: 'Deleted' },
516 ].map(field => (
517 <tr key={field.key}>
518 <td className="py-2 pr-4 text-text">{field.label}</td>
519 <td className="py-2">
520 <input
521 type="checkbox"
522 checked={(editingPaymentType as any)[field.key] === 1}
523 onChange={(e) => {
524 setEditingPaymentType({
525 ...editingPaymentType,
526 [field.key]: e.target.checked ? 1 : 0
527 });
528 }}
529 className="w-4 h-4 text-[#00946b] border-border rounded focus:ring-[#00946b]"
530 />
531 </td>
532 </tr>
533 ))}
534 <tr>
535 <td className="py-2 pr-4 text-text">Global Code</td>
536 <td className="py-2">
537 <input
538 type="text"
539 size={8}
540 value={editingPaymentType.GlobalCode || ''}
541 onChange={(e) => setEditingPaymentType({ ...editingPaymentType, GlobalCode: Number(e.target.value) || undefined })}
542 className="border border-border rounded px-2 py-1 text-sm"
543 />
544 </td>
545 </tr>
546 </tbody>
547 </table>
548
549 <div className="mt-6 flex gap-3">
550 <button
551 onClick={handleSaveSettings}
552 className="px-6 py-2 bg-brand text-surface rounded hover:bg-brand2 font-medium flex items-center gap-2"
553 >
554 <Icon name="save" size={18} />
555 Save Changes
556 </button>
557 <button
558 onClick={() => setShowEditModal(false)}
559 className="px-6 py-2 bg-surface-2 text-text rounded hover:bg-surface-2/80 font-medium"
560 >
561 Cancel
562 </button>
563 </div>
564 </div>
565 </div>
566 </div>
567 )}
568
569 {/* Add Payment Type Modal */}
570 {showAddModal && addingPaymentType && (
571 <div className="fixed inset-0 bg-black/30 backdrop-blur-sm flex items-center justify-center z-50 p-4">
572 <div className="bg-surface/95 rounded-lg shadow-2xl max-w-2xl w-full">
573 <div className="sticky top-0 bg-brand text-surface px-6 py-4 flex items-center justify-between rounded-t-lg">
574 <h2 className="text-xl font-bold">{addingPaymentType.name}</h2>
575 <button onClick={() => setShowAddModal(false)} className="text-surface hover:text-muted/70">
576 <Icon name="close" size={24} />
577 </button>
578 </div>
579
580 <div className="p-6">
581 {addingPaymentType.id === 164001 ? (
582 // Laybuy special form
583 <>
584 <p className="mb-4 text-text">
585 Laybuy.com allows customers to purchase using a hire purchase like system.
586 You need to register with Laybuy.com and enter your details below.
587 </p>
588 <table className="w-full mb-4">
589 <tbody>
590 <tr>
591 <td className="py-2 pr-4 text-text">Merchant Reference</td>
592 <td className="py-2">
593 <input
594 type="text"
595 size={12}
596 value={laybuyMerchRef}
597 onChange={(e) => setLaybuyMerchRef(e.target.value)}
598 className="border border-border rounded px-3 py-1"
599 />
600 </td>
601 </tr>
602 <tr>
603 <td className="py-2 pr-4 text-text">API Key</td>
604 <td className="py-2">
605 <input
606 type="text"
607 size={70}
608 value={laybuyApiKey}
609 onChange={(e) => setLaybuyApiKey(e.target.value)}
610 className="border border-border rounded px-3 py-1 w-full"
611 />
612 </td>
613 </tr>
614 </tbody>
615 </table>
616 <div className="flex gap-3">
617 <button
618 onClick={handleSaveLaybuy}
619 className="px-6 py-2 bg-brand text-surface rounded hover:bg-brand2 font-medium flex items-center gap-2"
620 >
621 <Icon name="save" size={18} />
622 Save
623 </button>
624 <button
625 onClick={() => setShowAddModal(false)}
626 className="px-6 py-2 bg-surface-2 text-text rounded hover:bg-surface-2/80 font-medium"
627 >
628 Cancel
629 </button>
630 </div>
631 </>
632 ) : (
633 // Standard add confirmation
634 <>
635 <p className="mb-4 text-text">
636 Confirm to add payment type #{addingPaymentType.id} of "{addingPaymentType.name}"
637 </p>
638 {addingPaymentType.warning && (
639 <p className="mb-4 text-red-600 font-bold">{addingPaymentType.warning}</p>
640 )}
641 {addingPaymentType.id >= 300000 && addingPaymentType.id <= 399999 && (
642 <p className="mb-4 text-text">
643 This payment type is a foreign currency type.<br />
644 It should only be added when this is <em>not</em> the primary currency in your country.
645 </p>
646 )}
647 <div className="flex gap-3">
648 <button
649 onClick={confirmAddPaymentType}
650 className="px-6 py-2 bg-brand text-surface rounded hover:bg-brand2 font-medium flex items-center gap-2"
651 >
652 <Icon name="check" size={18} />
653 Yes. Add this payment type
654 </button>
655 <button
656 onClick={() => setShowAddModal(false)}
657 className="px-6 py-2 bg-surface-2 text-text rounded hover:bg-surface-2/80 font-medium"
658 >
659 Cancel
660 </button>
661 </div>
662 </>
663 )}
664 </div>
665 </div>
666 </div>
667 )}
668 </div>
669 );
670}