Merge dev into main: pcat catalog + EMEX VIN decode + autonomy charter
Some checks failed
Deploy / Deploy to Production (push) Has been cancelled
Some checks failed
Deploy / Deploy to Production (push) Has been cancelled
Brings 35 dev branch commits onto main, integrating with the 32 main-side commits (Sentry, translation pipeline, deploy fixes). Critical merge across VIN decode pipeline and catalog services. # Conflicts: # .gitignore # apps/api/src/catalog/catalog.module.ts # apps/api/src/categories/categories.module.ts # apps/api/src/categories/categories.service.spec.ts # apps/api/src/common/filters/http-exception.filter.ts # apps/api/src/integrations/emex/emex.service.ts # apps/api/src/integrations/emex/emex.types.ts # apps/api/src/jobs/processors/emex-scrape.processor.ts # apps/api/src/vehicles/vehicles.controller.ts # apps/api/src/vehicles/vehicles.module.ts # apps/api/src/vehicles/vehicles.service.ts # apps/web/src/routes/dashboard.tsx # apps/web/src/routes/dashboard/catalog/index.tsx
This commit is contained in:
822
apps/web/src/lib/emex-group-hierarchy.ts
Normal file
822
apps/web/src/lib/emex-group-hierarchy.ts
Normal file
@@ -0,0 +1,822 @@
|
||||
/**
|
||||
* Static mapping: EMEX group_id → category hierarchy path.
|
||||
* Covers all 795 unique group_ids across 53 catalogs.
|
||||
* Generated from emexdwc.ae QuickGroups + name-based auto-categorization.
|
||||
*/
|
||||
export const EMEX_GROUP_HIERARCHY: Record<string, string[]> = {
|
||||
"10105": [],
|
||||
"10125": ["Brake System"],
|
||||
"10126": ["Brake System"],
|
||||
"10128": ["Brake System"],
|
||||
"10129": ["Brake System"],
|
||||
"10130": ["Brake System", "Disc Brake"],
|
||||
"10131": ["Brake System", "Drum Brake"],
|
||||
"10132": ["Brake System", "Disc Brake"],
|
||||
"10133": ["Brake System", "Drum Brake"],
|
||||
"10134": ["Brake System"],
|
||||
"10135": ["Brake System"],
|
||||
"10136": ["Brake System"],
|
||||
"10137": ["Brake System"],
|
||||
"10138": ["Brake System"],
|
||||
"10139": ["Brake System"],
|
||||
"10140": ["Electrics", "Starter System"],
|
||||
"10141": ["Electrics"],
|
||||
"10142": ["Electrics"],
|
||||
"10147": ["Exhaust System"],
|
||||
"10148": ["Exhaust System"],
|
||||
"10151": ["Clutch/ Parts"],
|
||||
"10152": ["Clutch/ Parts"],
|
||||
"10153": ["Clutch/ Parts"],
|
||||
"10154": ["Clutch/ Parts"],
|
||||
"10155": ["Clutch/ Parts", "Releaser, clutch"],
|
||||
"10156": ["Clutch/ Parts", "Releaser, clutch"],
|
||||
"10157": ["Clutch/ Parts"],
|
||||
"10159": ["Clutch/ Parts"],
|
||||
"10160": ["Clutch/ Parts", "Clutch Control"],
|
||||
"10161": ["Clutch/ Parts", "Clutch Control"],
|
||||
"10162": ["Wheel Drive"],
|
||||
"10166": ["Wheel Drive"],
|
||||
"10170": ["Wheel Drive"],
|
||||
"10171": ["Wheel Drive"],
|
||||
"10174": ["Wheel Drive"],
|
||||
"10177": ["Clutch/ Parts", "Clutch Control"],
|
||||
"10185": ["Belt Drive"],
|
||||
"10188": ["Cooling System"],
|
||||
"10189": ["Cooling System", "Water Pump/ Gasket"],
|
||||
"10191": ["Cooling System", "Water Pump/ Gasket"],
|
||||
"10194": ["Cooling System"],
|
||||
"10195": ["Cooling System", "Thermostat/ Gasket"],
|
||||
"10196": ["Cooling System", "Thermostat/ Gasket"],
|
||||
"10199": ["Cooling System"],
|
||||
"10200": ["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"],
|
||||
"10213": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10221": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10229": ["Axle Mounting/ Steering/ Wheels", "Suspension Parts"],
|
||||
"10233": ["Windscreen Cleaning System"],
|
||||
"10234": ["Windscreen Cleaning System"],
|
||||
"10235": ["Windscreen Cleaning System"],
|
||||
"10236": ["Windscreen Cleaning System"],
|
||||
"10237": ["Windscreen Cleaning System"],
|
||||
"10247": ["Electrics", "Lights"],
|
||||
"10248": ["Spark/ Glow Ignition"],
|
||||
"10250": ["Spark/ Glow Ignition"],
|
||||
"10251": ["Spark/ Glow Ignition"],
|
||||
"10252": ["Spark/ Glow Ignition"],
|
||||
"10253": ["Spark/ Glow Ignition"],
|
||||
"10255": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10264": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10265": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10266": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10268": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10269": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10281": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10284": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
|
||||
"10285": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10287": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10289": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
|
||||
"10291": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10292": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
|
||||
"10295": ["Exhaust System"],
|
||||
"10296": ["Exhaust System"],
|
||||
"10297": ["Axle Mounting/ Steering/ Wheels", "Tie Rod Assembly/ Parts"],
|
||||
"10298": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10299": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10300": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10301": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10302": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10303": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10307": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10308": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10309": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10310": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10311": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10312": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10313": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10315": ["Cooling System", "Hoses/ Pipes/ Flanges"],
|
||||
"10317": ["Engine"],
|
||||
"10324": ["Engine", "Gaskets"],
|
||||
"10325": ["Engine", "Gaskets"],
|
||||
"10327": ["Engine", "Gaskets"],
|
||||
"10328": ["Engine", "Gaskets"],
|
||||
"10329": ["Engine", "Gaskets"],
|
||||
"10331": ["Engine", "Gaskets"],
|
||||
"10333": ["Engine", "Gaskets"],
|
||||
"10334": ["Engine", "Gaskets"],
|
||||
"10337": ["Clutch/ Parts", "Releaser, clutch"],
|
||||
"10344": ["Engine", "Gaskets"],
|
||||
"10346": ["Spark/ Glow Ignition"],
|
||||
"10347": ["Spark/ Glow Ignition"],
|
||||
"10349": ["Spark/ Glow Ignition"],
|
||||
"10350": ["Fuel Supply System"],
|
||||
"10352": ["Fuel Supply System"],
|
||||
"10353": ["Fuel Supply System"],
|
||||
"10358": ["Fuel Supply System"],
|
||||
"10359": ["Filters"],
|
||||
"10360": ["Filters"],
|
||||
"10361": ["Filters"],
|
||||
"10362": ["Filters"],
|
||||
"10363": ["Filters"],
|
||||
"10367": ["Fuel Supply System"],
|
||||
"10368": ["Fuel Supply System"],
|
||||
"10369": ["Fuel Supply System"],
|
||||
"10370": ["Fuel Supply System"],
|
||||
"10376": ["Electrics", "Auxiliary Lights/ Parts"],
|
||||
"10377": ["Electrics", "Auxiliary Lights/ Parts"],
|
||||
"10379": ["Electrics", "Headlight/ Parts"],
|
||||
"10384": ["Electrics", "Lights"],
|
||||
"10385": ["Electrics", "Lights"],
|
||||
"10387": ["Electrics", "Lights"],
|
||||
"10389": ["Body", "Lighting"],
|
||||
"10391": ["Electrics", "Lights"],
|
||||
"10392": ["Electrics", "Lights"],
|
||||
"10395": ["Electrics"],
|
||||
"10398": ["Clutch/ Parts", "Clutch Control"],
|
||||
"10414": ["Exhaust System"],
|
||||
"10415": ["Exhaust System"],
|
||||
"10416": ["Exhaust System", "Assembly Parts"],
|
||||
"10418": ["Exhaust System"],
|
||||
"10419": ["Exhaust System"],
|
||||
"10420": ["Electrics"],
|
||||
"10421": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
|
||||
"10423": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
|
||||
"10425": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
|
||||
"10427": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
|
||||
"10428": ["Engine"],
|
||||
"10430": ["Engine"],
|
||||
"10432": ["Engine"],
|
||||
"10433": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
|
||||
"10434": ["Cooling System"],
|
||||
"10437": ["Cooling System"],
|
||||
"10438": ["Cooling System"],
|
||||
"10440": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10442": [],
|
||||
"10444": ["Cooling System"],
|
||||
"10446": ["Heater"],
|
||||
"10447": ["Heater"],
|
||||
"10448": ["Heater"],
|
||||
"10449": ["Heater"],
|
||||
"10450": ["Electrics", "Alternator/- Parts"],
|
||||
"10451": ["Electrics", "Alternator/- Parts"],
|
||||
"10452": ["Electrics", "Alternator/- Parts"],
|
||||
"10454": ["Air Conditioning"],
|
||||
"10455": ["Air Conditioning"],
|
||||
"10456": ["Air Conditioning"],
|
||||
"10457": ["Air Conditioning"],
|
||||
"10458": ["Air Conditioning"],
|
||||
"10459": ["Electrics", "Starter System"],
|
||||
"10460": ["Air Conditioning"],
|
||||
"10462": ["Electrics", "Starter System"],
|
||||
"10463": ["Air Conditioning"],
|
||||
"10464": ["Transmission"],
|
||||
"10465": ["Transmission"],
|
||||
"10466": ["Air Conditioning"],
|
||||
"10467": ["Carrier Equipment"],
|
||||
"10470": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10471": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10472": ["Axle Mounting/ Steering/ Wheels", "Suspension Parts"],
|
||||
"10474": ["Engine", "Cylinder Head/ Parts"],
|
||||
"10475": ["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"],
|
||||
"10481": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10482": ["Fuel Mixture Formation"],
|
||||
"10484": ["Engine", "Engine Air Supply"],
|
||||
"10485": ["Engine", "Engine Air Supply"],
|
||||
"10486": ["Engine", "Engine Air Supply"],
|
||||
"10487": ["Engine", "Engine Air Supply"],
|
||||
"10488": ["Engine", "Engine Air Supply"],
|
||||
"10489": ["Exhaust System"],
|
||||
"10491": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
|
||||
"10493": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
|
||||
"10494": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
|
||||
"10496": ["Engine", "Engine Timing Control"],
|
||||
"10497": ["Engine", "Engine Timing Control"],
|
||||
"10498": ["Engine", "Engine Timing Control"],
|
||||
"10499": ["Engine", "Engine Timing Control"],
|
||||
"10503": ["Engine", "Engine Timing Control"],
|
||||
"10504": ["Engine", "Engine Timing Control", "Timing Belt/ Tensioner/ Guide"],
|
||||
"10505": ["Engine", "Engine Timing Control", "Timing Belt/ Tensioner/ Guide"],
|
||||
"10506": ["Engine", "Engine Timing Control", "Timing Belt/ Tensioner/ Guide"],
|
||||
"10507": ["Engine", "Engine Timing Control", "Timing Belt/ Tensioner/ Guide"],
|
||||
"10510": ["Engine", "Engine Timing Control", "Timing Belt/ Tensioner/ Guide"],
|
||||
"10511": ["Engine", "Engine Timing Control", "Timing Chain/ Tensioner/ Guide"],
|
||||
"10513": ["Engine", "Engine Timing Control", "Timing Chain/ Tensioner/ Guide"],
|
||||
"10514": ["Engine", "Engine Timing Control", "Timing Chain/ Tensioner/ Guide"],
|
||||
"10515": ["Axle Drive"],
|
||||
"10516": ["Axle Drive"],
|
||||
"10519": ["Security Systems"],
|
||||
"10520": ["Security Systems"],
|
||||
"10521": ["Security Systems"],
|
||||
"10523": ["Engine", "Engine Timing Control", "Valve Train"],
|
||||
"10524": ["Engine", "Engine Timing Control", "Valve Train"],
|
||||
"10525": ["Engine", "Engine Timing Control"],
|
||||
"10527": ["Electrics", "Headlight/ Parts"],
|
||||
"10530": ["Electrics", "Headlight/ Parts"],
|
||||
"10531": ["Belt Drive", "V-Ribbed Belt / Set"],
|
||||
"10532": ["Belt Drive", "V-Ribbed Belt / Set"],
|
||||
"10533": ["Electrics", "Headlight/ Parts"],
|
||||
"10534": ["Belt Drive", "V-Ribbed Belt / Set"],
|
||||
"10535": ["Belt Drive", "V-Ribbed Belt / Set"],
|
||||
"10538": ["Engine"],
|
||||
"10539": ["Electrics", "Auxiliary Lights/ Parts", "Spotlight/ Parts"],
|
||||
"10540": ["Electrics", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
|
||||
"10541": ["Engine"],
|
||||
"10542": ["Electrics", "Auxiliary Lights/ Parts", "Spotlight/ Parts"],
|
||||
"10543": ["Body", "Lighting"],
|
||||
"10544": ["Electrics", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
|
||||
"10547": ["Electrics", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
|
||||
"10552": ["Belt Drive", "Timing Belt / Set"],
|
||||
"10553": ["Belt Drive", "Timing Belt / Set"],
|
||||
"10554": ["Electrics", "Lights", "Combination Rearlight/-Parts"],
|
||||
"10556": ["Electrics", "Lights", "Combination Rearlight/-Parts"],
|
||||
"10557": ["Belt Drive", "Timing Belt / Set"],
|
||||
"10560": ["Body", "Lighting"],
|
||||
"10561": ["Belt Drive", "Timing Belt / Set"],
|
||||
"10563": ["Electrics", "Lights", "Indicator/ Parts"],
|
||||
"10564": ["Electrics", "Lights", "Licence Plate Light/-Parts"],
|
||||
"10565": ["Electrics", "Lights", "Rear Fog Light/ Parts"],
|
||||
"10566": ["Electrics", "Lights", "Reverse Light/ Parts"],
|
||||
"10567": ["Body", "Lighting"],
|
||||
"10568": ["Electrics", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"10569": ["Electrics", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"10570": ["Engine", "Lubrication"],
|
||||
"10571": ["Body", "Lighting"],
|
||||
"10572": ["Engine", "Lubrication"],
|
||||
"10574": ["Engine", "Lubrication"],
|
||||
"10575": ["Engine", "Lubrication"],
|
||||
"10577": ["Engine"],
|
||||
"10578": ["Engine", "Lubrication"],
|
||||
"10579": ["Engine", "Lubrication"],
|
||||
"10580": ["Body", "Lighting"],
|
||||
"10581": ["Engine", "Lubrication"],
|
||||
"10582": ["Body"],
|
||||
"10583": ["Engine", "Lubrication", "Oil Cooler/ Parts"],
|
||||
"10584": ["Body", "Lighting"],
|
||||
"10586": ["Body", "Lighting"],
|
||||
"10587": ["Body", "Lighting"],
|
||||
"10588": ["Engine", "Lubrication", "Oil Cooler/ Parts"],
|
||||
"10589": ["Engine", "Lubrication", "Oil Pan/ Parts"],
|
||||
"10590": ["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"],
|
||||
"10595": ["Engine"],
|
||||
"10596": ["Electrics", "Lights", "Stop Light/ Parts"],
|
||||
"10598": ["Electrics", "Lights", "Indicator/ Parts"],
|
||||
"10599": ["Electrics", "Lights", "Licence Plate Light/-Parts"],
|
||||
"10600": ["Electrics", "Lights", "Rear Fog Light/ Parts"],
|
||||
"10601": ["Electrics", "Lights", "Reverse Light/ Parts"],
|
||||
"10603": ["Electrics", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"10605": ["Electrics", "Lights", "Interior Lights"],
|
||||
"10606": ["Engine"],
|
||||
"10607": ["Electrics", "Lights", "Interior Lights"],
|
||||
"10608": ["Electrics", "Lights", "Interior Lights"],
|
||||
"10609": ["Electrics", "Light Switches/ Relays/ Controls"],
|
||||
"10610": ["Electrics"],
|
||||
"10611": ["Electrics"],
|
||||
"10612": ["Engine"],
|
||||
"10613": ["Engine"],
|
||||
"10616": ["Body"],
|
||||
"10617": ["Engine", "Crankshaft Drive"],
|
||||
"10618": ["Engine", "Crankshaft Drive"],
|
||||
"10619": ["Engine", "Crankshaft Drive"],
|
||||
"10620": ["Engine", "Crankshaft Drive"],
|
||||
"10621": ["Engine", "Crankshaft Drive"],
|
||||
"10622": ["Engine", "Crankshaft Drive", "Crankshaft"],
|
||||
"10623": ["Engine", "Crankshaft Drive", "Crankshaft"],
|
||||
"10624": ["Engine", "Crankshaft Drive", "Connecting Rod Assembly"],
|
||||
"10625": ["Engine", "Crankshaft Drive", "Connecting Rod Assembly"],
|
||||
"10627": ["Engine", "Crankshaft Drive", "Connecting Rod Assembly"],
|
||||
"10628": ["Engine", "Crankshaft Drive", "Connecting Rod Assembly"],
|
||||
"10629": ["Engine", "Crankshaft Drive", "Piston Assembly"],
|
||||
"10630": ["Engine", "Crankshaft Drive", "Piston Assembly"],
|
||||
"10631": ["Engine", "Crankshaft Drive", "Piston Assembly"],
|
||||
"10632": ["Engine", "Crankshaft Drive", "Piston Assembly"],
|
||||
"10633": ["Engine", "Crankcase"],
|
||||
"10634": ["Engine", "Crankcase"],
|
||||
"10635": ["Engine"],
|
||||
"10636": ["Engine", "Engine Mountings"],
|
||||
"10637": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10638": ["Engine", "Engine Mountings"],
|
||||
"10639": ["Engine"],
|
||||
"10642": ["Engine", "Exhaust Emission Control"],
|
||||
"10643": ["Fuel Mixture Formation"],
|
||||
"10651": ["Engine", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
|
||||
"10652": ["Engine", "Exhaust Emission Control"],
|
||||
"10653": ["Electrics", "Instruments"],
|
||||
"10655": ["Electrics", "Instruments"],
|
||||
"10656": ["Engine", "Exhaust Emission Control", "Secondary Air Injection"],
|
||||
"10659": ["Engine", "Exhaust Emission Control", "Secondary Air Injection"],
|
||||
"10660": ["Engine", "Exhaust Emission Control", "Secondary Air Injection"],
|
||||
"10661": ["Electrics", "Instruments"],
|
||||
"10665": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10666": ["Body", "Windows/ Mirrors"],
|
||||
"10667": ["Body", "Windows/ Mirrors", "Windows"],
|
||||
"10668": ["Body", "Windows/ Mirrors", "Windows"],
|
||||
"10669": ["Body", "Windows/ Mirrors", "Windows"],
|
||||
"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"],
|
||||
"10674": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10677": ["Axle Mounting/ Steering/ Wheels", "Stabilizer/ Fasteners"],
|
||||
"10678": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
|
||||
"10679": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
|
||||
"10680": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
|
||||
"10681": ["Axle Mounting/ Steering/ Wheels", "Joints"],
|
||||
"10685": ["Axle Mounting/ Steering/ Wheels", "Axle Support / Axle Body / Axle Mounting"],
|
||||
"10686": ["Axle Mounting/ Steering/ Wheels", "Axle Support / Axle Body / Axle Mounting"],
|
||||
"10687": ["Axle Mounting/ Steering/ Wheels", "Stub Axle Repair Kit"],
|
||||
"10688": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10689": ["Axle Mounting/ Steering/ Wheels", "Stub Axle Repair Kit"],
|
||||
"10690": ["Axle Mounting/ Steering/ Wheels", "Stabilizer/ Fasteners"],
|
||||
"10691": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10692": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10693": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10694": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10696": ["Axle Mounting/ Steering/ Wheels", "Stabilizer/ Fasteners"],
|
||||
"10697": ["Maintenance Service Parts"],
|
||||
"10698": ["Maintenance Service Parts"],
|
||||
"10701": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10702": ["Axle Mounting/ Steering/ Wheels", "Tie Rod Assembly/ Parts"],
|
||||
"10703": ["Axle Mounting/ Steering/ Wheels", "Tie Rod Assembly/ Parts"],
|
||||
"10706": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10707": ["Towbar/ Parts"],
|
||||
"10708": ["Towbar/ Parts"],
|
||||
"10709": ["Towbar/ Parts"],
|
||||
"10710": ["Windscreen Cleaning System"],
|
||||
"10711": ["Windscreen Cleaning System"],
|
||||
"10712": ["Body"],
|
||||
"10713": ["Windscreen Cleaning System"],
|
||||
"10714": ["Comfort Systems"],
|
||||
"10715": ["Comfort Systems"],
|
||||
"10716": ["Electrics"],
|
||||
"10717": ["Comfort Systems"],
|
||||
"10718": ["Comfort Systems"],
|
||||
"10719": ["Comfort Systems"],
|
||||
"10721": ["Comfort Systems", "Motor/ Relay/ Switch"],
|
||||
"10722": ["Comfort Systems", "Motor/ Relay/ Switch"],
|
||||
"10723": ["Comfort Systems", "Motor/ Relay/ Switch"],
|
||||
"10724": ["Body"],
|
||||
"10725": ["Comfort Systems"],
|
||||
"10726": ["Brake System"],
|
||||
"10730": ["Brake System", "Disc Brake"],
|
||||
"10731": ["Brake System"],
|
||||
"10734": ["Brake System", "Drum Brake"],
|
||||
"10735": ["Brake System"],
|
||||
"10773": ["Interior Equipment"],
|
||||
"10780": ["Security Systems"],
|
||||
"10782": ["Engine", "Gaskets"],
|
||||
"10783": ["Engine", "Gaskets"],
|
||||
"10784": ["Engine", "Gaskets"],
|
||||
"10786": ["Locking System"],
|
||||
"10787": ["Locking System"],
|
||||
"10788": ["Locking System"],
|
||||
"10789": ["Locking System"],
|
||||
"10790": ["Locking System"],
|
||||
"10791": ["Locking System"],
|
||||
"10793": ["Information/ Communication Systems"],
|
||||
"10794": ["Information/ Communication Systems"],
|
||||
"10795": ["Information/ Communication Systems"],
|
||||
"10796": ["Information/ Communication Systems"],
|
||||
"10797": ["Information/ Communication Systems"],
|
||||
"10799": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10800": ["Engine"],
|
||||
"10801": ["Engine", "Complete Engine/ Sub-Assembly"],
|
||||
"10802": ["Engine", "Complete Engine/ Sub-Assembly"],
|
||||
"10803": ["Axle Drive"],
|
||||
"10804": ["Engine", "Engine Air Supply"],
|
||||
"10806": ["Engine", "Engine Air Supply", "Throttle/ Sensor"],
|
||||
"10807": ["Axle Drive", "Propshaft"],
|
||||
"10808": ["Electrics"],
|
||||
"10812": ["Clutch/ Parts", "Clutch Control"],
|
||||
"10813": ["Engine"],
|
||||
"10814": ["Exhaust System"],
|
||||
"10815": ["Exhaust System"],
|
||||
"10817": ["Fuel Supply System", "Fuel Pump / Parts"],
|
||||
"10818": ["Fuel Supply System", "Fuel Pump / Parts"],
|
||||
"10819": ["Engine"],
|
||||
"10823": ["Electrics", "Headlight/ Parts"],
|
||||
"10824": ["Electrics", "Light Switches/ Relays/ Controls"],
|
||||
"10825": ["Heater"],
|
||||
"10826": ["Heater"],
|
||||
"10827": ["Electrics"],
|
||||
"10828": ["Electrics"],
|
||||
"10829": ["Engine", "Exhaust Emission Control"],
|
||||
"10830": ["Interior Equipment"],
|
||||
"10832": ["Air Conditioning"],
|
||||
"10833": [],
|
||||
"10835": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10837": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10839": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"10840": ["Body", "Trim/ Protection/ Decorative Strips/ Emblems"],
|
||||
"10841": ["Body", "Trim/ Protection/ Decorative Strips/ Emblems"],
|
||||
"10845": ["Body", "Windows/ Mirrors"],
|
||||
"10851": ["Comfort Systems"],
|
||||
"10852": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10853": ["Electrics", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"10854": ["Engine"],
|
||||
"10857": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10858": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10859": ["Engine", "Crankshaft Drive", "Crankshaft"],
|
||||
"10860": ["Engine", "Crankcase"],
|
||||
"10861": ["Axle Mounting/ Steering/ Wheels", "Axle Support / Axle Body / Axle Mounting"],
|
||||
"10862": ["Security Systems"],
|
||||
"10866": ["Locking System"],
|
||||
"10867": ["Engine", "Crankcase"],
|
||||
"10868": ["Axle Drive"],
|
||||
"10869": ["Transmission", "Manual Transmission"],
|
||||
"10870": ["Transmission", "Automatic Transmission"],
|
||||
"10872": ["Transmission", "Manual Transmission"],
|
||||
"10873": ["Transmission", "Automatic Transmission"],
|
||||
"10874": ["Transmission", "Manual Transmission"],
|
||||
"10875": ["Transmission", "Automatic Transmission"],
|
||||
"10876": ["Transmission", "Automatic Transmission"],
|
||||
"10877": ["Heater"],
|
||||
"10878": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
|
||||
"10879": ["Air Conditioning"],
|
||||
"10880": ["Clutch/ Parts"],
|
||||
"10885": ["Electrics"],
|
||||
"10886": ["Engine"],
|
||||
"10888": ["Engine"],
|
||||
"10889": ["Engine", "Gaskets"],
|
||||
"10891": ["Fuel Mixture Formation", "Exhaust Emission Control"],
|
||||
"10892": ["Fuel Mixture Formation", "Exhaust Emission Control"],
|
||||
"10893": ["Fuel Mixture Formation", "Exhaust Emission Control"],
|
||||
"10894": ["Air Conditioning"],
|
||||
"10903": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
|
||||
"10905": ["Axle Drive", "Propshaft"],
|
||||
"10906": ["Brake System", "Brake Calipers"],
|
||||
"10907": ["Brake System", "Brake Calipers"],
|
||||
"10908": ["Fuel Mixture Formation"],
|
||||
"10909": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10910": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10911": [
|
||||
"Fuel Mixture Formation",
|
||||
"Exhaust Emission Control",
|
||||
"Exhaust Gas Recirculation (EGR)",
|
||||
],
|
||||
"10912": ["Engine"],
|
||||
"10918": ["Engine", "Engine Air Supply"],
|
||||
"10919": ["Locking System"],
|
||||
"10921": ["Fuel Mixture Formation", "Exhaust Emission Control", "Secondary Air Intake"],
|
||||
"10922": ["Fuel Mixture Formation", "Exhaust Emission Control", "Secondary Air Intake"],
|
||||
"10925": ["Fuel Mixture Formation", "Exhaust Emission Control", "Secondary Air Intake"],
|
||||
"10926": ["Body"],
|
||||
"10927": ["Spark/ Glow Ignition"],
|
||||
"10931": ["Clutch/ Parts"],
|
||||
"10932": ["Clutch/ Parts"],
|
||||
"10934": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"10936": ["Comfort Systems"],
|
||||
"10938": ["Engine"],
|
||||
"10939": ["Axle Drive", "Propshaft"],
|
||||
"10940": ["Cooling System", "Hoses/ Pipes/ Flanges"],
|
||||
"10948": ["Electrics"],
|
||||
"10950": ["Comfort Systems"],
|
||||
"10952": ["Engine"],
|
||||
"10954": ["Accessories"],
|
||||
"10957": ["Accessories"],
|
||||
"10958": ["Accessories"],
|
||||
"10960": ["Accessories"],
|
||||
"10962": ["Accessories"],
|
||||
"10963": ["Comfort Systems"],
|
||||
"10965": ["Air Conditioning"],
|
||||
"10967": ["Electrics", "Lights", "Stop Light/ Parts"],
|
||||
"10969": ["Electrics", "Auxiliary Lights/ Parts"],
|
||||
"10970": ["Electrics", "Lights"],
|
||||
"10972": ["Exhaust System"],
|
||||
"10974": ["Engine"],
|
||||
"10976": ["Engine"],
|
||||
"10978": ["Electrics"],
|
||||
"10979": ["Electrics"],
|
||||
"10980": ["Comfort Systems", "Motor/ Relay/ Switch"],
|
||||
"10981": ["Comfort Systems", "Motor/ Relay/ Switch"],
|
||||
"10982": ["Comfort Systems", "Motor/ Relay/ Switch"],
|
||||
"10983": ["Electrics"],
|
||||
"10984": ["Body", "Lighting"],
|
||||
"10985": ["Engine", "Lubrication", "Oil Pump/ Parts"],
|
||||
"10986": ["Engine", "Crankshaft Drive", "Crankshaft"],
|
||||
"11441": ["Body", "Auxiliary Lights/ Parts"],
|
||||
"11442": ["Body", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
|
||||
"11443": ["Body", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
|
||||
"11444": ["Body", "Auxiliary Lights/ Parts", "Fog Light/ Parts"],
|
||||
"11445": ["Body", "Auxiliary Lights/ Parts"],
|
||||
"11446": ["Body", "Auxiliary Lights/ Parts", "Spotlight/ Parts"],
|
||||
"11447": ["Body", "Auxiliary Lights/ Parts", "Spotlight/ Parts"],
|
||||
"11448": ["Body", "Lighting"],
|
||||
"11508": ["Body", "Lights"],
|
||||
"11509": ["Body", "Lights", "Combination Rearlight/-Parts"],
|
||||
"11510": ["Body", "Lights", "Combination Rearlight/-Parts"],
|
||||
"11511": ["Body", "Lights"],
|
||||
"11512": ["Body", "Lights", "Taillight/ Parts"],
|
||||
"11513": ["Body", "Lighting"],
|
||||
"11514": ["Body", "Lights", "Taillight/ Parts"],
|
||||
"11515": ["Body", "Lights"],
|
||||
"11516": ["Body", "Lights", "Stop Light/ Parts"],
|
||||
"11517": ["Body", "Lighting"],
|
||||
"11518": ["Body", "Lighting"],
|
||||
"11519": ["Body", "Lights", "Stop Light/ Parts"],
|
||||
"11521": ["Body", "Lights", "Indicator/ Parts"],
|
||||
"11522": ["Body", "Lighting"],
|
||||
"11523": ["Body", "Lights", "Indicator/ Parts"],
|
||||
"11524": ["Body", "Lights"],
|
||||
"11525": ["Body", "Lights", "Licence Plate Light/-Parts"],
|
||||
"11526": ["Body"],
|
||||
"11527": ["Body", "Lights", "Licence Plate Light/-Parts"],
|
||||
"11528": ["Body", "Lights"],
|
||||
"11529": ["Body", "Lights", "Rear Fog Light/ Parts"],
|
||||
"11530": ["Body", "Lighting"],
|
||||
"11531": ["Body", "Lights", "Rear Fog Light/ Parts"],
|
||||
"11532": ["Body", "Lights"],
|
||||
"11533": ["Body", "Lights", "Reverse Light/ Parts"],
|
||||
"11534": ["Body", "Lighting"],
|
||||
"11535": ["Body", "Lights", "Reverse Light/ Parts"],
|
||||
"11542": ["Body", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"11543": ["Body", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"11544": ["Body", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"11545": ["Body", "Lights", "Side-/Marker Light/-Parts"],
|
||||
"11546": ["Engine"],
|
||||
"11552": ["Body", "Lights"],
|
||||
"11554": ["Body"],
|
||||
"11566": ["Body", "Headlight/ Parts"],
|
||||
"11567": ["Body", "Headlight/ Parts"],
|
||||
"11568": ["Body", "Headlight/ Parts"],
|
||||
"11569": ["Body"],
|
||||
"11582": ["Belt Drive"],
|
||||
"11585": ["Engine", "Engine Timing Control", "Timing Chain/ Tensioner/ Guide"],
|
||||
"11595": ["Electrics", "Lights", "Combination Rearlight/-Parts"],
|
||||
"11604": ["Body", "Body Parts/ Wing/ Bumper"],
|
||||
"11749": ["Body", "Vehicle Front"],
|
||||
"11750": ["Body", "Vehicle Front"],
|
||||
"11752": ["Body", "Vehicle Front"],
|
||||
"11754": ["Body", "Vehicle Front"],
|
||||
"11755": ["Body", "Vehicle Front"],
|
||||
"11757": ["Body", "Vehicle Front", "Headlight/ Parts"],
|
||||
"11758": ["Body", "Vehicle Front", "Headlight/ Parts"],
|
||||
"11759": ["Body", "Vehicle Front", "Headlight/ Parts"],
|
||||
"11760": ["Body"],
|
||||
"11761": ["Body", "Vehicle Front"],
|
||||
"11762": ["Body", "Vehicle Front", "Fog Light/ Parts"],
|
||||
"11763": ["Body", "Vehicle Front", "Fog Light/ Parts"],
|
||||
"11764": ["Body", "Vehicle Front", "Fog Light/ Parts"],
|
||||
"11765": ["Body", "Vehicle Front"],
|
||||
"11766": ["Body", "Vehicle Front", "Spotlight/ Parts"],
|
||||
"11767": ["Body", "Vehicle Front", "Spotlight/ Parts"],
|
||||
"11768": ["Body", "Lighting"],
|
||||
"11770": ["Body", "Vehicle Front", "Indicator/ Parts"],
|
||||
"11771": ["Body", "Lighting"],
|
||||
"11775": ["Body", "Vehicle Front", "Parts"],
|
||||
"11779": ["Body", "Vehicle Front", "Parts"],
|
||||
"11791": ["Body", "Passenger Cabin"],
|
||||
"11792": ["Body", "Passenger Cabin"],
|
||||
"11793": ["Body", "Passenger Cabin"],
|
||||
"11794": ["Body", "Passenger Cabin"],
|
||||
"11795": ["Body", "Passenger Cabin"],
|
||||
"11796": ["Body", "Passenger Cabin"],
|
||||
"11797": ["Body", "Passenger Cabin"],
|
||||
"11798": ["Body", "Passenger Cabin"],
|
||||
"11799": ["Body", "Passenger Cabin"],
|
||||
"11802": ["Body", "Passenger Cabin", "Parts"],
|
||||
"11803": ["Body", "Passenger Cabin", "Parts"],
|
||||
"11806": ["Body", "Vehicle Rear"],
|
||||
"11807": ["Body"],
|
||||
"11808": ["Body", "Vehicle Rear"],
|
||||
"11810": ["Body", "Vehicle Rear"],
|
||||
"11815": ["Body", "Vehicle Rear"],
|
||||
"11816": ["Body", "Vehicle Rear", "Combination Rearlight/-Parts"],
|
||||
"11817": ["Body", "Vehicle Rear", "Combination Rearlight/-Parts"],
|
||||
"11818": ["Body", "Vehicle Rear"],
|
||||
"11819": ["Body", "Vehicle Rear", "Taillight/ Parts"],
|
||||
"11820": ["Body", "Lighting"],
|
||||
"11821": ["Body", "Vehicle Rear", "Taillight/ Parts"],
|
||||
"11822": ["Body", "Vehicle Rear"],
|
||||
"11823": ["Body", "Vehicle Rear", "Stop Light/ Parts"],
|
||||
"11824": ["Body", "Lighting"],
|
||||
"11825": ["Body", "Lighting"],
|
||||
"11826": ["Body", "Vehicle Rear", "Stop Light/ Parts"],
|
||||
"11828": ["Body", "Vehicle Rear", "Indicator/ Parts"],
|
||||
"11829": ["Body", "Lighting"],
|
||||
"11831": ["Body", "Vehicle Rear"],
|
||||
"11832": ["Body", "Vehicle Rear", "Licence Plate Light/-Parts"],
|
||||
"11833": ["Body"],
|
||||
"11834": ["Body", "Vehicle Rear", "Licence Plate Light/-Parts"],
|
||||
"11835": ["Body", "Vehicle Rear"],
|
||||
"11836": ["Body", "Vehicle Rear", "Rear Fog Light/ Parts"],
|
||||
"11837": ["Body", "Lighting"],
|
||||
"11838": ["Body", "Vehicle Rear", "Rear Fog Light/ Parts"],
|
||||
"11839": ["Body", "Vehicle Rear"],
|
||||
"11840": ["Body", "Vehicle Rear", "Reverse Light/ Parts"],
|
||||
"11841": ["Body", "Lighting"],
|
||||
"11842": ["Body", "Vehicle Rear", "Reverse Light/ Parts"],
|
||||
"11850": ["Body", "Vehicle Rear", "Parts"],
|
||||
"11851": ["Body", "Vehicle Rear", "Parts"],
|
||||
"11852": ["Body", "Vehicle Rear", "Parts"],
|
||||
"11863": ["Body", "Vehicle Rear"],
|
||||
"11865": ["Body"],
|
||||
"11867": ["Body", "Vehicle Front", "Side-/Marker Light/-Parts"],
|
||||
"11868": ["Body", "Vehicle Front", "Side-/Marker Light/-Parts"],
|
||||
"11869": ["Body", "Vehicle Front", "Side-/Marker Light/-Parts"],
|
||||
"11870": ["Body", "Vehicle Front", "Side-/Marker Light/-Parts"],
|
||||
"11871": ["Engine"],
|
||||
"11873": ["Body", "Vehicle Front", "Parts"],
|
||||
"11874": ["Body", "Vehicle Front", "Parts"],
|
||||
"11875": ["Engine"],
|
||||
"11877": ["Body", "Vehicle Front", "Parts"],
|
||||
"11879": ["Body", "Vehicle Rear"],
|
||||
"11880": ["Body", "Vehicle Rear"],
|
||||
"11881": ["Body", "Vehicle Rear"],
|
||||
"11882": ["Body", "Vehicle Rear"],
|
||||
"11884": ["Body", "Vehicle Rear"],
|
||||
"11886": ["Body", "Vehicle Rear", "Side-/Marker Light/-Parts"],
|
||||
"11887": ["Body", "Vehicle Rear", "Side-/Marker Light/-Parts"],
|
||||
"11888": ["Body", "Vehicle Rear", "Side-/Marker Light/-Parts"],
|
||||
"11889": ["Body", "Vehicle Rear", "Side-/Marker Light/-Parts"],
|
||||
"11890": ["Engine"],
|
||||
"11894": ["Electrics", "Lights", "Interior Lights"],
|
||||
"11903": ["Electrics", "Lights", "Interior Lights"],
|
||||
"11908": ["Transmission", "Manual Transmission"],
|
||||
"11909": ["Transmission", "Manual Transmission"],
|
||||
"11910": ["Transmission", "Automatic Transmission"],
|
||||
"11912": ["Transmission", "Automatic Transmission"],
|
||||
"11914": ["Transmission"],
|
||||
"11915": ["Transmission", "Automatic Transmission"],
|
||||
"11917": ["Transmission", "Automatic Transmission"],
|
||||
"11926": ["Engine"],
|
||||
"11933": ["Engine", "Engine Timing Control"],
|
||||
"11953": ["Transmission", "Automatic Transmission"],
|
||||
"11954": ["Transmission", "Automatic Transmission", "Oil Pan/ Parts"],
|
||||
"11955": ["Transmission", "Automatic Transmission", "Oil Pan/ Parts"],
|
||||
"11957": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"11984": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"12071": ["Belt Drive"],
|
||||
"12093": ["Transmission", "Manual Transmission"],
|
||||
"12094": ["Engine", "Lubrication"],
|
||||
"12096": ["Axle Drive"],
|
||||
"12115": ["Engine", "Engine Timing Control", "Timing Belt/ Tensioner/ Guide"],
|
||||
"12116": ["Belt Drive", "Timing Belt / Set"],
|
||||
"12173": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"12176": ["Engine", "Engine Air Supply", "Charger (Turbo-/ Supercharger)"],
|
||||
"12180": ["Clutch/ Parts", "Releaser, clutch"],
|
||||
"12182": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"12301": ["Engine"],
|
||||
"12303": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"12305": ["Cooling System"],
|
||||
"12308": ["Brake System"],
|
||||
"12311": ["Cooling System", "Water Pump/ Gasket"],
|
||||
"12315": ["Brake System"],
|
||||
"12319": ["Heater"],
|
||||
"12335": ["Engine", "Engine Air Supply"],
|
||||
"12339": ["Belt Drive"],
|
||||
"12344": ["Brake System", "Disc Brake"],
|
||||
"12348": ["Brake System"],
|
||||
"12350": ["Axle Mounting/ Steering/ Wheels", "Wheel Hub / Mounting"],
|
||||
"12436": ["Electrics"],
|
||||
"12439": ["Engine", "Engine Air Supply", "Throttle/ Sensor"],
|
||||
"12506": ["Body", "Lights", "Indicator/ Parts"],
|
||||
"12514": ["Body"],
|
||||
"12547": ["Cooling System"],
|
||||
"12550": ["Engine", "Cylinder Head/ Parts"],
|
||||
"12551": ["Exhaust System"],
|
||||
"12703": ["Fuel Supply System"],
|
||||
"12761": ["Electrics"],
|
||||
"12771": ["Electrics", "Auxiliary Lights/ Parts"],
|
||||
"12783": ["Engine", "Crankshaft Drive", "Crankshaft"],
|
||||
"12785": ["Transmission", "Manual Transmission"],
|
||||
"12789": ["Interior Equipment"],
|
||||
"12790": ["Interior Equipment"],
|
||||
"12791": ["Interior Equipment"],
|
||||
"12792": ["Interior Equipment"],
|
||||
"12793": ["Interior Equipment"],
|
||||
"12794": ["Interior Equipment"],
|
||||
"12795": ["Interior Equipment"],
|
||||
"12796": ["Interior Equipment"],
|
||||
"12797": ["Interior Equipment"],
|
||||
"12798": ["Interior Equipment"],
|
||||
"12806": ["Interior Equipment"],
|
||||
"12836": ["Comfort Systems"],
|
||||
"12847": ["Electrics"],
|
||||
"12854": ["Clutch/ Parts"],
|
||||
"12858": ["Body", "Passenger Cabin"],
|
||||
"12860": ["Body", "Hatches/Hoods/Doors/Sunroof/Folding Roof"],
|
||||
"12863": ["Brake System"],
|
||||
"12866": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"12878": ["Engine", "Cylinder Head/ Parts"],
|
||||
"12881": ["Transmission", "Manual Transmission"],
|
||||
"12883": ["Transmission", "Automatic Transmission"],
|
||||
"12894": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12895": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12896": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12898": ["Fuel Mixture Formation"],
|
||||
"12899": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12900": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12901": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12902": ["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"],
|
||||
"12907": ["Engine"],
|
||||
"12908": ["Electrics"],
|
||||
"12909": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12910": ["Fuel Mixture Formation", "Mixture Formation"],
|
||||
"12911": ["Engine"],
|
||||
"12975": ["Exhaust System"],
|
||||
"12977": ["Clutch/ Parts"],
|
||||
"12998": ["Exhaust System"],
|
||||
"13001": ["Fuel Mixture Formation"],
|
||||
"13004": ["Fuel Mixture Formation", "Carburettor System"],
|
||||
"13005": ["Fuel Mixture Formation"],
|
||||
"13006": ["Fuel Mixture Formation", "Carburettor System"],
|
||||
"13007": ["Fuel Mixture Formation"],
|
||||
"13008": ["Fuel Mixture Formation", "Carburettor System"],
|
||||
"13009": ["Fuel Mixture Formation", "Carburettor System"],
|
||||
"13010": ["Fuel Mixture Formation", "Carburettor System"],
|
||||
"13011": ["Fuel Mixture Formation", "Carburettor System"],
|
||||
"13022": ["Air Conditioning"],
|
||||
"13028": ["Engine"],
|
||||
"13030": ["Electrics"],
|
||||
"13031": ["Transmission", "Automatic Transmission"],
|
||||
"13064": ["Brake System", "Drum Brake"],
|
||||
"13065": ["Brake System", "Drum Brake"],
|
||||
"13092": [
|
||||
"Fuel Mixture Formation",
|
||||
"Exhaust Emission Control",
|
||||
"Exhaust Gas Recirculation (EGR)",
|
||||
],
|
||||
"13093": ["Engine", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
|
||||
"13098": ["Interior Equipment"],
|
||||
"13104": ["Interior Equipment"],
|
||||
"13119": ["Exhaust System"],
|
||||
"13120": ["Fuel Mixture Formation"],
|
||||
"13121": ["Fuel Mixture Formation"],
|
||||
"13122": ["Exhaust System", "Urea Injection (AdBlue)"],
|
||||
"13123": ["Fuel Mixture Formation"],
|
||||
"13135": ["Body", "Vehicle Front"],
|
||||
"13137": ["Engine"],
|
||||
"13146": ["Comfort Systems", "Motor/ Relay/ Switch"],
|
||||
"13147": ["Fuel Mixture Formation", "Exhaust Emission Control"],
|
||||
"13162": ["Exhaust System", "Urea Injection (AdBlue)"],
|
||||
"13164": ["Body", "Vehicle Front", "Parts"],
|
||||
"13165": ["Transmission", "Manual Transmission"],
|
||||
"13166": ["Electrics"],
|
||||
"13177": ["Fuel Supply System"],
|
||||
"13186": ["Fuel Mixture Formation"],
|
||||
"13189": ["Exhaust System", "Urea Injection (AdBlue)"],
|
||||
"13191": ["Electrics"],
|
||||
"13198": ["Body"],
|
||||
"13199": [],
|
||||
"13200": ["Wheels/Tyres"],
|
||||
"13201": ["Wheels/Tyres"],
|
||||
"13202": ["Wheels/Tyres"],
|
||||
"13203": ["Transmission"],
|
||||
"13209": ["Transmission", "Automatic Transmission"],
|
||||
"13210": ["Cooling System"],
|
||||
"13211": ["Exhaust System", "Assembly Parts", "Individual Assembly Parts"],
|
||||
"13218": ["Body", "Lighting"],
|
||||
"13220": ["Engine", "Crankshaft Drive"],
|
||||
"13233": ["Axle Mounting/ Steering/ Wheels"],
|
||||
"13236": ["Accessories"],
|
||||
"13239": ["Accessories"],
|
||||
"13256": ["Clutch/ Parts"],
|
||||
"13271": ["Compressed Air System"],
|
||||
"13293": ["Brake System"],
|
||||
"13295": ["Brake System"],
|
||||
"13297": ["Engine"],
|
||||
"13298": ["Compressed Air System"],
|
||||
"13300": ["Compressed Air System", "Valves/Compressed-air System"],
|
||||
"13302": ["Transmission"],
|
||||
"13303": ["Engine"],
|
||||
"13309": ["Transmission"],
|
||||
"13310": ["Engine"],
|
||||
"13317": ["Engine"],
|
||||
"13335": ["Engine", "Exhaust Emission Control", "Exhaust Gas Recirculation (EGR)"],
|
||||
"13336": ["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)"],
|
||||
"13339": [
|
||||
"Fuel Mixture Formation",
|
||||
"Exhaust Emission Control",
|
||||
"Exhaust Gas Recirculation (EGR)",
|
||||
],
|
||||
"13340": [
|
||||
"Fuel Mixture Formation",
|
||||
"Exhaust Emission Control",
|
||||
"Exhaust Gas Recirculation (EGR)",
|
||||
],
|
||||
"13341": [
|
||||
"Fuel Mixture Formation",
|
||||
"Exhaust Emission Control",
|
||||
"Exhaust Gas Recirculation (EGR)",
|
||||
],
|
||||
"13370": ["Engine", "Crankshaft Drive", "Piston Assembly"],
|
||||
"13372": ["Interior Equipment"],
|
||||
"13374": ["Accessories"],
|
||||
};
|
||||
@@ -48,12 +48,25 @@
|
||||
"locked": "This brand is not in your plan",
|
||||
"upgradeCta": "Upgrade Plan",
|
||||
"loadingModels": "Loading models...",
|
||||
"tabSasetr": "Sase.Tr",
|
||||
"tabPl24": "Pl24",
|
||||
"tabPcat": "Pcat",
|
||||
"tabEmex": "Emex",
|
||||
"tabTecdoc": "Tecdoc",
|
||||
"comingSoon": "Coming Soon",
|
||||
"categories": "Categories",
|
||||
"noCategories": "No categories found",
|
||||
"parts": "Parts",
|
||||
"noParts": "No parts found",
|
||||
"partNumber": "Part No",
|
||||
"partName": "Part Name",
|
||||
"qty": "Qty",
|
||||
"backToBrands": "Back to Brands",
|
||||
"backToModels": "Back to Models",
|
||||
"backToCategories": "Back to Categories",
|
||||
"selectCatalog": "Select a catalog",
|
||||
"selectModel": "Select model",
|
||||
"resetSelection": "Reset",
|
||||
"psaVariant": {
|
||||
"title": "Select Vehicle Variant",
|
||||
"subtitle": "Optional — use Show All to browse all variants",
|
||||
|
||||
@@ -48,12 +48,25 @@
|
||||
"locked": "Bu marka planınızda yok",
|
||||
"upgradeCta": "Planını Yükselt",
|
||||
"loadingModels": "Modeller yükleniyor...",
|
||||
"tabSasetr": "Sase.Tr",
|
||||
"tabPl24": "Pl24",
|
||||
"tabPcat": "Pcat",
|
||||
"tabEmex": "Emex",
|
||||
"tabTecdoc": "Tecdoc",
|
||||
"comingSoon": "Yakında",
|
||||
"categories": "Kategoriler",
|
||||
"noCategories": "Kategori bulunamadı",
|
||||
"parts": "Parçalar",
|
||||
"noParts": "Parça bulunamadı",
|
||||
"partNumber": "Parça No",
|
||||
"partName": "Parça Adı",
|
||||
"qty": "Adet",
|
||||
"backToBrands": "Markalara Dön",
|
||||
"backToModels": "Modellere Dön",
|
||||
"backToCategories": "Kategorilere Dön",
|
||||
"selectCatalog": "Bir katalog seçin",
|
||||
"selectModel": "Model seçin",
|
||||
"resetSelection": "Sıfırla",
|
||||
"psaVariant": {
|
||||
"title": "Araç Varyantını Seçin",
|
||||
"subtitle": "İsteğe bağlı — tüm varyantlar için Tümü seçeneğini kullanın",
|
||||
|
||||
@@ -22,6 +22,7 @@ import { Route as AuthRouteImport } from "./routes/_auth"
|
||||
import { Route as IndexRouteImport } from "./routes/index"
|
||||
import { Route as DashboardIndexRouteImport } from "./routes/dashboard/index"
|
||||
import { Route as DashboardSettingsRouteImport } from "./routes/dashboard/settings"
|
||||
import { Route as DashboardServiceTestRouteImport } from "./routes/dashboard/service-test"
|
||||
import { Route as DashboardSearchRouteImport } from "./routes/dashboard/search"
|
||||
import { Route as DashboardHistoryRouteImport } from "./routes/dashboard/history"
|
||||
import { Route as DashboardBillingRouteImport } from "./routes/dashboard/billing"
|
||||
@@ -41,9 +42,16 @@ import { Route as DashboardAdminCopyLogsRouteImport } from "./routes/dashboard/a
|
||||
import { Route as DashboardAdminAnalyticsRouteImport } from "./routes/dashboard/admin/analytics"
|
||||
import { Route as DashboardVehiclesIdIndexRouteImport } from "./routes/dashboard/vehicles_/$id/index"
|
||||
import { Route as DashboardCatalogBrandNameIndexRouteImport } from "./routes/dashboard/catalog_/$brandName/index"
|
||||
import { Route as DashboardCatalogPcatCatalogIdIndexRouteImport } from "./routes/dashboard/catalog_/pcat/$catalogId/index"
|
||||
import { Route as DashboardCatalogEmexCatalogCodeIndexRouteImport } from "./routes/dashboard/catalog_/emex/$catalogCode/index"
|
||||
import { Route as DashboardCatalogBrandNameModelIdIndexRouteImport } from "./routes/dashboard/catalog_/$brandName_/$modelId/index"
|
||||
import { Route as DashboardVehiclesIdCategoriesCategoryIdRouteImport } from "./routes/dashboard/vehicles_/$id/categories_/$categoryId"
|
||||
import { Route as DashboardCatalogPcatCatalogIdModelIdIndexRouteImport } from "./routes/dashboard/catalog_/pcat/$catalogId_/$modelId/index"
|
||||
import { Route as DashboardCatalogEmexCatalogCodeVehicleIdIndexRouteImport } from "./routes/dashboard/catalog_/emex/$catalogCode_/$vehicleId/index"
|
||||
import { Route as DashboardCatalogBrandNameModelIdCategoriesCategoryIdRouteImport } from "./routes/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId"
|
||||
import { Route as DashboardCatalogPcatCatalogIdModelIdCarIdIndexRouteImport } from "./routes/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId/index"
|
||||
import { Route as DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRouteImport } from "./routes/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId"
|
||||
import { Route as DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRouteImport } from "./routes/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId"
|
||||
|
||||
const TermsRoute = TermsRouteImport.update({
|
||||
id: "/terms",
|
||||
@@ -109,6 +117,11 @@ const DashboardSettingsRoute = DashboardSettingsRouteImport.update({
|
||||
path: "/settings",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardServiceTestRoute = DashboardServiceTestRouteImport.update({
|
||||
id: "/service-test",
|
||||
path: "/service-test",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardSearchRoute = DashboardSearchRouteImport.update({
|
||||
id: "/search",
|
||||
path: "/search",
|
||||
@@ -208,6 +221,18 @@ const DashboardCatalogBrandNameIndexRoute =
|
||||
path: "/catalog/$brandName/",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogPcatCatalogIdIndexRoute =
|
||||
DashboardCatalogPcatCatalogIdIndexRouteImport.update({
|
||||
id: "/catalog_/pcat/$catalogId/",
|
||||
path: "/catalog/pcat/$catalogId/",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogEmexCatalogCodeIndexRoute =
|
||||
DashboardCatalogEmexCatalogCodeIndexRouteImport.update({
|
||||
id: "/catalog_/emex/$catalogCode/",
|
||||
path: "/catalog/emex/$catalogCode/",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogBrandNameModelIdIndexRoute =
|
||||
DashboardCatalogBrandNameModelIdIndexRouteImport.update({
|
||||
id: "/catalog_/$brandName_/$modelId/",
|
||||
@@ -220,12 +245,42 @@ const DashboardVehiclesIdCategoriesCategoryIdRoute =
|
||||
path: "/vehicles/$id/categories/$categoryId",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogPcatCatalogIdModelIdIndexRoute =
|
||||
DashboardCatalogPcatCatalogIdModelIdIndexRouteImport.update({
|
||||
id: "/catalog_/pcat/$catalogId_/$modelId/",
|
||||
path: "/catalog/pcat/$catalogId/$modelId/",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute =
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdIndexRouteImport.update({
|
||||
id: "/catalog_/emex/$catalogCode_/$vehicleId/",
|
||||
path: "/catalog/emex/$catalogCode/$vehicleId/",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute =
|
||||
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRouteImport.update({
|
||||
id: "/catalog_/$brandName_/$modelId/categories_/$categoryId",
|
||||
path: "/catalog/$brandName/$modelId/categories/$categoryId",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute =
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdIndexRouteImport.update({
|
||||
id: "/catalog_/pcat/$catalogId_/$modelId_/$carId/",
|
||||
path: "/catalog/pcat/$catalogId/$modelId/$carId/",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute =
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRouteImport.update({
|
||||
id: "/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId",
|
||||
path: "/catalog/emex/$catalogCode/$vehicleId/groups/$groupId",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
const DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute =
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRouteImport.update({
|
||||
id: "/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId",
|
||||
path: "/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId",
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
"/": typeof IndexRoute
|
||||
@@ -246,6 +301,7 @@ export interface FileRoutesByFullPath {
|
||||
"/dashboard/billing": typeof DashboardBillingRoute
|
||||
"/dashboard/history": typeof DashboardHistoryRoute
|
||||
"/dashboard/search": typeof DashboardSearchRoute
|
||||
"/dashboard/service-test": typeof DashboardServiceTestRoute
|
||||
"/dashboard/settings": typeof DashboardSettingsRoute
|
||||
"/dashboard/": typeof DashboardIndexRoute
|
||||
"/dashboard/admin/analytics": typeof DashboardAdminAnalyticsRoute
|
||||
@@ -261,7 +317,14 @@ export interface FileRoutesByFullPath {
|
||||
"/dashboard/vehicles/$id/": typeof DashboardVehiclesIdIndexRoute
|
||||
"/dashboard/vehicles/$id/categories/$categoryId": typeof DashboardVehiclesIdCategoriesCategoryIdRoute
|
||||
"/dashboard/catalog/$brandName/$modelId/": typeof DashboardCatalogBrandNameModelIdIndexRoute
|
||||
"/dashboard/catalog/emex/$catalogCode/": typeof DashboardCatalogEmexCatalogCodeIndexRoute
|
||||
"/dashboard/catalog/pcat/$catalogId/": typeof DashboardCatalogPcatCatalogIdIndexRoute
|
||||
"/dashboard/catalog/$brandName/$modelId/categories/$categoryId": typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
|
||||
"/dashboard/catalog/emex/$catalogCode/$vehicleId/": typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
|
||||
"/dashboard/catalog/pcat/$catalogId/$modelId/": typeof DashboardCatalogPcatCatalogIdModelIdIndexRoute
|
||||
"/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId": typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
|
||||
"/dashboard/catalog/pcat/$catalogId/$modelId/$carId/": typeof DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute
|
||||
"/dashboard/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId": typeof DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute
|
||||
}
|
||||
export interface FileRoutesByTo {
|
||||
"/": typeof IndexRoute
|
||||
@@ -281,6 +344,7 @@ export interface FileRoutesByTo {
|
||||
"/dashboard/billing": typeof DashboardBillingRoute
|
||||
"/dashboard/history": typeof DashboardHistoryRoute
|
||||
"/dashboard/search": typeof DashboardSearchRoute
|
||||
"/dashboard/service-test": typeof DashboardServiceTestRoute
|
||||
"/dashboard/settings": typeof DashboardSettingsRoute
|
||||
"/dashboard": typeof DashboardIndexRoute
|
||||
"/dashboard/admin/analytics": typeof DashboardAdminAnalyticsRoute
|
||||
@@ -296,7 +360,14 @@ export interface FileRoutesByTo {
|
||||
"/dashboard/vehicles/$id": typeof DashboardVehiclesIdIndexRoute
|
||||
"/dashboard/vehicles/$id/categories/$categoryId": typeof DashboardVehiclesIdCategoriesCategoryIdRoute
|
||||
"/dashboard/catalog/$brandName/$modelId": typeof DashboardCatalogBrandNameModelIdIndexRoute
|
||||
"/dashboard/catalog/emex/$catalogCode": typeof DashboardCatalogEmexCatalogCodeIndexRoute
|
||||
"/dashboard/catalog/pcat/$catalogId": typeof DashboardCatalogPcatCatalogIdIndexRoute
|
||||
"/dashboard/catalog/$brandName/$modelId/categories/$categoryId": typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
|
||||
"/dashboard/catalog/emex/$catalogCode/$vehicleId": typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
|
||||
"/dashboard/catalog/pcat/$catalogId/$modelId": typeof DashboardCatalogPcatCatalogIdModelIdIndexRoute
|
||||
"/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId": typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
|
||||
"/dashboard/catalog/pcat/$catalogId/$modelId/$carId": typeof DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute
|
||||
"/dashboard/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId": typeof DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute
|
||||
}
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
@@ -319,6 +390,7 @@ export interface FileRoutesById {
|
||||
"/dashboard/billing": typeof DashboardBillingRoute
|
||||
"/dashboard/history": typeof DashboardHistoryRoute
|
||||
"/dashboard/search": typeof DashboardSearchRoute
|
||||
"/dashboard/service-test": typeof DashboardServiceTestRoute
|
||||
"/dashboard/settings": typeof DashboardSettingsRoute
|
||||
"/dashboard/": typeof DashboardIndexRoute
|
||||
"/dashboard/admin/analytics": typeof DashboardAdminAnalyticsRoute
|
||||
@@ -334,7 +406,14 @@ export interface FileRoutesById {
|
||||
"/dashboard/vehicles_/$id/": typeof DashboardVehiclesIdIndexRoute
|
||||
"/dashboard/vehicles_/$id/categories_/$categoryId": typeof DashboardVehiclesIdCategoriesCategoryIdRoute
|
||||
"/dashboard/catalog_/$brandName_/$modelId/": typeof DashboardCatalogBrandNameModelIdIndexRoute
|
||||
"/dashboard/catalog_/emex/$catalogCode/": typeof DashboardCatalogEmexCatalogCodeIndexRoute
|
||||
"/dashboard/catalog_/pcat/$catalogId/": typeof DashboardCatalogPcatCatalogIdIndexRoute
|
||||
"/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId": typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
|
||||
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId/": typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
|
||||
"/dashboard/catalog_/pcat/$catalogId_/$modelId/": typeof DashboardCatalogPcatCatalogIdModelIdIndexRoute
|
||||
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId": typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
|
||||
"/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId/": typeof DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute
|
||||
"/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId": typeof DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute
|
||||
}
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
@@ -357,6 +436,7 @@ export interface FileRouteTypes {
|
||||
| "/dashboard/billing"
|
||||
| "/dashboard/history"
|
||||
| "/dashboard/search"
|
||||
| "/dashboard/service-test"
|
||||
| "/dashboard/settings"
|
||||
| "/dashboard/"
|
||||
| "/dashboard/admin/analytics"
|
||||
@@ -372,7 +452,14 @@ export interface FileRouteTypes {
|
||||
| "/dashboard/vehicles/$id/"
|
||||
| "/dashboard/vehicles/$id/categories/$categoryId"
|
||||
| "/dashboard/catalog/$brandName/$modelId/"
|
||||
| "/dashboard/catalog/emex/$catalogCode/"
|
||||
| "/dashboard/catalog/pcat/$catalogId/"
|
||||
| "/dashboard/catalog/$brandName/$modelId/categories/$categoryId"
|
||||
| "/dashboard/catalog/emex/$catalogCode/$vehicleId/"
|
||||
| "/dashboard/catalog/pcat/$catalogId/$modelId/"
|
||||
| "/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
|
||||
| "/dashboard/catalog/pcat/$catalogId/$modelId/$carId/"
|
||||
| "/dashboard/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId"
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to:
|
||||
| "/"
|
||||
@@ -392,6 +479,7 @@ export interface FileRouteTypes {
|
||||
| "/dashboard/billing"
|
||||
| "/dashboard/history"
|
||||
| "/dashboard/search"
|
||||
| "/dashboard/service-test"
|
||||
| "/dashboard/settings"
|
||||
| "/dashboard"
|
||||
| "/dashboard/admin/analytics"
|
||||
@@ -407,7 +495,14 @@ export interface FileRouteTypes {
|
||||
| "/dashboard/vehicles/$id"
|
||||
| "/dashboard/vehicles/$id/categories/$categoryId"
|
||||
| "/dashboard/catalog/$brandName/$modelId"
|
||||
| "/dashboard/catalog/emex/$catalogCode"
|
||||
| "/dashboard/catalog/pcat/$catalogId"
|
||||
| "/dashboard/catalog/$brandName/$modelId/categories/$categoryId"
|
||||
| "/dashboard/catalog/emex/$catalogCode/$vehicleId"
|
||||
| "/dashboard/catalog/pcat/$catalogId/$modelId"
|
||||
| "/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
|
||||
| "/dashboard/catalog/pcat/$catalogId/$modelId/$carId"
|
||||
| "/dashboard/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId"
|
||||
id:
|
||||
| "__root__"
|
||||
| "/"
|
||||
@@ -429,6 +524,7 @@ export interface FileRouteTypes {
|
||||
| "/dashboard/billing"
|
||||
| "/dashboard/history"
|
||||
| "/dashboard/search"
|
||||
| "/dashboard/service-test"
|
||||
| "/dashboard/settings"
|
||||
| "/dashboard/"
|
||||
| "/dashboard/admin/analytics"
|
||||
@@ -444,7 +540,14 @@ export interface FileRouteTypes {
|
||||
| "/dashboard/vehicles_/$id/"
|
||||
| "/dashboard/vehicles_/$id/categories_/$categoryId"
|
||||
| "/dashboard/catalog_/$brandName_/$modelId/"
|
||||
| "/dashboard/catalog_/emex/$catalogCode/"
|
||||
| "/dashboard/catalog_/pcat/$catalogId/"
|
||||
| "/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId"
|
||||
| "/dashboard/catalog_/emex/$catalogCode_/$vehicleId/"
|
||||
| "/dashboard/catalog_/pcat/$catalogId_/$modelId/"
|
||||
| "/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId"
|
||||
| "/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId/"
|
||||
| "/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId"
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
export interface RootRouteChildren {
|
||||
@@ -555,6 +658,13 @@ declare module "@tanstack/react-router" {
|
||||
preLoaderRoute: typeof DashboardSettingsRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/service-test": {
|
||||
id: "/dashboard/service-test"
|
||||
path: "/service-test"
|
||||
fullPath: "/dashboard/service-test"
|
||||
preLoaderRoute: typeof DashboardServiceTestRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/search": {
|
||||
id: "/dashboard/search"
|
||||
path: "/search"
|
||||
@@ -688,6 +798,20 @@ declare module "@tanstack/react-router" {
|
||||
preLoaderRoute: typeof DashboardCatalogBrandNameIndexRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/pcat/$catalogId/": {
|
||||
id: "/dashboard/catalog_/pcat/$catalogId/"
|
||||
path: "/catalog/pcat/$catalogId"
|
||||
fullPath: "/dashboard/catalog/pcat/$catalogId/"
|
||||
preLoaderRoute: typeof DashboardCatalogPcatCatalogIdIndexRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/emex/$catalogCode/": {
|
||||
id: "/dashboard/catalog_/emex/$catalogCode/"
|
||||
path: "/catalog/emex/$catalogCode"
|
||||
fullPath: "/dashboard/catalog/emex/$catalogCode/"
|
||||
preLoaderRoute: typeof DashboardCatalogEmexCatalogCodeIndexRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/$brandName_/$modelId/": {
|
||||
id: "/dashboard/catalog_/$brandName_/$modelId/"
|
||||
path: "/catalog/$brandName/$modelId"
|
||||
@@ -702,6 +826,20 @@ declare module "@tanstack/react-router" {
|
||||
preLoaderRoute: typeof DashboardVehiclesIdCategoriesCategoryIdRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/pcat/$catalogId_/$modelId/": {
|
||||
id: "/dashboard/catalog_/pcat/$catalogId_/$modelId/"
|
||||
path: "/catalog/pcat/$catalogId/$modelId"
|
||||
fullPath: "/dashboard/catalog/pcat/$catalogId/$modelId/"
|
||||
preLoaderRoute: typeof DashboardCatalogPcatCatalogIdModelIdIndexRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId/": {
|
||||
id: "/dashboard/catalog_/emex/$catalogCode_/$vehicleId/"
|
||||
path: "/catalog/emex/$catalogCode/$vehicleId"
|
||||
fullPath: "/dashboard/catalog/emex/$catalogCode/$vehicleId/"
|
||||
preLoaderRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId": {
|
||||
id: "/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId"
|
||||
path: "/catalog/$brandName/$modelId/categories/$categoryId"
|
||||
@@ -709,6 +847,27 @@ declare module "@tanstack/react-router" {
|
||||
preLoaderRoute: typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId/": {
|
||||
id: "/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId/"
|
||||
path: "/catalog/pcat/$catalogId/$modelId/$carId"
|
||||
fullPath: "/dashboard/catalog/pcat/$catalogId/$modelId/$carId/"
|
||||
preLoaderRoute: typeof DashboardCatalogPcatCatalogIdModelIdCarIdIndexRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId": {
|
||||
id: "/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId"
|
||||
path: "/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
|
||||
fullPath: "/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId"
|
||||
preLoaderRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
"/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId": {
|
||||
id: "/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId"
|
||||
path: "/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId"
|
||||
fullPath: "/dashboard/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId"
|
||||
preLoaderRoute: typeof DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRouteImport
|
||||
parentRoute: typeof DashboardRoute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,6 +891,7 @@ interface DashboardRouteChildren {
|
||||
DashboardBillingRoute: typeof DashboardBillingRoute
|
||||
DashboardHistoryRoute: typeof DashboardHistoryRoute
|
||||
DashboardSearchRoute: typeof DashboardSearchRoute
|
||||
DashboardServiceTestRoute: typeof DashboardServiceTestRoute
|
||||
DashboardSettingsRoute: typeof DashboardSettingsRoute
|
||||
DashboardIndexRoute: typeof DashboardIndexRoute
|
||||
DashboardAdminAnalyticsRoute: typeof DashboardAdminAnalyticsRoute
|
||||
@@ -747,13 +907,21 @@ interface DashboardRouteChildren {
|
||||
DashboardVehiclesIdIndexRoute: typeof DashboardVehiclesIdIndexRoute
|
||||
DashboardVehiclesIdCategoriesCategoryIdRoute: typeof DashboardVehiclesIdCategoriesCategoryIdRoute
|
||||
DashboardCatalogBrandNameModelIdIndexRoute: typeof DashboardCatalogBrandNameModelIdIndexRoute
|
||||
DashboardCatalogEmexCatalogCodeIndexRoute: typeof DashboardCatalogEmexCatalogCodeIndexRoute
|
||||
DashboardCatalogPcatCatalogIdIndexRoute: typeof DashboardCatalogPcatCatalogIdIndexRoute
|
||||
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute: typeof DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute
|
||||
DashboardCatalogPcatCatalogIdModelIdIndexRoute: typeof DashboardCatalogPcatCatalogIdModelIdIndexRoute
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute: typeof DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute: typeof DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute: typeof DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute
|
||||
}
|
||||
|
||||
const DashboardRouteChildren: DashboardRouteChildren = {
|
||||
DashboardBillingRoute: DashboardBillingRoute,
|
||||
DashboardHistoryRoute: DashboardHistoryRoute,
|
||||
DashboardSearchRoute: DashboardSearchRoute,
|
||||
DashboardServiceTestRoute: DashboardServiceTestRoute,
|
||||
DashboardSettingsRoute: DashboardSettingsRoute,
|
||||
DashboardIndexRoute: DashboardIndexRoute,
|
||||
DashboardAdminAnalyticsRoute: DashboardAdminAnalyticsRoute,
|
||||
@@ -771,8 +939,22 @@ const DashboardRouteChildren: DashboardRouteChildren = {
|
||||
DashboardVehiclesIdCategoriesCategoryIdRoute,
|
||||
DashboardCatalogBrandNameModelIdIndexRoute:
|
||||
DashboardCatalogBrandNameModelIdIndexRoute,
|
||||
DashboardCatalogEmexCatalogCodeIndexRoute:
|
||||
DashboardCatalogEmexCatalogCodeIndexRoute,
|
||||
DashboardCatalogPcatCatalogIdIndexRoute:
|
||||
DashboardCatalogPcatCatalogIdIndexRoute,
|
||||
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute:
|
||||
DashboardCatalogBrandNameModelIdCategoriesCategoryIdRoute,
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute:
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdIndexRoute,
|
||||
DashboardCatalogPcatCatalogIdModelIdIndexRoute:
|
||||
DashboardCatalogPcatCatalogIdModelIdIndexRoute,
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute:
|
||||
DashboardCatalogEmexCatalogCodeVehicleIdGroupsGroupIdRoute,
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute:
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdIndexRoute,
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute:
|
||||
DashboardCatalogPcatCatalogIdModelIdCarIdGroupsGroupIdRoute,
|
||||
}
|
||||
|
||||
const DashboardRouteWithChildren = DashboardRoute._addFileChildren(
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
Copy,
|
||||
CreditCard,
|
||||
DollarSign,
|
||||
FlaskConical,
|
||||
History,
|
||||
LayoutDashboard,
|
||||
Library,
|
||||
@@ -69,6 +70,7 @@ const adminItems = [
|
||||
{ to: "/dashboard/admin/analytics", label: "Analitik", icon: BarChart3 },
|
||||
{ to: "/dashboard/admin/copy-logs", label: "OEM Kopyalama", icon: Copy },
|
||||
{ to: "/dashboard/admin/referrals", label: "Referanslar", icon: Share2 },
|
||||
{ to: "/dashboard/service-test", label: "Servis Test", icon: FlaskConical },
|
||||
] as const;
|
||||
|
||||
// ─── HELPERS ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
import { api } from "@/lib/api-client";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { Button, Skeleton } from "@sase/ui";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute } from "@tanstack/react-router";
|
||||
import { AlertCircle, ArrowLeft, Car, ChevronRight, RotateCcw } from "lucide-react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/catalog_/emex/$catalogCode/")({
|
||||
component: EmexVehicleListPage,
|
||||
});
|
||||
|
||||
// ── Types ────────────────────────────────────────────
|
||||
|
||||
interface WizardRow {
|
||||
name: string;
|
||||
value: string | null;
|
||||
determined: boolean;
|
||||
options: WizardOption[];
|
||||
}
|
||||
|
||||
interface WizardOption {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface EmexVehicle {
|
||||
id: string;
|
||||
vehicleId: string;
|
||||
name: string | null;
|
||||
engine: string | null;
|
||||
engineCode: string | null;
|
||||
bodyType: string | null;
|
||||
transmission: string | null;
|
||||
driveType: string | null;
|
||||
fuelType: string | null;
|
||||
yearFrom: number | null;
|
||||
yearTo: number | null;
|
||||
optionsRaw: string | null;
|
||||
}
|
||||
|
||||
// ── Component ────────────────────────────────────────
|
||||
|
||||
function EmexVehicleListPage() {
|
||||
const { t } = useTranslation();
|
||||
const { catalogCode } = Route.useParams();
|
||||
|
||||
// Current SSD state for wizard navigation
|
||||
const [ssd, setSsd] = useState("");
|
||||
|
||||
// Fetch wizard data for current SSD
|
||||
const {
|
||||
data: wizardRows,
|
||||
isLoading: wizardLoading,
|
||||
isError: wizardError,
|
||||
} = useQuery({
|
||||
queryKey: ["emex-wizard", catalogCode, ssd],
|
||||
queryFn: () =>
|
||||
api.get<WizardRow[]>(
|
||||
`/catalog/emex/brands/${catalogCode}/wizard?ssd=${encodeURIComponent(ssd)}`,
|
||||
),
|
||||
});
|
||||
|
||||
// Parse wizard state
|
||||
const determined = useMemo(() => wizardRows?.filter((r) => r.determined) ?? [], [wizardRows]);
|
||||
const undetermined = useMemo(
|
||||
() => wizardRows?.filter((r) => !r.determined && r.options?.length > 0) ?? [],
|
||||
[wizardRows],
|
||||
);
|
||||
const allDetermined = wizardRows ? wizardRows.length > 0 && undetermined.length === 0 : false;
|
||||
|
||||
// Get the "Sales Designation" and "Model" from determined params
|
||||
const wizardMatch = useMemo(() => {
|
||||
if (!allDetermined || !determined.length) return null;
|
||||
let salesDesignation: string | null = null;
|
||||
let model: string | null = null;
|
||||
|
||||
for (const key of ["Sales Designation", "Name", "Modification", "Model name"]) {
|
||||
const row = determined.find((r) => r.name === key);
|
||||
if (row?.value && row.value !== "None") {
|
||||
salesDesignation = row.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const modelRow = determined.find((r) => r.name === "Model");
|
||||
if (modelRow?.value && modelRow.value !== "None") {
|
||||
model = modelRow.value;
|
||||
}
|
||||
|
||||
const name = salesDesignation || model;
|
||||
if (!name) return null;
|
||||
return { name, model };
|
||||
}, [allDetermined, determined]);
|
||||
|
||||
// When all wizard params are determined, search DB for matching vehicles
|
||||
const { data: matchedVehicles, isLoading: matchLoading } = useQuery({
|
||||
queryKey: ["emex-wizard-vehicles", catalogCode, wizardMatch?.name, wizardMatch?.model],
|
||||
queryFn: () => {
|
||||
const params = new URLSearchParams({ name: wizardMatch?.name ?? "" });
|
||||
if (wizardMatch?.model) params.set("model", wizardMatch?.model);
|
||||
return api.get<EmexVehicle[]>(
|
||||
`/catalog/emex/brands/${catalogCode}/wizard-vehicles?${params}`,
|
||||
);
|
||||
},
|
||||
enabled: !!wizardMatch,
|
||||
});
|
||||
|
||||
// Handle wizard option selection — navigate to new SSD
|
||||
const handleSelect = useCallback((_rowName: string, option: WizardOption) => {
|
||||
setSsd(option.key);
|
||||
}, []);
|
||||
|
||||
// Reset wizard to initial state
|
||||
const handleReset = useCallback(() => {
|
||||
setSsd("");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-3">
|
||||
<Link to="/dashboard/catalog" search={{}}>
|
||||
<Button variant="ghost" size="sm">
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToBrands")}
|
||||
</Button>
|
||||
</Link>
|
||||
<h1 className="text-xl font-bold">{decodeURIComponent(catalogCode)}</h1>
|
||||
{determined.length > 0 && (
|
||||
<Button variant="ghost" size="sm" onClick={handleReset}>
|
||||
<RotateCcw className="mr-1 size-3.5" />
|
||||
{t("catalog.resetSelection")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Determined params — shown as tags */}
|
||||
{determined.length > 0 && (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{determined.map((r) => (
|
||||
<span
|
||||
key={r.name}
|
||||
className="rounded-md border border-border bg-muted/50 px-2 py-1 text-xs"
|
||||
>
|
||||
<span className="text-muted-foreground">{r.name}:</span> {r.value}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Error state */}
|
||||
{wizardError && (
|
||||
<div className="flex items-center gap-2 rounded-lg border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive">
|
||||
<AlertCircle className="size-4 shrink-0" />
|
||||
<p>Katalog verileri yüklenemedi. Lütfen tekrar deneyin.</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Loading */}
|
||||
{wizardLoading && (
|
||||
<div className="space-y-2">
|
||||
{Array.from({ length: 3 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-10 w-full rounded-lg" />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Wizard: show first undetermined row as clickable list */}
|
||||
{!wizardLoading && !wizardError && !allDetermined && undetermined.length > 0 && (
|
||||
<WizardStep row={undetermined[0]} onSelect={handleSelect} />
|
||||
)}
|
||||
|
||||
{/* All determined: show matched vehicles from DB */}
|
||||
{allDetermined && (
|
||||
<div className="space-y-3">
|
||||
{matchLoading ? (
|
||||
<div className="space-y-2">
|
||||
{Array.from({ length: 3 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-12 w-full rounded-lg" />
|
||||
))}
|
||||
</div>
|
||||
) : matchedVehicles && matchedVehicles.length > 0 ? (
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs text-muted-foreground">{matchedVehicles.length} varyant</p>
|
||||
{matchedVehicles.map((v) => (
|
||||
<VehicleRow key={v.id} vehicle={v} catalogCode={catalogCode} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-lg border border-dashed border-border py-8 text-center">
|
||||
<Car className="mx-auto mb-2 size-8 text-muted-foreground/50" />
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Bu araç konfigürasyonu için parça verisi henüz mevcut değil.
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-muted-foreground/70">
|
||||
Farklı bir model veya varyant seçmeyi deneyin.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Empty state: no wizard rows at all */}
|
||||
{!wizardLoading && !wizardError && wizardRows && wizardRows.length === 0 && (
|
||||
<p className="py-8 text-center text-muted-foreground">{t("catalog.noModels")}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Wizard step: show options for first undetermined row ──
|
||||
|
||||
function WizardStep({
|
||||
row,
|
||||
onSelect,
|
||||
}: {
|
||||
row: WizardRow;
|
||||
onSelect: (rowName: string, option: WizardOption) => void;
|
||||
}) {
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
if (!search) return row.options;
|
||||
const q = search.toLowerCase();
|
||||
return row.options.filter((o) => o.value.toLowerCase().includes(q));
|
||||
}, [row.options, search]);
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-sm font-medium">{row.name}</h2>
|
||||
<span className="text-xs text-muted-foreground">{row.options.length} seçenek</span>
|
||||
</div>
|
||||
|
||||
{row.options.length > 10 && (
|
||||
<input
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder="Ara..."
|
||||
className="h-8 w-full rounded-md border border-input bg-background px-3 text-sm shadow-sm focus:outline-none focus:ring-1 focus:ring-ring"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="grid gap-1">
|
||||
{filtered.map((opt) => (
|
||||
<button
|
||||
key={opt.key}
|
||||
type="button"
|
||||
onClick={() => onSelect(row.name, opt)}
|
||||
className="flex items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 text-left text-sm transition-colors hover:bg-accent"
|
||||
>
|
||||
<span className="min-w-0 flex-1 truncate">{opt.value}</span>
|
||||
<ChevronRight className="size-4 shrink-0 text-muted-foreground" />
|
||||
</button>
|
||||
))}
|
||||
{filtered.length === 0 && (
|
||||
<p className="py-4 text-center text-sm text-muted-foreground">Sonuç bulunamadı</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Vehicle row ──────────────────────────────────────
|
||||
|
||||
function VehicleRow({
|
||||
vehicle,
|
||||
catalogCode,
|
||||
}: {
|
||||
vehicle: EmexVehicle;
|
||||
catalogCode: string;
|
||||
}) {
|
||||
const parts: string[] = [];
|
||||
|
||||
if (vehicle.optionsRaw) {
|
||||
parts.push(vehicle.optionsRaw);
|
||||
}
|
||||
const raw = vehicle.optionsRaw?.toLowerCase() || "";
|
||||
if (vehicle.engine && !raw.includes(vehicle.engine.toLowerCase())) parts.push(vehicle.engine);
|
||||
if (vehicle.bodyType && !raw.includes(vehicle.bodyType.toLowerCase()))
|
||||
parts.push(vehicle.bodyType);
|
||||
if (vehicle.transmission && !raw.includes(vehicle.transmission.toLowerCase()))
|
||||
parts.push(vehicle.transmission);
|
||||
if (vehicle.driveType && !raw.includes(vehicle.driveType.toLowerCase()))
|
||||
parts.push(vehicle.driveType);
|
||||
|
||||
if (parts.length === 0 && vehicle.engine) parts.push(vehicle.engine);
|
||||
|
||||
return (
|
||||
<Link
|
||||
to="/dashboard/catalog/emex/$catalogCode/$vehicleId"
|
||||
params={{ catalogCode, vehicleId: vehicle.id }}
|
||||
className="flex items-center gap-3 rounded-lg border border-border bg-card px-3 py-2.5 transition-colors hover:bg-accent"
|
||||
>
|
||||
<Car className="size-4 shrink-0 text-muted-foreground" />
|
||||
<div className="min-w-0 flex-1">
|
||||
{parts.length > 0 ? (
|
||||
<p className="truncate text-sm">{parts.join(" · ")}</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">{vehicle.vehicleId}</p>
|
||||
)}
|
||||
</div>
|
||||
<ChevronRight className="size-4 shrink-0 text-muted-foreground" />
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
import { api } from "@/lib/api-client";
|
||||
import { EMEX_GROUP_HIERARCHY } from "@/lib/emex-group-hierarchy";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { Button, Skeleton } from "@sase/ui";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute } from "@tanstack/react-router";
|
||||
import { ArrowLeft, ChevronDown, ChevronRight, FolderOpen } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/catalog_/emex/$catalogCode_/$vehicleId/")({
|
||||
component: EmexGroupListPage,
|
||||
});
|
||||
|
||||
interface EmexGroup {
|
||||
id: string;
|
||||
groupId: string;
|
||||
name: string;
|
||||
nameOriginal: string | null;
|
||||
hasParts: boolean | null;
|
||||
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();
|
||||
|
||||
const { data: groups, isLoading } = useQuery({
|
||||
queryKey: ["emex-groups", vehicleId],
|
||||
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">
|
||||
<Link to="/dashboard/catalog/emex/$catalogCode" params={{ catalogCode }}>
|
||||
<Button variant="ghost" size="sm">
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToModels")}
|
||||
</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="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) => (
|
||||
<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);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import type { Part, SchemaPic } from "@/hooks/use-parts";
|
||||
import { api } from "@/lib/api-client";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { useSchemaStore } from "@/stores/schema.store";
|
||||
import { Button, Skeleton } from "@sase/ui";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute } from "@tanstack/react-router";
|
||||
import { ArrowLeft, ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { Suspense, lazy, useEffect, useState } from "react";
|
||||
|
||||
const SchemaViewer = lazy(() =>
|
||||
import("@/components/schema/schema-viewer").then((mod) => ({
|
||||
default: mod.SchemaViewer,
|
||||
})),
|
||||
);
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId",
|
||||
)({
|
||||
component: EmexGroupPartsPage,
|
||||
});
|
||||
|
||||
interface EmexGroupParts {
|
||||
group: {
|
||||
id: string;
|
||||
groupId: string;
|
||||
name: string;
|
||||
nameOriginal: string | null;
|
||||
};
|
||||
parts: Part[];
|
||||
schemaPics: SchemaPic[];
|
||||
}
|
||||
|
||||
function EmexGroupPartsPage() {
|
||||
const { t } = useTranslation();
|
||||
const { catalogCode, vehicleId, groupId } = Route.useParams();
|
||||
const [activeImageIndex, setActiveImageIndex] = useState(0);
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ["emex-group-parts", vehicleId, groupId],
|
||||
queryFn: () => api.get<EmexGroupParts>(`/catalog/emex/vehicles/${vehicleId}/groups/${groupId}`),
|
||||
});
|
||||
|
||||
// Reset schema store and image index on group change
|
||||
useEffect(() => {
|
||||
useSchemaStore.getState().resetView();
|
||||
setActiveImageIndex(0);
|
||||
}, [groupId]);
|
||||
|
||||
const activePic = data?.schemaPics?.[activeImageIndex] ?? null;
|
||||
const totalImages = data?.schemaPics?.length ?? 0;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link
|
||||
to="/dashboard/catalog/emex/$catalogCode/$vehicleId"
|
||||
params={{ catalogCode, vehicleId }}
|
||||
>
|
||||
<Button variant="ghost" size="sm">
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToCategories")}
|
||||
</Button>
|
||||
</Link>
|
||||
<h1 className="text-xl font-bold">{data?.group?.name || t("catalog.parts")}</h1>
|
||||
</div>
|
||||
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="flex flex-col gap-4 rounded-lg border border-border md:h-[600px] md:flex-row">
|
||||
<div className="flex h-[300px] items-center justify-center md:h-auto md:w-[60%]">
|
||||
<Skeleton className="h-[80%] w-[80%]" />
|
||||
</div>
|
||||
<div className="w-full space-y-3 p-4 md:w-[40%]">
|
||||
<Skeleton className="h-6 w-1/2" />
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-10 w-full" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<SchemaViewer
|
||||
schemaPic={activePic}
|
||||
hotspots={[]}
|
||||
parts={data?.parts ?? []}
|
||||
isLoading={isLoading}
|
||||
vehicleId={vehicleId}
|
||||
categoryId={groupId}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{totalImages > 1 && (
|
||||
<div className="flex items-center justify-center gap-2 py-1">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
disabled={activeImageIndex === 0}
|
||||
onClick={() => setActiveImageIndex((i) => i - 1)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
</Button>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{activeImageIndex + 1} / {totalImages}
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
disabled={activeImageIndex === totalImages - 1}
|
||||
onClick={() => setActiveImageIndex((i) => i + 1)}
|
||||
>
|
||||
<ChevronRight className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { api } from "@/lib/api-client";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { Button, Skeleton } from "@sase/ui";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute } from "@tanstack/react-router";
|
||||
import { ArrowLeft, Library } from "lucide-react";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/catalog_/pcat/$catalogId/")({
|
||||
component: PcatModelsPage,
|
||||
});
|
||||
|
||||
interface PcatModel {
|
||||
id: string;
|
||||
catalogId: string;
|
||||
name: string;
|
||||
imgUrl: string | null;
|
||||
yearFrom: number | null;
|
||||
yearTo: number | null;
|
||||
carsCount: number;
|
||||
}
|
||||
|
||||
function PcatModelsPage() {
|
||||
const { t } = useTranslation();
|
||||
const { catalogId } = Route.useParams();
|
||||
|
||||
const { data: models, isLoading } = useQuery({
|
||||
queryKey: ["pcat-models", catalogId],
|
||||
queryFn: () => api.get<PcatModel[]>(`/catalog/pcat/catalogs/${catalogId}/models`),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link to="/dashboard/catalog" search={{}}>
|
||||
<Button variant="ghost" size="sm">
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToBrands")}
|
||||
</Button>
|
||||
</Link>
|
||||
<h1 className="text-xl font-bold">{catalogId.toUpperCase()}</h1>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-28 w-full rounded-xl" />
|
||||
))}
|
||||
</div>
|
||||
) : !models || models.length === 0 ? (
|
||||
<p className="py-8 text-center text-muted-foreground">{t("catalog.noModels")}</p>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
|
||||
{models.map((model) => (
|
||||
<Link
|
||||
key={model.id}
|
||||
to="/dashboard/catalog/pcat/$catalogId/$modelId"
|
||||
params={{ catalogId, modelId: model.id }}
|
||||
className="flex flex-col items-center justify-center rounded-xl border border-border bg-card p-4 text-center transition-colors hover:bg-accent hover:border-accent-foreground/20"
|
||||
>
|
||||
{model.imgUrl ? (
|
||||
<img
|
||||
src={model.imgUrl.startsWith("//") ? `https:${model.imgUrl}` : model.imgUrl}
|
||||
alt={model.name}
|
||||
className="mb-2 h-16 w-auto object-contain"
|
||||
/>
|
||||
) : (
|
||||
<div className="mb-2 flex size-10 items-center justify-center rounded-full bg-emerald-500/10">
|
||||
<Library className="size-5 text-emerald-500" />
|
||||
</div>
|
||||
)}
|
||||
<p className="text-sm font-semibold">{model.name}</p>
|
||||
{(model.yearFrom || model.yearTo) && (
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
{model.yearFrom || "?"} - {model.yearTo || "..."}
|
||||
</p>
|
||||
)}
|
||||
{model.carsCount > 0 && (
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">{model.carsCount} araç</p>
|
||||
)}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import { api } from "@/lib/api-client";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { Button, Skeleton } from "@sase/ui";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute } from "@tanstack/react-router";
|
||||
import { ArrowLeft, Car, ChevronRight } from "lucide-react";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/catalog_/pcat/$catalogId_/$modelId/")({
|
||||
component: PcatCarsPage,
|
||||
});
|
||||
|
||||
interface PcatCar {
|
||||
id: string;
|
||||
modelId: string;
|
||||
name: string;
|
||||
yearFrom: number | null;
|
||||
yearTo: number | null;
|
||||
engine: string | null;
|
||||
transmission: string | null;
|
||||
bodyType: string | null;
|
||||
fuelType: string | null;
|
||||
driveType: string | null;
|
||||
steering: string | null;
|
||||
schemasCount: number;
|
||||
partsCount: number;
|
||||
}
|
||||
|
||||
function PcatCarsPage() {
|
||||
const { t } = useTranslation();
|
||||
const { catalogId, modelId } = Route.useParams();
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const { data: cars, isLoading } = useQuery({
|
||||
queryKey: ["pcat-cars", catalogId, modelId],
|
||||
queryFn: () => api.get<PcatCar[]>(`/catalog/pcat/catalogs/${catalogId}/models/${modelId}/cars`),
|
||||
});
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
if (!cars) return [];
|
||||
if (!search) return cars;
|
||||
const q = search.toLowerCase();
|
||||
return cars.filter(
|
||||
(c) =>
|
||||
c.name.toLowerCase().includes(q) ||
|
||||
c.engine?.toLowerCase().includes(q) ||
|
||||
c.bodyType?.toLowerCase().includes(q),
|
||||
);
|
||||
}, [cars, search]);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link to="/dashboard/catalog/pcat/$catalogId" params={{ catalogId }}>
|
||||
<Button variant="ghost" size="sm">
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToModels")}
|
||||
</Button>
|
||||
</Link>
|
||||
<h1 className="text-xl font-bold">{catalogId.toUpperCase()}</h1>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="space-y-2">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-14 w-full rounded-lg" />
|
||||
))}
|
||||
</div>
|
||||
) : !cars || cars.length === 0 ? (
|
||||
<p className="py-8 text-center text-muted-foreground">{t("catalog.noModels")}</p>
|
||||
) : (
|
||||
<>
|
||||
{cars.length > 10 && (
|
||||
<input
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder="Ara..."
|
||||
className="h-8 w-full rounded-md border border-input bg-background px-3 text-sm shadow-sm focus:outline-none focus:ring-1 focus:ring-ring"
|
||||
/>
|
||||
)}
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs text-muted-foreground">{filtered.length} araç</p>
|
||||
{filtered.map((car) => (
|
||||
<Link
|
||||
key={car.id}
|
||||
to="/dashboard/catalog/pcat/$catalogId/$modelId/$carId"
|
||||
params={{ catalogId, modelId, carId: car.id }}
|
||||
className="flex items-center gap-3 rounded-lg border border-border bg-card px-3 py-2.5 transition-colors hover:bg-accent"
|
||||
>
|
||||
<Car className="size-4 shrink-0 text-muted-foreground" />
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-medium">{car.name}</p>
|
||||
<p className="truncate text-xs text-muted-foreground">
|
||||
{[
|
||||
car.engine,
|
||||
car.bodyType,
|
||||
car.transmission,
|
||||
car.fuelType,
|
||||
car.yearFrom && car.yearTo
|
||||
? `${car.yearFrom}-${car.yearTo}`
|
||||
: car.yearFrom
|
||||
? `${car.yearFrom}+`
|
||||
: null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" · ")}
|
||||
</p>
|
||||
</div>
|
||||
{car.schemasCount > 0 && (
|
||||
<span className="shrink-0 text-xs text-muted-foreground">
|
||||
{car.schemasCount} şema
|
||||
</span>
|
||||
)}
|
||||
<ChevronRight className="size-4 shrink-0 text-muted-foreground" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
import { api } from "@/lib/api-client";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { Button, Skeleton } from "@sase/ui";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute } from "@tanstack/react-router";
|
||||
import { ArrowLeft, ChevronRight, FolderOpen } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId/")({
|
||||
component: PcatCarGroupsPage,
|
||||
});
|
||||
|
||||
interface PcatGroup {
|
||||
id: string;
|
||||
catalogId: string;
|
||||
parentId: string | null;
|
||||
name: string;
|
||||
imgUrl: string | null;
|
||||
hasSubgroups: boolean;
|
||||
hasParts: boolean;
|
||||
}
|
||||
|
||||
function PcatCarGroupsPage() {
|
||||
const { t } = useTranslation();
|
||||
const { catalogId, modelId, carId } = Route.useParams();
|
||||
|
||||
const [parentStack, setParentStack] = useState<{ id: string; name: string }[]>([]);
|
||||
const currentParentId =
|
||||
parentStack.length > 0 ? parentStack[parentStack.length - 1].id : undefined;
|
||||
|
||||
const { data: groups, isLoading } = useQuery({
|
||||
queryKey: ["pcat-car-groups", carId, currentParentId || "root"],
|
||||
queryFn: () => {
|
||||
const params = currentParentId ? `?parentId=${encodeURIComponent(currentParentId)}` : "";
|
||||
return api.get<PcatGroup[]>(`/catalog/pcat/cars/${carId}/groups${params}`);
|
||||
},
|
||||
});
|
||||
|
||||
const handleGroupClick = (group: PcatGroup) => {
|
||||
if (group.hasSubgroups) {
|
||||
setParentStack((prev) => [...prev, { id: group.id, name: group.name }]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
setParentStack((prev) => prev.slice(0, -1));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
{parentStack.length > 0 ? (
|
||||
<Button variant="ghost" size="sm" onClick={handleBack}>
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToCategories")}
|
||||
</Button>
|
||||
) : (
|
||||
<Link to="/dashboard/catalog/pcat/$catalogId/$modelId" params={{ catalogId, modelId }}>
|
||||
<Button variant="ghost" size="sm">
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToModels")}
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
<h1 className="text-xl font-bold">
|
||||
{catalogId.toUpperCase()}
|
||||
{parentStack.length > 0 && (
|
||||
<span className="font-normal text-muted-foreground">
|
||||
{" / "}
|
||||
{parentStack.map((p) => p.name).join(" / ")}
|
||||
</span>
|
||||
)}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-24 w-full rounded-xl" />
|
||||
))}
|
||||
</div>
|
||||
) : !groups || groups.length === 0 ? (
|
||||
<p className="py-8 text-center text-muted-foreground">{t("catalog.noCategories")}</p>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4">
|
||||
{groups.map((group) => {
|
||||
// Leaf group with parts → link to schema page
|
||||
if (!group.hasSubgroups && group.hasParts) {
|
||||
return (
|
||||
<Link
|
||||
key={group.id}
|
||||
to="/dashboard/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId"
|
||||
params={{ catalogId, modelId, carId, groupId: group.id }}
|
||||
className="flex flex-col items-center justify-center rounded-xl border border-border bg-card p-4 text-center transition-colors hover:bg-accent hover:border-accent-foreground/20"
|
||||
>
|
||||
{group.imgUrl ? (
|
||||
<img
|
||||
src={group.imgUrl.startsWith("//") ? `https:${group.imgUrl}` : group.imgUrl}
|
||||
alt={group.name}
|
||||
className="mb-2 h-12 w-auto object-contain"
|
||||
/>
|
||||
) : (
|
||||
<FolderOpen className="mb-2 size-8 text-muted-foreground/50" />
|
||||
)}
|
||||
<p className="text-xs font-medium">{group.name}</p>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
// Group with subgroups → drill in
|
||||
return (
|
||||
<button
|
||||
key={group.id}
|
||||
type="button"
|
||||
onClick={() => handleGroupClick(group)}
|
||||
className="flex flex-col items-center justify-center rounded-xl border border-border bg-card p-4 text-center transition-colors hover:bg-accent hover:border-accent-foreground/20"
|
||||
>
|
||||
{group.imgUrl ? (
|
||||
<img
|
||||
src={group.imgUrl.startsWith("//") ? `https:${group.imgUrl}` : group.imgUrl}
|
||||
alt={group.name}
|
||||
className="mb-2 h-12 w-auto object-contain"
|
||||
/>
|
||||
) : (
|
||||
<FolderOpen className="mb-2 size-8 text-muted-foreground/50" />
|
||||
)}
|
||||
<p className="text-xs font-medium">{group.name}</p>
|
||||
{group.hasSubgroups && (
|
||||
<ChevronRight className="mt-1 size-3.5 text-muted-foreground" />
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import type { Hotspot, Part, SchemaPic } from "@/hooks/use-parts";
|
||||
import { api } from "@/lib/api-client";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { useSchemaStore } from "@/stores/schema.store";
|
||||
import { Button, Skeleton } from "@sase/ui";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, createFileRoute } from "@tanstack/react-router";
|
||||
import { ArrowLeft, ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { Suspense, lazy, useEffect, useState } from "react";
|
||||
|
||||
const SchemaViewer = lazy(() =>
|
||||
import("@/components/schema/schema-viewer").then((mod) => ({
|
||||
default: mod.SchemaViewer,
|
||||
})),
|
||||
);
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId",
|
||||
)({
|
||||
component: PcatSchemaPage,
|
||||
});
|
||||
|
||||
interface PcatSchemaImage {
|
||||
id: string;
|
||||
name: string | null;
|
||||
imgUrl: string | null;
|
||||
partsCount: number;
|
||||
}
|
||||
|
||||
interface PcatSchemaDetail {
|
||||
schemaImage: PcatSchemaImage;
|
||||
parts: Part[];
|
||||
schemaPics: SchemaPic[];
|
||||
hotspots: Hotspot[];
|
||||
}
|
||||
|
||||
function PcatSchemaPage() {
|
||||
const { t } = useTranslation();
|
||||
const { catalogId, modelId, carId, groupId } = Route.useParams();
|
||||
const [activeImageIndex, setActiveImageIndex] = useState(0);
|
||||
|
||||
// Fetch all schema images for this car+group
|
||||
const { data: schemaImages, isLoading: imagesLoading } = useQuery({
|
||||
queryKey: ["pcat-schemas", carId, groupId],
|
||||
queryFn: () =>
|
||||
api.get<PcatSchemaImage[]>(`/catalog/pcat/cars/${carId}/groups/${groupId}/schemas`),
|
||||
});
|
||||
|
||||
const activeSchema = schemaImages?.[activeImageIndex];
|
||||
const totalImages = schemaImages?.length ?? 0;
|
||||
|
||||
// Fetch detail for active schema image
|
||||
const { data: detail, isLoading: detailLoading } = useQuery({
|
||||
queryKey: ["pcat-schema-detail", activeSchema?.id],
|
||||
queryFn: () => api.get<PcatSchemaDetail>(`/catalog/pcat/schemas/${activeSchema?.id}`),
|
||||
enabled: !!activeSchema?.id,
|
||||
});
|
||||
|
||||
// Reset schema store on group change
|
||||
useEffect(() => {
|
||||
useSchemaStore.getState().resetView();
|
||||
setActiveImageIndex(0);
|
||||
}, [groupId]);
|
||||
|
||||
const isLoading = imagesLoading || detailLoading;
|
||||
const activePic = detail?.schemaPics?.[0] ?? null;
|
||||
const hotspots = detail?.hotspots ?? [];
|
||||
const parts = detail?.parts ?? [];
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link
|
||||
to="/dashboard/catalog/pcat/$catalogId/$modelId/$carId"
|
||||
params={{ catalogId, modelId, carId }}
|
||||
>
|
||||
<Button variant="ghost" size="sm">
|
||||
<ArrowLeft className="mr-1 size-4" />
|
||||
{t("catalog.backToCategories")}
|
||||
</Button>
|
||||
</Link>
|
||||
<h1 className="text-xl font-bold">{activeSchema?.name || t("catalog.parts")}</h1>
|
||||
</div>
|
||||
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="flex flex-col gap-4 rounded-lg border border-border md:h-[600px] md:flex-row">
|
||||
<div className="flex h-[300px] items-center justify-center md:h-auto md:w-[60%]">
|
||||
<Skeleton className="h-[80%] w-[80%]" />
|
||||
</div>
|
||||
<div className="w-full space-y-3 p-4 md:w-[40%]">
|
||||
<Skeleton className="h-6 w-1/2" />
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-10 w-full" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<SchemaViewer
|
||||
schemaPic={activePic}
|
||||
hotspots={hotspots}
|
||||
parts={parts}
|
||||
isLoading={isLoading}
|
||||
vehicleId={carId}
|
||||
categoryId={groupId}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{totalImages > 1 && (
|
||||
<div className="flex items-center justify-center gap-2 py-1">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
disabled={activeImageIndex === 0}
|
||||
onClick={() => setActiveImageIndex((i) => i - 1)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
</Button>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{activeImageIndex + 1} / {totalImages}
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
disabled={activeImageIndex === totalImages - 1}
|
||||
onClick={() => setActiveImageIndex((i) => i + 1)}
|
||||
>
|
||||
<ChevronRight className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
403
apps/web/src/routes/dashboard/service-test.tsx
Normal file
403
apps/web/src/routes/dashboard/service-test.tsx
Normal file
@@ -0,0 +1,403 @@
|
||||
import { VehicleSelectModal } from "@/components/vehicles/vehicle-select-modal";
|
||||
import { ApiError, api } from "@/lib/api-client";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Badge, Button, Input, Separator } from "@sase/ui";
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import { AlertCircle, Car, Check, Copy, FlaskConical, Loader2, Search } from "lucide-react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
// ─── HELPERS ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const VIN_REGEX = /^[A-HJ-NPR-Z0-9]{17}$/;
|
||||
|
||||
function isValidVin(vin: string): boolean {
|
||||
if (!vin || vin.length !== 17) return false;
|
||||
return VIN_REGEX.test(vin.toUpperCase());
|
||||
}
|
||||
|
||||
function sanitizeVin(raw: string): { cleaned: string; corrections: string[] } {
|
||||
const corrections: string[] = [];
|
||||
const cleaned = raw.replace(/[IOQioq]/g, (ch) => {
|
||||
const upper = ch.toUpperCase();
|
||||
if (upper === "I") {
|
||||
corrections.push("I→1");
|
||||
return "1";
|
||||
}
|
||||
if (upper === "O") {
|
||||
corrections.push("O→0");
|
||||
return "0";
|
||||
}
|
||||
corrections.push("Q→9");
|
||||
return "9";
|
||||
});
|
||||
return { cleaned, corrections };
|
||||
}
|
||||
|
||||
const SERVICE_OPTIONS = [
|
||||
{ value: "all", label: "Normal Akış (Cascade)" },
|
||||
{ value: "corgi", label: "Corgi (Offline WMI)" },
|
||||
{ value: "parts-catalogs", label: "PartsCatalogs" },
|
||||
{ value: "pl24", label: "PL24 (PartsLink24)" },
|
||||
{ value: "emex", label: "EMEX" },
|
||||
{ value: "vin-api", label: "VIN API (NHTSA)" },
|
||||
] as const;
|
||||
|
||||
// ─── ROUTE ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const Route = createFileRoute("/dashboard/service-test")({
|
||||
component: ServiceTestPage,
|
||||
});
|
||||
|
||||
function ServiceTestPage() {
|
||||
const navigate = useNavigate();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [vin, setVin] = useState("");
|
||||
const [service, setService] = useState("all");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [result, setResult] = useState<{
|
||||
service: string;
|
||||
success: boolean;
|
||||
responseTimeMs: number;
|
||||
result: any;
|
||||
error?: string;
|
||||
} | null>(null);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
// EMEX candidate selection state
|
||||
const [candidates, setCandidates] = useState<any[] | null>(null);
|
||||
const [candidateVin, setCandidateVin] = useState("");
|
||||
const [selectLoading, setSelectLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
function handleVinChange(raw: string) {
|
||||
const upper = raw.toUpperCase();
|
||||
const { cleaned, corrections } = sanitizeVin(upper);
|
||||
setVin(cleaned);
|
||||
setError(null);
|
||||
if (corrections.length > 0) {
|
||||
const unique = [...new Set(corrections)];
|
||||
toast.info(`Otomatik düzeltildi: ${unique.join(", ")}`, {
|
||||
description: "Şase numarasında I, O, Q harfleri kullanılamaz",
|
||||
duration: 2500,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTest(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setError(null);
|
||||
setResult(null);
|
||||
setCopied(false);
|
||||
|
||||
const cleanVin = vin.toUpperCase().trim();
|
||||
if (!isValidVin(cleanVin)) {
|
||||
setError("Geçersiz şase. 17 karakter olmalı, I, O, Q harfleri kullanılamaz.");
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await api.post<any>("/vehicles/service-test", {
|
||||
vin: cleanVin,
|
||||
service: service === "all" ? undefined : service,
|
||||
});
|
||||
|
||||
// EMEX success with candidates → show selection modal
|
||||
if (data.success && data.result?.type === "candidates" && data.result.candidates) {
|
||||
setCandidateVin(cleanVin);
|
||||
setCandidates(data.result.candidates);
|
||||
setResult(data);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// EMEX success with single vehicle → navigate to decode flow
|
||||
if (data.success && data.result?.type === "vehicle" && data.result.vehicle) {
|
||||
setResult(data);
|
||||
setLoading(false);
|
||||
// Auto-decode via normal flow
|
||||
try {
|
||||
const decoded = await api.post<any>("/vehicles/decode", { vin: cleanVin });
|
||||
if (decoded.id) {
|
||||
navigate({ to: "/dashboard/vehicles/$id", params: { id: decoded.id } });
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Fall through to show JSON result
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setResult(data);
|
||||
} catch (err) {
|
||||
const message =
|
||||
err instanceof ApiError ? err.message : "Bir hata oluştu. Lütfen tekrar deneyin.";
|
||||
setError(message);
|
||||
toast.error("Servis testi başarısız");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCopyJson() {
|
||||
if (!result) return;
|
||||
try {
|
||||
await navigator.clipboard.writeText(JSON.stringify(result, null, 2));
|
||||
setCopied(true);
|
||||
toast.success("JSON kopyalandı");
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
} catch {
|
||||
toast.error("Kopyalama başarısız");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCandidateSelect(carId: string) {
|
||||
setSelectLoading(true);
|
||||
try {
|
||||
const data = await api.post<any>("/vehicles/decode", {
|
||||
vin: candidateVin,
|
||||
emexCarIndex: Number.parseInt(carId, 10),
|
||||
});
|
||||
setCandidates(null);
|
||||
if (data.id) {
|
||||
navigate({ to: "/dashboard/vehicles/$id", params: { id: data.id } });
|
||||
}
|
||||
} catch (err) {
|
||||
const message = err instanceof ApiError ? err.message : "Bir hata oluştu.";
|
||||
setError(message);
|
||||
setCandidates(null);
|
||||
toast.error("Araç seçimi başarısız");
|
||||
} finally {
|
||||
setSelectLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function fillExampleVin() {
|
||||
setVin("WVWZZZ1JZ3W597935");
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-3xl space-y-6">
|
||||
{/* ─── SECTION 1: Hero Input Card ─────────────────────────────────── */}
|
||||
<div className="rounded-2xl border border-border bg-background p-6 sm:p-8">
|
||||
{/* Header */}
|
||||
<div className="flex flex-col items-center text-center">
|
||||
<div className="inline-flex size-14 items-center justify-center rounded-2xl bg-muted">
|
||||
<FlaskConical className="size-6 text-muted-foreground" />
|
||||
</div>
|
||||
<h2 className="mt-4 font-[family-name:var(--font-display)] text-2xl font-bold tracking-tight">
|
||||
Servis Test
|
||||
</h2>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
VIN decode servislerini tek tek test edin
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Separator className="my-6 bg-border" />
|
||||
|
||||
{/* Form */}
|
||||
<form onSubmit={handleTest} className="space-y-4">
|
||||
{/* Service Selector */}
|
||||
<div>
|
||||
<label
|
||||
htmlFor="service-select"
|
||||
className="mb-1.5 block text-sm font-medium text-foreground"
|
||||
>
|
||||
Servis
|
||||
</label>
|
||||
<select
|
||||
id="service-select"
|
||||
value={service}
|
||||
onChange={(e) => setService(e.target.value)}
|
||||
className="h-12 w-full rounded-xl border border-border bg-muted/50 px-4 text-sm text-foreground outline-none transition-colors focus:border-ring focus:ring-1 focus:ring-ring"
|
||||
>
|
||||
{SERVICE_OPTIONS.map((opt) => (
|
||||
<option key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* VIN Input */}
|
||||
<div className="relative">
|
||||
<Search className="absolute left-4 top-1/2 size-5 -translate-y-1/2 text-muted-foreground" />
|
||||
<Input
|
||||
ref={inputRef}
|
||||
placeholder="Şase numarasını girin (17 karakter)"
|
||||
value={vin}
|
||||
onChange={(e) => handleVinChange(e.target.value)}
|
||||
maxLength={17}
|
||||
className={`h-14 rounded-xl bg-muted/50 pl-12 font-mono tracking-wider ${vin.length === 0 ? "pr-24" : "pr-4"}`}
|
||||
/>
|
||||
{vin.length === 0 && (
|
||||
<div className="pointer-events-none absolute right-4 top-1/2 flex -translate-y-1/2 items-center gap-1 text-xs text-muted-foreground">
|
||||
<kbd className="rounded border border-border bg-muted px-1.5 py-0.5 font-sans text-[10px]">
|
||||
Ctrl
|
||||
</kbd>
|
||||
<span>+</span>
|
||||
<kbd className="rounded border border-border bg-muted px-1.5 py-0.5 font-sans text-[10px]">
|
||||
K
|
||||
</kbd>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 17-segment progress bar */}
|
||||
<div className="flex gap-0.5">
|
||||
{Array.from({ length: 17 }).map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`h-1.5 flex-1 rounded-full transition-colors duration-200 ${
|
||||
i < vin.length ? "bg-emerald-500" : "bg-muted"
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Counter + Example VIN */}
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="tabular-nums text-muted-foreground">{vin.length}/17 karakter</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={fillExampleVin}
|
||||
className="text-muted-foreground underline underline-offset-4 transition hover:text-foreground"
|
||||
>
|
||||
Örnek şase deneyin →
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Submit button */}
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={loading || vin.length !== 17}
|
||||
className="h-12 w-full rounded-xl"
|
||||
>
|
||||
{loading ? (
|
||||
<Loader2 className="mr-2 size-4 animate-spin" />
|
||||
) : (
|
||||
<FlaskConical className="mr-2 size-4" />
|
||||
)}
|
||||
Test Et
|
||||
</Button>
|
||||
|
||||
{/* Error card */}
|
||||
{error && (
|
||||
<div className="flex items-start gap-3 rounded-xl border border-destructive/30 bg-destructive/5 p-4">
|
||||
<AlertCircle className="mt-0.5 size-4 shrink-0 text-destructive" />
|
||||
<p className="text-sm text-destructive">{error}</p>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* ─── SECTION 2: Vehicle Info Card (successful single decode) ──── */}
|
||||
{result?.success && result.result?.type === "vehicle" && result.result.vehicle && (
|
||||
<div className="rounded-2xl border border-emerald-500/30 bg-background p-5 sm:p-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-emerald-500/10">
|
||||
<Car className="size-5 text-emerald-500" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="font-[family-name:var(--font-display)] text-lg font-bold">
|
||||
{result.result.vehicle.brand} {result.result.vehicle.model}
|
||||
</p>
|
||||
<p className="mt-0.5 text-sm text-muted-foreground">
|
||||
{result.result.vehicle.year || "—"}
|
||||
{result.result.vehicle.engineCode &&
|
||||
` — Motor: ${result.result.vehicle.engineCode}`}
|
||||
</p>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
<Badge variant="default" className="bg-emerald-600 text-xs text-white">
|
||||
Araç tanımlandı
|
||||
</Badge>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{result.service}
|
||||
</Badge>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{result.responseTimeMs.toLocaleString("tr-TR")}ms
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{result.result.vehicle.categories?.length > 0 && (
|
||||
<>
|
||||
<Separator className="my-4 bg-border" />
|
||||
<p className="mb-2 text-sm font-medium text-muted-foreground">
|
||||
{result.result.vehicle.categories.length} kategori bulundu
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ─── SECTION 3: Result Card (JSON for failures or non-vehicle results) ── */}
|
||||
{result &&
|
||||
(!result.success || result.result?.type !== "vehicle") &&
|
||||
result.result?.type !== "candidates" && (
|
||||
<div className="rounded-2xl border border-border bg-background p-5 sm:p-6">
|
||||
{/* Meta badges */}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Badge variant="default" className="bg-blue-600 text-xs text-white">
|
||||
{result.service}
|
||||
</Badge>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{result.responseTimeMs.toLocaleString("tr-TR")}ms
|
||||
</Badge>
|
||||
<Badge
|
||||
variant={result.success ? "default" : "destructive"}
|
||||
className={`text-xs ${result.success ? "bg-emerald-600 text-white" : ""}`}
|
||||
>
|
||||
{result.success ? "Başarılı" : "Başarısız"}
|
||||
</Badge>
|
||||
<div className="flex-1" />
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCopyJson}
|
||||
className="h-8 gap-1.5 rounded-lg text-xs"
|
||||
>
|
||||
{copied ? <Check className="size-3.5" /> : <Copy className="size-3.5" />}
|
||||
{copied ? "Kopyalandı" : "JSON Kopyala"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Error message */}
|
||||
{result.error && (
|
||||
<div className="mt-4 flex items-start gap-3 rounded-xl border border-destructive/30 bg-destructive/5 p-4">
|
||||
<AlertCircle className="mt-0.5 size-4 shrink-0 text-destructive" />
|
||||
<p className="text-sm text-destructive">{result.error}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* JSON output */}
|
||||
{result.result !== null && (
|
||||
<>
|
||||
<Separator className="my-4 bg-border" />
|
||||
<pre className="max-h-[600px] overflow-auto rounded-xl border border-border bg-muted/50 p-4 font-mono text-xs leading-relaxed">
|
||||
{JSON.stringify(result.result, null, 2)}
|
||||
</pre>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ─── Vehicle Selection Modal (EMEX multi-result) ──────────────── */}
|
||||
{candidates && (
|
||||
<VehicleSelectModal
|
||||
open={!!candidates}
|
||||
onClose={() => setCandidates(null)}
|
||||
candidates={candidates}
|
||||
vin={candidateVin}
|
||||
onSelect={handleCandidateSelect}
|
||||
loading={selectLoading}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user