feat(emex): add 3-level category tree view with static group hierarchy mapping
Some checks failed
CI / Lint, Typecheck, Test & Build (push) Has been cancelled

Parse emexdwc.ae QuickGroups hierarchy and create a static gid→path mapping
(384 groups). Groups page now shows collapsible tree (Body > Vehicle Front >
Bumper/Parts) instead of flat list. Unmapped groups fall back to flat display.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 06:15:08 +00:00
parent 2e3c609a72
commit 50847c5fd8
2 changed files with 529 additions and 15 deletions

View File

@@ -0,0 +1,387 @@
/** Static mapping: EMEX group_id → parent category path */
export const EMEX_GROUP_HIERARCHY: Record<string, string[]> = {
"10105": [],
"10442": [],
"10833": [],
"13199": [],
"10957": ["Accessories"],
"10958": ["Accessories"],
"10454": ["Air Conditioning"],
"10455": ["Air Conditioning"],
"10456": ["Air Conditioning"],
"10457": ["Air Conditioning"],
"10458": ["Air Conditioning"],
"10460": ["Air Conditioning"],
"10466": ["Air Conditioning"],
"10879": ["Air Conditioning"],
"10894": ["Air Conditioning"],
"10515": ["Axle Drive"],
"10516": ["Axle Drive"],
"10803": ["Axle Drive"],
"10807": ["Axle Drive", "Propshaft"],
"10905": ["Axle Drive", "Propshaft"],
"10939": ["Axle Drive", "Propshaft"],
"10307": ["Axle Mounting/ Steering/ Wheels"],
"10308": ["Axle Mounting/ Steering/ Wheels"],
"10309": ["Axle Mounting/ Steering/ Wheels"],
"10310": ["Axle Mounting/ Steering/ Wheels"],
"10313": ["Axle Mounting/ Steering/ Wheels"],
"10835": ["Axle Mounting/ Steering/ Wheels"],
"10934": ["Axle Mounting/ Steering/ Wheels"],
"10671": ["Axle Mounting/ Steering/ Wheels", "Control Arm/Swing Arm Joint"],
"10672": ["Axle Mounting/ Steering/ Wheels", "Control Arm/Swing Arm Joint"],
"10673": ["Axle Mounting/ Steering/ Wheels", "Stabilizer/ Fasteners"],
"10677": ["Axle Mounting/ Steering/ Wheels", "Stabilizer/ Fasteners"],
"10690": ["Axle Mounting/ Steering/ Wheels", "Stabilizer/ Fasteners"],
"10696": ["Axle Mounting/ Steering/ Wheels", "Stabilizer/ Fasteners"],
"10687": ["Axle Mounting/ Steering/ Wheels", "Stub Axle Repair Kit"],
"10678": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
"10679": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
"10680": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
"11582": ["Belt Drive"],
"12071": ["Belt Drive"],
"10531": ["Belt Drive", "V-Ribbed Belt / Set"],
"10532": ["Belt Drive", "V-Ribbed Belt / Set"],
"11554": ["Body"],
"11441": ["Body", "Auxiliary Lights/ Parts"],
"11445": ["Body", "Auxiliary Lights/ Parts"],
"11442": ["Body", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
"11444": ["Body", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
"11446": ["Body", "Auxiliary Lights/ Parts", "Spotlight/ Parts"],
"10255": ["Body", "Body Parts/ Wing/ Bumper"],
"10264": ["Body", "Body Parts/ Wing/ Bumper"],
"10265": ["Body", "Body Parts/ Wing/ Bumper"],
"10268": ["Body", "Body Parts/ Wing/ Bumper"],
"10269": ["Body", "Body Parts/ Wing/ Bumper"],
"10281": ["Body", "Body Parts/ Wing/ Bumper"],
"10285": ["Body", "Body Parts/ Wing/ Bumper"],
"10287": ["Body", "Body Parts/ Wing/ Bumper"],
"10291": ["Body", "Body Parts/ Wing/ Bumper"],
"10799": ["Body", "Body Parts/ Wing/ Bumper"],
"10837": ["Body", "Body Parts/ Wing/ Bumper"],
"10284": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
"10289": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
"10292": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
"11566": ["Body", "Headlight/ Parts"],
"11508": ["Body", "Lights"],
"11515": ["Body", "Lights"],
"11524": ["Body", "Lights"],
"11552": ["Body", "Lights"],
"11509": ["Body", "Lights", "Combination Rearlight/-Parts"],
"11521": ["Body", "Lights", "Indicator/ Parts"],
"12506": ["Body", "Lights", "Indicator/ Parts"],
"11525": ["Body", "Lights", "Licence Plate Light/-Parts"],
"11516": ["Body", "Lights", "Stop Light/ Parts"],
"11791": ["Body", "Passenger Cabin"],
"11792": ["Body", "Passenger Cabin"],
"11793": ["Body", "Passenger Cabin"],
"11794": ["Body", "Passenger Cabin"],
"11796": ["Body", "Passenger Cabin"],
"11797": ["Body", "Passenger Cabin"],
"11798": ["Body", "Passenger Cabin"],
"11799": ["Body", "Passenger Cabin"],
"11802": ["Body", "Passenger Cabin", "Parts"],
"10840": ["Body", "Trim/ Protection/ Decorative Strips/ Emblems"],
"11749": ["Body", "Vehicle Front"],
"11750": ["Body", "Vehicle Front"],
"11754": ["Body", "Vehicle Front"],
"11755": ["Body", "Vehicle Front"],
"11761": ["Body", "Vehicle Front"],
"11765": ["Body", "Vehicle Front"],
"13135": ["Body", "Vehicle Front"],
"11762": ["Body", "Vehicle Front", "Fog Light/ Parts"],
"11764": ["Body", "Vehicle Front", "Fog Light/ Parts"],
"11757": ["Body", "Vehicle Front", "Headlight/ Parts"],
"11770": ["Body", "Vehicle Front", "Indicator/ Parts"],
"11775": ["Body", "Vehicle Front", "Parts"],
"11873": ["Body", "Vehicle Front", "Parts"],
"11766": ["Body", "Vehicle Front", "Spotlight/ Parts"],
"11806": ["Body", "Vehicle Rear"],
"11815": ["Body", "Vehicle Rear"],
"11822": ["Body", "Vehicle Rear"],
"11831": ["Body", "Vehicle Rear"],
"11863": ["Body", "Vehicle Rear"],
"11879": ["Body", "Vehicle Rear"],
"11880": ["Body", "Vehicle Rear"],
"11882": ["Body", "Vehicle Rear"],
"11884": ["Body", "Vehicle Rear"],
"11816": ["Body", "Vehicle Rear", "Combination Rearlight/-Parts"],
"11828": ["Body", "Vehicle Rear", "Indicator/ Parts"],
"11832": ["Body", "Vehicle Rear", "Licence Plate Light/-Parts"],
"11850": ["Body", "Vehicle Rear", "Parts"],
"11823": ["Body", "Vehicle Rear", "Stop Light/ Parts"],
"10666": ["Body", "Windows/ Mirrors"],
"10845": ["Body", "Windows/ Mirrors"],
"10667": ["Body", "Windows/ Mirrors", "Windows"],
"10668": ["Body", "Windows/ Mirrors", "Windows"],
"10125": ["Brake System"],
"10126": ["Brake System"],
"10128": ["Brake System"],
"10129": ["Brake System"],
"10134": ["Brake System"],
"10135": ["Brake System"],
"10136": ["Brake System"],
"10137": ["Brake System"],
"10138": ["Brake System"],
"10139": ["Brake System"],
"10726": ["Brake System"],
"10735": ["Brake System"],
"12348": ["Brake System"],
"10906": ["Brake System", "Brake Calipers"],
"10907": ["Brake System", "Brake Calipers"],
"10130": ["Brake System", "Disc Brake"],
"10132": ["Brake System", "Disc Brake"],
"10730": ["Brake System", "Disc Brake"],
"10131": ["Brake System", "Drum Brake"],
"10133": ["Brake System", "Drum Brake"],
"10734": ["Brake System", "Drum Brake"],
"13064": ["Brake System", "Drum Brake"],
"13065": ["Brake System", "Drum Brake"],
"10467": ["Carrier Equipment"],
"10151": ["Clutch/ Parts"],
"10157": ["Clutch/ Parts"],
"10160": ["Clutch/ Parts", "Clutch Control"],
"10161": ["Clutch/ Parts", "Clutch Control"],
"10398": ["Clutch/ Parts", "Clutch Control"],
"10812": ["Clutch/ Parts", "Clutch Control"],
"10718": ["Comfort Systems"],
"10851": ["Comfort Systems"],
"10936": ["Comfort Systems"],
"10963": ["Comfort Systems"],
"10721": ["Comfort Systems", "Motor/ Relay/ Switch"],
"10722": ["Comfort Systems", "Motor/ Relay/ Switch"],
"10723": ["Comfort Systems", "Motor/ Relay/ Switch"],
"10982": ["Comfort Systems", "Motor/ Relay/ Switch"],
"10188": ["Cooling System"],
"10194": ["Cooling System"],
"10199": ["Cooling System"],
"10434": ["Cooling System"],
"10437": ["Cooling System"],
"10200": ["Cooling System", "Hoses/ Pipes/ Flanges"],
"10940": ["Cooling System", "Hoses/ Pipes/ Flanges"],
"10203": ["Cooling System", "Radiator/ Oil Cooler"],
"10204": ["Cooling System", "Radiator/ Oil Cooler"],
"10205": ["Cooling System", "Radiator/ Oil Cooler"],
"10208": ["Cooling System", "Radiator/ Oil Cooler"],
"10212": ["Cooling System", "Radiator/ Oil Cooler"],
"10195": ["Cooling System", "Thermostat/ Gasket"],
"10196": ["Cooling System", "Thermostat/ Gasket"],
"10189": ["Cooling System", "Water Pump/ Gasket"],
"10191": ["Cooling System", "Water Pump/ Gasket"],
"12311": ["Cooling System", "Water Pump/ Gasket"],
"10141": ["Electrics"],
"10142": ["Electrics"],
"10420": ["Electrics"],
"10808": ["Electrics"],
"10827": ["Electrics"],
"10885": ["Electrics"],
"12847": ["Electrics"],
"10450": ["Electrics", "Alternator/- Parts"],
"10376": ["Electrics", "Auxiliary Lights/ Parts"],
"10377": ["Electrics", "Auxiliary Lights/ Parts"],
"10540": ["Electrics", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
"10544": ["Electrics", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
"10539": ["Electrics", "Auxiliary Lights/ Parts", "Spotlight/ Parts"],
"10533": ["Electrics", "Headlight/ Parts"],
"10653": ["Electrics", "Instruments"],
"10655": ["Electrics", "Instruments"],
"10609": ["Electrics", "Light Switches/ Relays/ Controls"],
"10247": ["Electrics", "Lights"],
"10384": ["Electrics", "Lights"],
"10391": ["Electrics", "Lights"],
"10392": ["Electrics", "Lights"],
"10554": ["Electrics", "Lights", "Combination Rearlight/-Parts"],
"10563": ["Electrics", "Lights", "Indicator/ Parts"],
"10605": ["Electrics", "Lights", "Interior Lights"],
"10564": ["Electrics", "Lights", "Licence Plate Light/-Parts"],
"10967": ["Electrics", "Lights", "Stop Light/ Parts"],
"10140": ["Electrics", "Starter System"],
"10459": ["Electrics", "Starter System"],
"10635": ["Engine"],
"10800": ["Engine"],
"10854": ["Engine"],
"13137": ["Engine"],
"10801": ["Engine", "Complete Engine/ Sub-Assembly"],
"10633": ["Engine", "Crankcase"],
"10860": ["Engine", "Crankcase"],
"10867": ["Engine", "Crankcase"],
"10617": ["Engine", "Crankshaft Drive"],
"10618": ["Engine", "Crankshaft Drive"],
"10619": ["Engine", "Crankshaft Drive"],
"10620": ["Engine", "Crankshaft Drive"],
"10621": ["Engine", "Crankshaft Drive"],
"13220": ["Engine", "Crankshaft Drive"],
"10624": ["Engine", "Crankshaft Drive", "Connecting Rod Assembly"],
"10625": ["Engine", "Crankshaft Drive", "Connecting Rod Assembly"],
"10622": ["Engine", "Crankshaft Drive", "Crankshaft"],
"12783": ["Engine", "Crankshaft Drive", "Crankshaft"],
"10629": ["Engine", "Crankshaft Drive", "Piston Assembly"],
"10630": ["Engine", "Crankshaft Drive", "Piston Assembly"],
"10631": ["Engine", "Crankshaft Drive", "Piston Assembly"],
"10474": ["Engine", "Cylinder Head/ Parts"],
"10476": ["Engine", "Cylinder Head/ Parts"],
"10477": ["Engine", "Cylinder Head/ Parts"],
"10478": ["Engine", "Cylinder Head/ Parts"],
"10479": ["Engine", "Cylinder Head/ Parts"],
"10480": ["Engine", "Cylinder Head/ Parts"],
"12550": ["Engine", "Cylinder Head/ Parts"],
"10484": ["Engine", "Engine Air Supply"],
"10486": ["Engine", "Engine Air Supply"],
"10804": ["Engine", "Engine Air Supply"],
"10918": ["Engine", "Engine Air Supply"],
"10491": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
"10493": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
"10494": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
"12176": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
"12439": ["Engine", "Engine Air Supply", "Throttle/ Sensor"],
"10636": ["Engine", "Engine Mountings"],
"10638": ["Engine", "Engine Mountings"],
"10497": ["Engine", "Engine Timing Control"],
"10498": ["Engine", "Engine Timing Control"],
"10499": ["Engine", "Engine Timing Control"],
"10503": ["Engine", "Engine Timing Control"],
"11933": ["Engine", "Engine Timing Control"],
"10511": ["Engine", "Engine Timing Control", "Timing Chain/ Tensioner/ Guide"],
"10514": ["Engine", "Engine Timing Control", "Timing Chain/ Tensioner/ Guide"],
"10523": ["Engine", "Engine Timing Control", "Valve Train"],
"10524": ["Engine", "Engine Timing Control", "Valve Train"],
"10642": ["Engine", "Exhaust Emission Control"],
"10829": ["Engine", "Exhaust Emission Control"],
"10651": ["Engine", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
"13335": ["Engine", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
"13337": ["Engine", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
"13338": ["Engine", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
"10325": ["Engine", "Gaskets"],
"10328": ["Engine", "Gaskets"],
"10329": ["Engine", "Gaskets"],
"10331": ["Engine", "Gaskets"],
"10334": ["Engine", "Gaskets"],
"10782": ["Engine", "Gaskets"],
"10783": ["Engine", "Gaskets"],
"10784": ["Engine", "Gaskets"],
"10889": ["Engine", "Gaskets"],
"10570": ["Engine", "Lubrication"],
"10572": ["Engine", "Lubrication"],
"10574": ["Engine", "Lubrication"],
"10575": ["Engine", "Lubrication"],
"10578": ["Engine", "Lubrication"],
"10579": ["Engine", "Lubrication"],
"10583": ["Engine", "Lubrication", "Oil Cooler/ Parts"],
"10588": ["Engine", "Lubrication", "Oil Cooler/ Parts"],
"10589": ["Engine", "Lubrication", "Oil Pan/ Parts"],
"10591": ["Engine", "Lubrication", "Oil Pan/ Parts"],
"10592": ["Engine", "Lubrication", "Oil Pump/ Parts"],
"10593": ["Engine", "Lubrication", "Oil Pump/ Parts"],
"10594": ["Engine", "Lubrication", "Oil Pump/ Parts"],
"10985": ["Engine", "Lubrication", "Oil Pump/ Parts"],
"10147": ["Exhaust System"],
"10148": ["Exhaust System"],
"10295": ["Exhaust System"],
"10414": ["Exhaust System"],
"10415": ["Exhaust System"],
"10814": ["Exhaust System"],
"10972": ["Exhaust System"],
"13119": ["Exhaust System"],
"10421": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
"10427": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
"13122": ["Exhaust System", "Urea Injection (AdBlue)"],
"13162": ["Exhaust System", "Urea Injection (AdBlue)"],
"13189": ["Exhaust System", "Urea Injection (AdBlue)"],
"10359": ["Filters"],
"10360": ["Filters"],
"10361": ["Filters"],
"10363": ["Filters"],
"10891": ["Fuel Mixture Formation", "Exhaust Emission Control"],
"10893": ["Fuel Mixture Formation", "Exhaust Emission Control"],
"13147": ["Fuel Mixture Formation", "Exhaust Emission Control"],
"10911": ["Fuel Mixture Formation", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
"13339": ["Fuel Mixture Formation", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
"13341": ["Fuel Mixture Formation", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
"12895": ["Fuel Mixture Formation", "Mixture Formation"],
"12896": ["Fuel Mixture Formation", "Mixture Formation"],
"12899": ["Fuel Mixture Formation", "Mixture Formation"],
"12903": ["Fuel Mixture Formation", "Mixture Formation"],
"12904": ["Fuel Mixture Formation", "Mixture Formation"],
"12905": ["Fuel Mixture Formation", "Mixture Formation"],
"12906": ["Fuel Mixture Formation", "Mixture Formation"],
"12909": ["Fuel Mixture Formation", "Mixture Formation"],
"12910": ["Fuel Mixture Formation", "Mixture Formation"],
"10350": ["Fuel Supply System"],
"10353": ["Fuel Supply System"],
"10358": ["Fuel Supply System"],
"10368": ["Fuel Supply System"],
"13177": ["Fuel Supply System"],
"10817": ["Fuel Supply System", "Fuel Pump / Parts"],
"10446": ["Heater"],
"10447": ["Heater"],
"10448": ["Heater"],
"10449": ["Heater"],
"10825": ["Heater"],
"10826": ["Heater"],
"10877": ["Heater"],
"10793": ["Information/ Communication Systems"],
"10794": ["Information/ Communication Systems"],
"10795": ["Information/ Communication Systems"],
"10796": ["Information/ Communication Systems"],
"10797": ["Information/ Communication Systems"],
"10773": ["Interior Equipment"],
"10830": ["Interior Equipment"],
"12790": ["Interior Equipment"],
"12791": ["Interior Equipment"],
"12792": ["Interior Equipment"],
"12794": ["Interior Equipment"],
"12795": ["Interior Equipment"],
"12798": ["Interior Equipment"],
"12806": ["Interior Equipment"],
"13098": ["Interior Equipment"],
"13104": ["Interior Equipment"],
"10787": ["Locking System"],
"10788": ["Locking System"],
"10791": ["Locking System"],
"10866": ["Locking System"],
"10697": ["Maintenance Service Parts"],
"10698": ["Maintenance Service Parts"],
"10519": ["Security Systems"],
"10520": ["Security Systems"],
"10521": ["Security Systems"],
"10862": ["Security Systems"],
"10347": ["Spark/ Glow Ignition"],
"10349": ["Spark/ Glow Ignition"],
"10298": ["Steering"],
"10299": ["Steering"],
"10301": ["Steering"],
"10302": ["Steering"],
"10692": ["Steering"],
"10701": ["Steering"],
"11957": ["Steering"],
"12173": ["Steering"],
"10703": ["Steering", "Tie Rod Assembly/ Parts"],
"10213": ["Suspension"],
"10221": ["Suspension"],
"10471": ["Suspension"],
"10481": ["Suspension"],
"10910": ["Suspension"],
"10229": ["Suspension", "Suspension Parts"],
"10472": ["Suspension", "Suspension Parts"],
"10707": ["Towbar/ Parts"],
"11953": ["Transmission", "Automatic Transmission"],
"13209": ["Transmission", "Automatic Transmission"],
"11954": ["Transmission", "Automatic Transmission", "Oil Pan/ Parts"],
"11955": ["Transmission", "Automatic Transmission", "Oil Pan/ Parts"],
"11908": ["Transmission", "Manual Transmission"],
"13165": ["Transmission", "Manual Transmission"],
"10162": ["Wheel Drive"],
"10171": ["Wheel Drive"],
"10174": ["Wheel Drive"],
"13200": ["Wheels/Tyres"],
"13201": ["Wheels/Tyres"],
"13202": ["Wheels/Tyres"],
"10233": ["Windscreen Cleaning System"],
"10234": ["Windscreen Cleaning System"],
"10235": ["Windscreen Cleaning System"],
"10236": ["Windscreen Cleaning System"],
"10237": ["Windscreen Cleaning System"],
"10710": ["Windscreen Cleaning System"],
"10711": ["Windscreen Cleaning System"],
"10713": ["Windscreen Cleaning System"],
};

View File

@@ -1,9 +1,11 @@
import { useState } from "react";
import { createFileRoute, Link } from "@tanstack/react-router";
import { useQuery } from "@tanstack/react-query";
import { api } from "@/lib/api-client";
import { useTranslation } from "@/lib/i18n";
import { EMEX_GROUP_HIERARCHY } from "@/lib/emex-group-hierarchy";
import { Button, Skeleton } from "@sase/ui";
import { ArrowLeft, FolderOpen, ChevronRight } from "lucide-react";
import { ArrowLeft, FolderOpen, ChevronRight, ChevronDown } from "lucide-react";
export const Route = createFileRoute(
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId/",
@@ -20,6 +22,43 @@ interface EmexGroup {
hasChildren: boolean | null;
}
interface TreeNode {
label: string;
children: TreeNode[];
groups: EmexGroup[];
}
function buildTree(groups: EmexGroup[]): TreeNode[] {
const root: TreeNode = { label: "", children: [], groups: [] };
for (const g of groups) {
const path = EMEX_GROUP_HIERARCHY[g.groupId];
if (!path || path.length === 0) {
// Unmapped group — put under root
root.groups.push(g);
continue;
}
let current = root;
for (const segment of path) {
let child = current.children.find((c) => c.label === segment);
if (!child) {
child = { label: segment, children: [], groups: [] };
current.children.push(child);
}
current = child;
}
current.groups.push(g);
}
// If no tree structure was built (no mappings matched), return flat
if (root.children.length === 0 && root.groups.length > 0) {
return [];
}
return root.children;
}
function EmexGroupListPage() {
const { t } = useTranslation();
const { catalogCode, vehicleId } = Route.useParams();
@@ -29,6 +68,9 @@ function EmexGroupListPage() {
queryFn: () => api.get<EmexGroup[]>(`/catalog/emex/vehicles/${vehicleId}/groups`),
});
const tree = groups ? buildTree(groups) : [];
const isFlat = tree.length === 0 && groups && groups.length > 0;
return (
<div className="space-y-4">
<div className="flex items-center gap-3">
@@ -42,34 +84,119 @@ function EmexGroupListPage() {
</Button>
</Link>
<h1 className="text-xl font-bold">{t("catalog.categories")}</h1>
{groups && (
<span className="text-sm text-muted-foreground">({groups.length})</span>
)}
</div>
{isLoading ? (
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3">
{Array.from({ length: 12 }).map((_, i) => (
<Skeleton key={`g-skel-${i}`} className="h-14 w-full rounded-lg" />
<div className="space-y-2">
{Array.from({ length: 8 }).map((_, i) => (
<Skeleton key={i} className="h-10 w-full rounded-lg" />
))}
</div>
) : !groups || groups.length === 0 ? (
<p className="py-8 text-center text-muted-foreground">
{t("catalog.noCategories")}
</p>
) : (
) : isFlat ? (
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3">
{groups.map((g) => (
<Link
key={g.id}
to="/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
params={{ catalogCode, vehicleId, groupId: g.id }}
className="flex items-center gap-3 rounded-lg border border-border bg-card p-3 transition-colors hover:bg-accent"
>
<FolderOpen className="size-4 shrink-0 text-muted-foreground" />
<span className="min-w-0 flex-1 truncate text-sm">{g.name}</span>
<ChevronRight className="size-4 shrink-0 text-muted-foreground" />
</Link>
<GroupLink key={g.id} group={g} catalogCode={catalogCode} vehicleId={vehicleId} />
))}
</div>
) : (
<div className="space-y-1">
{tree.map((node) => (
<TreeSection
key={node.label}
node={node}
catalogCode={catalogCode}
vehicleId={vehicleId}
depth={0}
/>
))}
</div>
)}
</div>
);
}
function TreeSection({
node,
catalogCode,
vehicleId,
depth,
}: {
node: TreeNode;
catalogCode: string;
vehicleId: string;
depth: number;
}) {
const [open, setOpen] = useState(depth === 0);
const totalGroups = countGroups(node);
return (
<div style={{ marginLeft: depth > 0 ? 16 : 0 }}>
<button
type="button"
onClick={() => setOpen(!open)}
className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-medium transition-colors hover:bg-accent"
>
{open ? (
<ChevronDown className="size-4 shrink-0 text-muted-foreground" />
) : (
<ChevronRight className="size-4 shrink-0 text-muted-foreground" />
)}
<span className="flex-1">{node.label}</span>
<span className="text-xs text-muted-foreground">{totalGroups}</span>
</button>
{open && (
<div className="ml-2 border-l border-border pl-2">
{node.children.map((child) => (
<TreeSection
key={child.label}
node={child}
catalogCode={catalogCode}
vehicleId={vehicleId}
depth={depth + 1}
/>
))}
{node.groups.map((g) => (
<GroupLink key={g.id} group={g} catalogCode={catalogCode} vehicleId={vehicleId} />
))}
</div>
)}
</div>
);
}
function GroupLink({
group,
catalogCode,
vehicleId,
}: {
group: EmexGroup;
catalogCode: string;
vehicleId: string;
}) {
return (
<Link
to="/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
params={{ catalogCode, vehicleId, groupId: group.id }}
className="flex items-center gap-2 rounded-lg px-3 py-2 text-sm transition-colors hover:bg-accent"
>
<FolderOpen className="size-3.5 shrink-0 text-muted-foreground" />
<span className="min-w-0 flex-1 truncate">{group.name}</span>
<ChevronRight className="size-3.5 shrink-0 text-muted-foreground" />
</Link>
);
}
function countGroups(node: TreeNode): number {
return (
node.groups.length +
node.children.reduce((sum, c) => sum + countGroups(c), 0)
);
}