mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 16:00:56 +00:00
chore: add company select to backoffice booking
This commit is contained in:
@@ -180,8 +180,10 @@ export default function NewBookingPage() {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const [isGovernment, setIsGovernment] = useState(false);
|
const [isGovernment, setIsGovernment] = useState(false);
|
||||||
const [governmentInstitution, setGovernmentInstitution] = useState("");
|
|
||||||
const [companyId, setCompanyId] = useState<string | null>(null);
|
const [companyId, setCompanyId] = useState<string | null>(null);
|
||||||
|
// Government bookings bill to a real government company + an explicit profile.
|
||||||
|
const [govCompanyId, setGovCompanyId] = useState<string | null>(null);
|
||||||
|
const [govProfileId, setGovProfileId] = useState<string | null>(null);
|
||||||
const [freightType, setFreightType] = useState<FreightType>("CONTAINER");
|
const [freightType, setFreightType] = useState<FreightType>("CONTAINER");
|
||||||
const [originYardId, setOriginYardId] = useState<string | null>(null);
|
const [originYardId, setOriginYardId] = useState<string | null>(null);
|
||||||
const [destinationYardId, setDestinationYardId] = useState<string | null>(null);
|
const [destinationYardId, setDestinationYardId] = useState<string | null>(null);
|
||||||
@@ -220,6 +222,42 @@ export default function NewBookingPage() {
|
|||||||
label: c.name || c.email || c.tin || c.id,
|
label: c.name || c.email || c.tin || c.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Active government companies (kind=government) the booking can bill to.
|
||||||
|
const { data: govCompaniesPage, isLoading: govCompaniesLoading } = useQuery({
|
||||||
|
queryKey: ["companies", "government", "active"],
|
||||||
|
queryFn: () =>
|
||||||
|
customersService.list({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 1000,
|
||||||
|
kind: "government",
|
||||||
|
status: "active",
|
||||||
|
}),
|
||||||
|
enabled: isGovernment,
|
||||||
|
});
|
||||||
|
|
||||||
|
const govCompanies = govCompaniesPage?.items ?? [];
|
||||||
|
const govCompanyOptions = govCompanies.map((c) => ({
|
||||||
|
value: c.id,
|
||||||
|
label: c.name || c.tin || c.id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Profiles (importer/exporter) of the chosen government company — the booking
|
||||||
|
// must link to one explicitly.
|
||||||
|
const selectedGovCompany = govCompanies.find((c) => c.id === govCompanyId);
|
||||||
|
const govProfileOptions = (selectedGovCompany?.companyProfiles ?? [])
|
||||||
|
.filter((p) => p.status === "active")
|
||||||
|
.map((p) => ({
|
||||||
|
value: p.id,
|
||||||
|
label: `${p.type === "importer" ? "Import" : p.type === "exporter" ? "Export" : p.type}${
|
||||||
|
p.reference ? ` — ${p.reference}` : ""
|
||||||
|
}`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Reset the chosen profile when the government company changes.
|
||||||
|
useEffect(() => {
|
||||||
|
setGovProfileId(null);
|
||||||
|
}, [govCompanyId]);
|
||||||
|
|
||||||
// Day-level pool: fetch only the days that have a departure on the route (no
|
// Day-level pool: fetch only the days that have a departure on the route (no
|
||||||
// train, no capacity). The batch engine assigns the train after booking.
|
// train, no capacity). The batch engine assigns the train after booking.
|
||||||
const { data: availableDays, isLoading: daysLoading } = useQuery(
|
const { data: availableDays, isLoading: daysLoading } = useQuery(
|
||||||
@@ -306,7 +344,7 @@ export default function NewBookingPage() {
|
|||||||
Boolean(tradeDirection) &&
|
Boolean(tradeDirection) &&
|
||||||
Boolean(serviceTypeId) &&
|
Boolean(serviceTypeId) &&
|
||||||
departureSatisfied &&
|
departureSatisfied &&
|
||||||
(isGovernment ? governmentInstitution.trim().length >= 2 : Boolean(companyId)) &&
|
(isGovernment ? Boolean(govCompanyId && govProfileId) : Boolean(companyId)) &&
|
||||||
(freightType === "BULK"
|
(freightType === "BULK"
|
||||||
? Boolean(cargoTypeId) && bulkWeight > 0
|
? Boolean(cargoTypeId) && bulkWeight > 0
|
||||||
: allLinesValid);
|
: allLinesValid);
|
||||||
@@ -320,8 +358,8 @@ export default function NewBookingPage() {
|
|||||||
mutationFn: () =>
|
mutationFn: () =>
|
||||||
bookingsService.create({
|
bookingsService.create({
|
||||||
isGovernment,
|
isGovernment,
|
||||||
governmentInstitution: isGovernment ? governmentInstitution : undefined,
|
companyId: isGovernment ? govCompanyId || undefined : companyId || undefined,
|
||||||
companyId: isGovernment ? undefined : companyId || undefined,
|
companyProfileId: isGovernment ? govProfileId || undefined : undefined,
|
||||||
freightType,
|
freightType,
|
||||||
contractType: "NEW",
|
contractType: "NEW",
|
||||||
equipmentReturn,
|
equipmentReturn,
|
||||||
@@ -390,18 +428,37 @@ export default function NewBookingPage() {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Switch
|
<Switch
|
||||||
label="Government booking"
|
label="Government booking"
|
||||||
description="No company required — institution name instead. Expedited to the scheduling queue."
|
description="Bills to a government entity + profile. Expedited to the scheduling queue."
|
||||||
checked={isGovernment}
|
checked={isGovernment}
|
||||||
onChange={(e) => setIsGovernment(e.currentTarget.checked)}
|
onChange={(e) => setIsGovernment(e.currentTarget.checked)}
|
||||||
/>
|
/>
|
||||||
{isGovernment ? (
|
{isGovernment ? (
|
||||||
<TextInput
|
<Group grow align="flex-start">
|
||||||
label="Government institution"
|
<Select
|
||||||
placeholder="e.g. Ministry of Transport"
|
label="Government entity"
|
||||||
value={governmentInstitution}
|
placeholder="Select government company"
|
||||||
onChange={(e) => setGovernmentInstitution(e.currentTarget.value)}
|
data={govCompanyOptions}
|
||||||
required
|
value={govCompanyId}
|
||||||
/>
|
onChange={setGovCompanyId}
|
||||||
|
searchable
|
||||||
|
required
|
||||||
|
disabled={govCompaniesLoading}
|
||||||
|
nothingFoundMessage="No active government companies"
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Profile"
|
||||||
|
placeholder={
|
||||||
|
govCompanyId ? "Select import/export profile" : "Pick an entity first"
|
||||||
|
}
|
||||||
|
data={govProfileOptions}
|
||||||
|
value={govProfileId}
|
||||||
|
onChange={setGovProfileId}
|
||||||
|
searchable
|
||||||
|
required
|
||||||
|
disabled={!govCompanyId}
|
||||||
|
nothingFoundMessage="No active profiles for this entity"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
) : (
|
) : (
|
||||||
<Select
|
<Select
|
||||||
label="Customer"
|
label="Customer"
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ export type CompanyType =
|
|||||||
/** Mirrors backend `CompanyStatus`. */
|
/** Mirrors backend `CompanyStatus`. */
|
||||||
export type CompanyStatus = "active" | "pending" | "suspended" | "blacklisted";
|
export type CompanyStatus = "active" | "pending" | "suspended" | "blacklisted";
|
||||||
|
|
||||||
|
/** Mirrors backend `CompanyKind` — commercial customer vs. government entity. */
|
||||||
|
export type CompanyKind = "commercial" | "government";
|
||||||
|
|
||||||
/** Mirrors backend `ProfileType` (the role a company plays). */
|
/** Mirrors backend `ProfileType` (the role a company plays). */
|
||||||
export type ProfileType =
|
export type ProfileType =
|
||||||
| "importer"
|
| "importer"
|
||||||
@@ -47,6 +50,7 @@ export interface Company {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: CompanyType;
|
type: CompanyType;
|
||||||
|
kind: CompanyKind;
|
||||||
status: CompanyStatus;
|
status: CompanyStatus;
|
||||||
tin: string;
|
tin: string;
|
||||||
vatNumber?: string | null;
|
vatNumber?: string | null;
|
||||||
@@ -73,6 +77,7 @@ export interface CompanyListFilter {
|
|||||||
pageSize: number;
|
pageSize: number;
|
||||||
search?: string;
|
search?: string;
|
||||||
type?: CompanyType;
|
type?: CompanyType;
|
||||||
|
kind?: CompanyKind;
|
||||||
status?: CompanyStatus;
|
status?: CompanyStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user