mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 22:25:42 +00:00
83 lines
4.0 KiB
TypeScript
83 lines
4.0 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { PlusCircle } from 'lucide-react';
|
|
import Modal from '@/components/ui/Modal';
|
|
import ActionButton from '@/components/ui/ActionButton';
|
|
import { useCreateSupplementaryCharge } from './useSupplementaryCharges';
|
|
|
|
const REASONS = ['UNDERPAYMENT', 'FARE_CORRECTION', 'CURRENCY_ADJUSTMENT', 'OTHER'];
|
|
|
|
interface Props {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function SupplementaryChargesModal({ isOpen, onClose }: Props) {
|
|
const [form, setForm] = useState({ bookingRef: '', amountEtb: '', reason: 'UNDERPAYMENT', notes: '' });
|
|
const [formError, setFormError] = useState<string | null>(null);
|
|
const [createSuccess, setCreateSuccess] = useState<string | null>(null);
|
|
|
|
const createMutation = useCreateSupplementaryCharge(() => {
|
|
setCreateSuccess('Charge created and payment link sent.');
|
|
setForm({ bookingRef: '', amountEtb: '', reason: 'UNDERPAYMENT', notes: '' });
|
|
setFormError(null);
|
|
setTimeout(() => { setCreateSuccess(null); onClose(); }, 2000);
|
|
});
|
|
|
|
const handleCreate = async () => {
|
|
setFormError(null);
|
|
const amountMinor = Math.round(parseFloat(form.amountEtb) * 100);
|
|
if (!form.bookingRef.trim()) return setFormError('Booking reference is required');
|
|
if (!form.amountEtb || isNaN(amountMinor) || amountMinor <= 0) return setFormError('Enter a valid amount');
|
|
try {
|
|
await createMutation.mutateAsync({ bookingRef: form.bookingRef.trim(), amountMinor, reason: form.reason, notes: form.notes || undefined });
|
|
} catch (e: any) {
|
|
setFormError(e?.response?.data?.message ?? e?.message ?? 'Failed to create charge');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Modal isOpen={isOpen} onClose={onClose} title="Raise Supplementary Charge" size="lg">
|
|
<div className="space-y-4">
|
|
{createSuccess && (
|
|
<div className="rounded-lg bg-green-50 dark:bg-green-900/20 p-3 text-sm text-green-800 dark:text-green-200">✓ {createSuccess}</div>
|
|
)}
|
|
{formError && (
|
|
<div className="rounded-lg bg-red-50 dark:bg-red-900/20 p-3 text-sm text-red-700 dark:text-red-300">{formError}</div>
|
|
)}
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="md:col-span-2">
|
|
<label className="label">Booking Reference <span className="text-red-500">*</span></label>
|
|
<input className="input" placeholder="e.g. EDR-20240001" value={form.bookingRef} onChange={(e) => setForm({ ...form, bookingRef: e.target.value })} />
|
|
</div>
|
|
<div>
|
|
<label className="label">Amount Owed (ETB) <span className="text-red-500">*</span></label>
|
|
<input className="input" type="number" min="0.01" step="0.01" placeholder="e.g. 50.00" value={form.amountEtb} onChange={(e) => setForm({ ...form, amountEtb: e.target.value })} />
|
|
</div>
|
|
<div>
|
|
<label className="label">Reason <span className="text-red-500">*</span></label>
|
|
<select className="input" value={form.reason} onChange={(e) => setForm({ ...form, reason: e.target.value })}>
|
|
{REASONS.map((r) => <option key={r} value={r}>{r.replace('_', ' ')}</option>)}
|
|
</select>
|
|
</div>
|
|
<div className="md:col-span-2">
|
|
<label className="label">Notes (optional)</label>
|
|
<textarea className="input resize-none" rows={2} placeholder="e.g. Passenger paid 350 ETB, correct fare is 400 ETB" value={form.notes} onChange={(e) => setForm({ ...form, notes: e.target.value })} />
|
|
</div>
|
|
</div>
|
|
|
|
<p className="text-xs text-muted-foreground">
|
|
A payment link will be sent to the passenger's registered phone/email. The link expires in 72 hours.
|
|
</p>
|
|
|
|
<div className="flex justify-end gap-2 pt-2 border-t border-muted">
|
|
<ActionButton variant="secondary" onClick={onClose}>Cancel</ActionButton>
|
|
<ActionButton icon={PlusCircle} onClick={handleCreate} loading={createMutation.isPending}>Raise Charge</ActionButton>
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
);
|
|
}
|