mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
add payment currency field to booking forms with ETB/USD selection support
This commit is contained in:
@@ -53,6 +53,7 @@ import {
|
||||
type BookingFormValues,
|
||||
} from "./new-booking-form/schema";
|
||||
import { SelectField } from "./new-booking-form/shared";
|
||||
import { PaymentCurrencyField } from "./new-booking-form/payment-currency-field";
|
||||
import { Step5CargoDetails, StepScheduling } from "./new-booking-form/steps";
|
||||
|
||||
const EDIT_SECTIONS = [
|
||||
@@ -137,6 +138,8 @@ function mapBookingToFormValues(
|
||||
isRefrigerated: booking.isRefrigerated ?? false,
|
||||
shippingLine: (booking as any).shippingLine?.name ?? "",
|
||||
consolidationEnabled: booking.allowConsolidation ?? false,
|
||||
paymentCurrency:
|
||||
booking.paymentCurrency === "ETB" ? "ETB" : "USD",
|
||||
scheduledDate: booking.scheduledDate
|
||||
? new Date(booking.scheduledDate).toISOString().slice(0, 10)
|
||||
: "",
|
||||
@@ -426,7 +429,7 @@ export default function EditBookingPage() {
|
||||
cargoTypeId: data.cargoType === "container" ? undefined : cargoTypeId,
|
||||
cargoTotalWeightVgm: totalWeight,
|
||||
isHazardous: data.isHazardous,
|
||||
paymentCurrency: "USD",
|
||||
paymentCurrency: data.paymentCurrency,
|
||||
allowConsolidation: data.consolidationEnabled,
|
||||
freightType:
|
||||
data.cargoType === "container"
|
||||
@@ -607,6 +610,8 @@ export default function EditBookingPage() {
|
||||
/>
|
||||
</SimpleGrid>
|
||||
|
||||
<PaymentCurrencyField control={form.control} />
|
||||
|
||||
{(selectedService?.includesFirstMile ||
|
||||
selectedService?.includesLastMile ||
|
||||
selectedService?.includesCustoms) && (
|
||||
|
||||
@@ -274,7 +274,7 @@ export default function NewBookingPage() {
|
||||
data.equipmentReturn === "with_return"
|
||||
? "WITH_RETURN"
|
||||
: "WITHOUT_RETURN",
|
||||
paymentCurrency: "USD",
|
||||
paymentCurrency: data.paymentCurrency,
|
||||
originYardId: data.originYard,
|
||||
destinationYardId: data.destinationYard,
|
||||
tradeDirection: direction!,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Box, Text } from "@mantine/core";
|
||||
import { Banknote, DollarSign } from "lucide-react";
|
||||
import { Controller, type Control } from "react-hook-form";
|
||||
import {
|
||||
PAYMENT_CURRENCY_OPTIONS,
|
||||
type BookingFormInputValues,
|
||||
type BookingFormValues,
|
||||
type PaymentCurrency,
|
||||
} from "./schema";
|
||||
import { OptionCard, OptionFieldError, StepLabel } from "./shared";
|
||||
|
||||
const CURRENCY_ICONS: Record<
|
||||
PaymentCurrency,
|
||||
{ icon: typeof DollarSign; bg: string; color: string }
|
||||
> = {
|
||||
USD: { icon: DollarSign, bg: "#EEF0FB", color: "#4F46E5" },
|
||||
ETB: { icon: Banknote, bg: "#ECF6F1", color: "#0A6F4D" },
|
||||
};
|
||||
|
||||
export function PaymentCurrencyField({
|
||||
control,
|
||||
}: {
|
||||
control: Control<BookingFormInputValues, any, BookingFormValues>;
|
||||
}) {
|
||||
return (
|
||||
<Box mt={24}>
|
||||
<StepLabel>Payment currency</StepLabel>
|
||||
<Text fz={12} c="#6B7C8E" mt={4} mb={12}>
|
||||
Choose the currency for your freight quote and invoices.
|
||||
</Text>
|
||||
<Controller
|
||||
name="paymentCurrency"
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<div>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
{PAYMENT_CURRENCY_OPTIONS.map((option) => {
|
||||
const Icon = CURRENCY_ICONS[option.value].icon;
|
||||
return (
|
||||
<OptionCard
|
||||
key={option.value}
|
||||
selected={field.value === option.value}
|
||||
onClick={() => field.onChange(option.value)}
|
||||
icon={<Icon className="h-5 w-5" />}
|
||||
iconBg={CURRENCY_ICONS[option.value].bg}
|
||||
iconColor={CURRENCY_ICONS[option.value].color}
|
||||
title={option.label}
|
||||
description={option.description}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<OptionFieldError error={fieldState.error} />
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -61,11 +61,32 @@ export const BOOKING_DOCS_SETTING: Freight.IFileUploadSetting = {
|
||||
|
||||
export type BookingDocuments = Record<string, File | File[] | null>;
|
||||
|
||||
export const PAYMENT_CURRENCIES = ["USD", "ETB"] as const;
|
||||
export type PaymentCurrency = (typeof PAYMENT_CURRENCIES)[number];
|
||||
|
||||
export const PAYMENT_CURRENCY_OPTIONS: Array<{
|
||||
value: PaymentCurrency;
|
||||
label: string;
|
||||
description: string;
|
||||
}> = [
|
||||
{
|
||||
value: "USD",
|
||||
label: "USD",
|
||||
description: "US Dollar — international pricing and invoicing.",
|
||||
},
|
||||
{
|
||||
value: "ETB",
|
||||
label: "ETB",
|
||||
description: "Ethiopian Birr — local pricing and invoicing.",
|
||||
},
|
||||
];
|
||||
|
||||
export const bookingFormSchema = z
|
||||
.object({
|
||||
contractType: z.enum(["new", "renewal"], "Select a contract type."),
|
||||
previousContractRef: z.string(),
|
||||
serviceTypeId: z.string("Select a service type."),
|
||||
paymentCurrency: z.enum(PAYMENT_CURRENCIES, "Select a payment currency."),
|
||||
|
||||
firstMile: z
|
||||
.object({
|
||||
@@ -200,6 +221,7 @@ export const initialBookingFormValues: DeepPartial<BookingFormValues> = {
|
||||
previousContractRef: "",
|
||||
|
||||
serviceTypeId: "",
|
||||
paymentCurrency: "USD",
|
||||
firstMile: {
|
||||
enabled: false,
|
||||
pickUpAddress: "",
|
||||
@@ -230,6 +252,7 @@ export const stepFields: Record<number, Array<Path<BookingFormValues>>> = {
|
||||
1: ["contractType", "previousContractRef"],
|
||||
2: [
|
||||
"serviceTypeId",
|
||||
"paymentCurrency",
|
||||
"firstMile",
|
||||
"lastMile",
|
||||
"equipmentReturn",
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
StepHeader,
|
||||
StepLabel,
|
||||
} from "./shared";
|
||||
import { PaymentCurrencyField } from "./payment-currency-field";
|
||||
|
||||
import type { Freight } from "@edr/types";
|
||||
|
||||
@@ -102,6 +103,8 @@ export function Step2ServiceType({
|
||||
)}
|
||||
/>
|
||||
|
||||
<PaymentCurrencyField control={form.control} />
|
||||
|
||||
{showServiceSections && (
|
||||
<Stack gap={12} mt={24}>
|
||||
<StepLabel>Trucking & customs options</StepLabel>
|
||||
|
||||
@@ -248,6 +248,10 @@ export function Step8Review({
|
||||
<DetailRow label="Previous ref" value={values.previousContractRef} />
|
||||
)}
|
||||
<DetailRow label="Service" value={serviceType?.name ?? ""} />
|
||||
<DetailRow
|
||||
label="Payment currency"
|
||||
value={values.paymentCurrency ?? "USD"}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="subtle"
|
||||
@@ -431,6 +435,10 @@ export function Step8Review({
|
||||
</Text>
|
||||
<Stack gap="sm">
|
||||
<ReadinessItem done={Boolean(values.serviceTypeId)} label="Service configured" />
|
||||
<ReadinessItem
|
||||
done={Boolean(values.paymentCurrency)}
|
||||
label="Payment currency selected"
|
||||
/>
|
||||
<ReadinessItem
|
||||
done={Boolean(values.originYard && values.destinationYard)}
|
||||
label="Route selected"
|
||||
|
||||
Reference in New Issue
Block a user