Merge pull request #27 from Tria-plc/freight/feature/dynamic-dropdown

Implemented the dynamic dropdown
This commit is contained in:
Nathnael Wondisha
2026-05-22 17:34:36 +03:00
committed by GitHub
3 changed files with 175 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
import { useQuery } from "@tanstack/react-query";
import { cn } from "@/lib/utils";
import { api } from "@/services/api";
import { Loader2, AlertCircle } from "lucide-react";
import * as React from "react";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@edr/ui-common";
export interface DynamicSelectProps {
code: string;
placeholder?: string;
value?: string;
onValueChange?: (value: string) => void;
disabled?: boolean;
className?: string;
}
export function DynamicSelect({
code,
placeholder,
value,
onValueChange,
disabled,
className,
}: DynamicSelectProps) {
const { data, isLoading, isError } = useQuery(
api.dropdownSettings.getByCode.queryOptions({ input: { code } }),
);
if (isLoading) {
return (
<div
className={cn(
"flex h-9 w-full items-center gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm text-muted-foreground",
className,
)}
>
<Loader2 className="size-4 animate-spin" />
Loading...
</div>
);
}
if (isError || !data) {
return (
<div
className={cn(
"flex h-9 w-full items-center gap-2 rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive",
className,
)}
>
<AlertCircle className="size-4 shrink-0" />
Failed to load options
</div>
);
}
const options = [...data.children].sort((a, b) => a.order - b.order);
return (
<Select
value={value}
onValueChange={onValueChange}
disabled={disabled}
>
<SelectTrigger className={cn("w-full", className)}>
<SelectValue placeholder={placeholder ?? `Select ${data.label}`} />
</SelectTrigger>
<SelectContent>
{options.length === 0 ? (
<div className="p-2 text-center text-sm text-muted-foreground">
No options available
</div>
) : (
options.map((option) => (
<SelectItem
key={option.id}
value={option.value}
disabled={option.disabled}
>
{option.label}
{option.note ? (
<span className="ml-1 text-xs text-muted-foreground">
{option.note}
</span>
) : null}
</SelectItem>
))
)}
</SelectContent>
</Select>
);
}

View File

@@ -0,0 +1,2 @@
export { DynamicSelect } from "./DynamicSelect";
export type { DynamicSelectProps } from "./DynamicSelect";

View File

@@ -12,6 +12,15 @@ import { bookingsService } from "./bookings.service";
import { consignmentsService } from "./consignments.service";
import { trackingService } from "./tracking.service";
import { fileUploadSettingsService } from "./fileUploadSettings.service";
import { dropdownSettingsService } from "./dropdownSettings.service";
import {
CreateDropdownOptionDto,
CreateDropdownSettingDto,
DropdownOption,
DropdownSetting,
UpdateDropdownOptionDto,
UpdateDropdownSettingDto,
} from "@/types/dropdownSettings";
// ---------------------------------------------------------------------------
// API definition
@@ -135,4 +144,69 @@ export const api = {
({ fieldId }) => fileUploadSettingsService.removeField(fieldId),
),
},
dropdownSettings: {
list: endpoint<void, DropdownSetting[]>(
"dropdown-settings",
"list",
dropdownSettingsService.list,
),
getById: endpoint<{ id: string }, DropdownSetting>(
"dropdown-settings",
"getById",
({ id }) => dropdownSettingsService.getById(id),
),
getByCode: endpoint<{ code: string }, DropdownSetting>(
"dropdown-settings",
"getByCode",
({ code }) => dropdownSettingsService.getByCode(code),
),
create: endpoint<CreateDropdownSettingDto, DropdownSetting>(
"dropdown-settings",
"create",
(payload) => dropdownSettingsService.create(payload),
),
update: endpoint<
{ id: string; dto: UpdateDropdownSettingDto },
DropdownSetting
>("dropdown-settings", "update", ({ id, dto }) =>
dropdownSettingsService.update(id, dto),
),
remove: endpoint<{ id: string }, void>(
"dropdown-settings",
"remove",
({ id }) => dropdownSettingsService.remove(id),
),
replaceOptions: endpoint<
{ id: string; options: CreateDropdownOptionDto[] },
DropdownOption[]
>("dropdown-settings", "replaceOptions", ({ id, options }) =>
dropdownSettingsService.replaceOptions(id, options),
),
addOption: endpoint<
{ id: string; dto: CreateDropdownOptionDto },
DropdownOption
>("dropdown-settings", "addOption", ({ id, dto }) =>
dropdownSettingsService.addOption(id, dto),
),
updateOption: endpoint<
{ optionId: string; dto: UpdateDropdownOptionDto },
DropdownOption
>("dropdown-settings", "updateOption", ({ optionId, dto }) =>
dropdownSettingsService.updateOption(optionId, dto),
),
removeOption: endpoint<{ optionId: string }, void>(
"dropdown-settings",
"removeOption",
({ optionId }) => dropdownSettingsService.removeOption(optionId),
),
},
};