feat: add toggle to DJF

This commit is contained in:
ghost2023
2026-09-06 16:35:14 +03:00
parent aa96bb4086
commit eab36a2526
21 changed files with 337 additions and 41 deletions

View File

@@ -291,8 +291,8 @@ export default function UsdPaymentsPanel({
const { user } = useAuth();
const canConfirm = hasPermission(user, FREIGHT_PERMS.invoices.confirmOffline);
// Manual settlement is switched on per currency in Configuration → Manual
// payments. FinanceHubPage hides the tab for a disabled currency; this is
// Manual settlement is switched on per currency in Configuration →
// Payments. FinanceHubPage hides the tab for a disabled currency; this is
// the fallback for a direct `?tab=` link, and the API refuses regardless.
const { data: manualSettings } = useManualPaymentSettingsQuery();
const currencyEnabled = manualSettings
@@ -549,7 +549,7 @@ export default function UsdPaymentsPanel({
onRowClick={(row) => navigate(`/dashboard/invoices/${row.id}`)}
emptyMessage={
!currencyEnabled
? `Manual payment is switched off for ${currency} invoices. Enable it in Configuration → Manual payments.`
? `Manual payment is switched off for ${currency} invoices. Enable it in Configuration → Payments.`
: controls.activeCount > 0
? "No invoices match these filters."
: `No ${currency} invoices awaiting manual payment confirmation.`

View File

@@ -8,7 +8,7 @@ import {
import { Badge } from "@/shared/common/ui/badge";
import { Switch } from "@/shared/common/ui/switch";
import { Skeleton } from "@/shared/common/ui/skeleton";
import { AlertTriangle, Banknote, Landmark } from "lucide-react";
import { AlertTriangle, Banknote, Coins, Landmark } from "lucide-react";
import { useAuth } from "@/auth/useAuth";
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
@@ -53,7 +53,8 @@ const CURRENCIES: {
];
/**
* Switches the manual (offline) payment channel on or off per currency.
* Two levels of switch: whether DJF is accepted as a payment currency at all,
* and whether the manual (offline) channel is open, per currency.
*
* Off means gone, not greyed out: the Manual Payments worklist lists only
* enabled currencies, and the API refuses a confirmation in a disabled one —
@@ -75,11 +76,12 @@ export default function ManualPaymentSettingsCard() {
return (
<Card className="shadow-lg border-gray-200 dark:border-gray-700">
<CardHeader>
<CardTitle>Manual payments</CardTitle>
<CardTitle>Payments</CardTitle>
<CardDescription>
Whether Finance staff may mark invoices as paid by hand, from
Invoices Manual Payments. Each currency is switched separately.
Confirming still requires the payment slip and the booking&apos;s pay
Which currencies customers may be billed in, and whether Finance
staff may mark invoices as paid by hand from Invoices Manual
Payments. Each currency is switched separately. Confirming a manual
payment still requires the payment slip and the booking&apos;s pay
window to be open.
</CardDescription>
</CardHeader>
@@ -95,6 +97,38 @@ export default function ManualPaymentSettingsCard() {
</div>
)}
{isLoading || !data ? (
<Skeleton className="h-[86px] w-full rounded-md" />
) : (
<div className="flex items-start justify-between gap-4 rounded-md border p-4 dark:border-gray-700">
<div className="space-y-1">
<div className="flex items-center gap-2">
<Coins className="h-4 w-4 text-muted-foreground" />
<p className="font-medium">Accept Djibouti Franc (DJF)</p>
<Badge variant={data.djfPaymentsEnabled ? "default" : "secondary"}>
{data.djfPaymentsEnabled ? "Enabled" : "Disabled"}
</Badge>
</div>
<p className="text-sm text-muted-foreground">
Whether DJF is offered as a billing currency on new bookings and
shipment requests, and whether DJF invoices can be paid online
(Waafi / CAC Bank). Switching this off stops new DJF business
invoices already in DJF stay settleable by hand below.
</p>
</div>
<Switch
checked={data.djfPaymentsEnabled}
disabled={!canManage || update.isPending}
aria-label="Accept DJF as a payment currency"
onCheckedChange={(checked) =>
update.mutate({ djfPaymentsEnabled: checked })
}
/>
</div>
)}
<p className="pt-2 text-sm font-medium">Manual (offline) settlement</p>
{isLoading || !data
? CURRENCIES.map((c) => (
<Skeleton key={c.code} className="h-[86px] w-full rounded-md" />