1 line
46 KiB
JSON
1 line
46 KiB
JSON
{"file":"edit-Db3uK3sd.js","mappings":"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","names":["_ssrRenderClass","_ssrIncludeBooleanAttr","_ssrInterpolate","$emit","$route","_ssrRenderList","_ssrRenderVNode","_createVNode","_resolveDynamicComponent","_ssrRenderAttr"],"sources":["../../../../components/TreeNode.vue","../../../../pages/providers/[id]/edit.vue"],"sourcesContent":["<template>\n <div>\n <div class=\"flex items-center gap-2 py-1\">\n <button\n @click=\"$emit('toggle-expand', node.id)\"\n class=\"text-slate-500 hover:text-slate-300 transition w-4 h-4 flex items-center justify-center\"\n >\n <svg\n class=\"w-3 h-3 transition-transform\"\n :class=\"expandedIds.has(node.id) ? 'rotate-90' : ''\"\n fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n <label class=\"flex items-center gap-2 cursor-pointer flex-1\">\n <input\n type=\"checkbox\"\n :checked=\"selectedIds.includes(node.id)\"\n @change=\"$emit('toggle', node.id)\"\n class=\"w-4 h-4 rounded border-slate-500 bg-slate-700 text-indigo-500 focus:ring-indigo-500/50\"\n />\n <span class=\"text-sm text-slate-300\">{{ node.name_hu || node.name_en || node.key }}</span>\n <span class=\"text-xs text-slate-500\">(Szint {{ node.level }})</span>\n </label>\n </div>\n <div v-if=\"expandedIds.has(node.id) && node.children?.length\" class=\"ml-6 border-l border-slate-700 pl-3\">\n <div v-for=\"child in node.children\" :key=\"child.id\">\n <TreeNode\n :node=\"child\"\n :selected-ids=\"selectedIds\"\n :expanded-ids=\"expandedIds\"\n @toggle=\"(id: number) => $emit('toggle', id)\"\n @toggle-expand=\"(id: number) => $emit('toggle-expand', id)\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * Recursive TreeNode component for the category tree.\n * Renders a checkbox tree with expand/collapse for nested categories.\n */\ninterface CategoryTreeNode {\n id: number\n key: string\n name_hu?: string | null\n name_en?: string | null\n level: number\n path?: string | null\n is_official: boolean\n children: CategoryTreeNode[]\n}\n\ndefineProps<{\n node: CategoryTreeNode\n selectedIds: number[]\n expandedIds: Set<number>\n}>()\n\ndefineEmits<{\n toggle: [id: number]\n 'toggle-expand': [id: number]\n}>()\n</script>\n","<template>\n <div>\n <!-- Back Button & Header -->\n <div class=\"mb-8\">\n <button\n @click=\"goBack\"\n class=\"inline-flex items-center gap-1.5 text-sm text-slate-400 hover:text-white transition mb-4\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Vissza a szolgáltatóhoz\n </button>\n <h1 class=\"text-2xl font-bold text-white\">Szolgáltató szerkesztése</h1>\n <p class=\"text-slate-400 mt-1\">Szolgáltató #{{ $route.params.id }}</p>\n </div>\n\n <!-- Loading State -->\n <div v-if=\"loading\" class=\"flex items-center justify-center py-20\">\n <div class=\"text-slate-400 flex items-center gap-3\">\n <svg class=\"w-5 h-5 animate-spin\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <span>Szolgáltató betöltése...</span>\n </div>\n </div>\n\n <!-- Error State -->\n <div v-else-if=\"error\" class=\"bg-rose-500/10 border border-rose-500/30 rounded-xl p-6 mb-8\">\n <p class=\"text-rose-400\">Hiba történt a szolgáltató betöltése közben.</p>\n <button @click=\"fetchProvider\" class=\"mt-3 text-sm text-rose-300 hover:text-rose-200 underline\">Újrapróbálkozás</button>\n </div>\n\n <!-- Not Found -->\n <div v-else-if=\"!provider\" class=\"bg-slate-800 rounded-xl border border-slate-700 p-6\">\n <p class=\"text-slate-400 text-center py-12\">A szolgáltató nem található.</p>\n </div>\n\n <template v-else>\n <!-- Tab Navigation -->\n <div class=\"border-b border-slate-700 mb-6\">\n <nav class=\"flex gap-6 -mb-px\">\n <button\n v-for=\"tab in tabs\"\n :key=\"tab.key\"\n @click=\"activeTab = tab.key\"\n class=\"pb-3 text-sm font-medium border-b-2 transition flex items-center gap-2\"\n :class=\"activeTab === tab.key ? 'text-indigo-400 border-indigo-400' : 'text-slate-400 border-transparent hover:text-slate-300'\"\n >\n <component :is=\"tab.icon\" class=\"w-4 h-4\" />\n {{ tab.label }}\n </button>\n </nav>\n </div>\n\n <!-- ═══════════════════════════════════════════════════\n TAB 1: Alapadatok & Kapcsolat (Basic Info & Contact)\n ═══════════════════════════════════════════════════ -->\n <div v-if=\"activeTab === 'basic'\" class=\"max-w-3xl\">\n <form @submit.prevent=\"saveForm\">\n <div class=\"bg-slate-800 rounded-xl border border-slate-700 p-6 mb-6\">\n <h2 class=\"text-lg font-semibold text-white mb-4\">Alapadatok</h2>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Name -->\n <div class=\"md:col-span-2\">\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Név *</label>\n <input\n v-model=\"form.name\"\n required\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <!-- Category -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Kategória</label>\n <input\n v-model=\"form.category\"\n placeholder=\"pl. Autószerviz, Gumiszerviz\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <!-- Source (read-only) -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Forrás</label>\n <div class=\"w-full px-3 py-2 bg-slate-700/50 border border-slate-600 rounded-lg text-slate-400 text-sm\">\n {{ provider.source }}\n </div>\n </div>\n </div>\n </div>\n\n <!-- Contact Information -->\n <div class=\"bg-slate-800 rounded-xl border border-slate-700 p-6 mb-6\">\n <h2 class=\"text-lg font-semibold text-white mb-4\">Elérhetőség</h2>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Telefon</label>\n <input\n v-model=\"form.contact_phone\"\n placeholder=\"+36 30 123 4567\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Email</label>\n <input\n v-model=\"form.contact_email\"\n type=\"email\"\n placeholder=\"info@example.com\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <div class=\"md:col-span-2\">\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Weboldal</label>\n <input\n v-model=\"form.website\"\n placeholder=\"https://...\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n </div>\n </div>\n </form>\n </div>\n\n <!-- ═══════════════════════════════════════════════════\n TAB 2: Szolgáltatások & Járművek (The 3D Matrix)\n ═══════════════════════════════════════════════════ -->\n <div v-if=\"activeTab === 'matrix'\" class=\"max-w-4xl\">\n <div class=\"bg-slate-800 rounded-xl border border-slate-700 p-6 mb-6\">\n <h2 class=\"text-lg font-semibold text-white mb-2\">3D Képesség Mátrix</h2>\n <p class=\"text-sm text-slate-400 mb-6\">\n Állítsd be, hogy a szolgáltató milyen járműosztályokhoz, szolgáltatási kategóriákhoz\n és specializációkhoz tartozik.\n </p>\n\n <!-- ── Dimension A: Vehicle Classes ── -->\n <div class=\"mb-8\">\n <h3 class=\"text-md font-medium text-white mb-3 flex items-center gap-2\">\n <span class=\"w-6 h-6 rounded-full bg-indigo-500/20 text-indigo-400 flex items-center justify-center text-xs font-bold\">A</span>\n Járműosztályok (Vehicle Classes)\n </h3>\n <p class=\"text-xs text-slate-500 mb-3\">Mely járműtípusokat szervizeli a szolgáltató?</p>\n <div class=\"grid grid-cols-2 md:grid-cols-4 gap-3\">\n <label\n v-for=\"vc in VEHICLE_CLASSES\"\n :key=\"vc.key\"\n class=\"flex items-center gap-3 p-3 rounded-lg border cursor-pointer transition\"\n :class=\"form.supported_vehicle_classes.includes(vc.key)\n ? 'bg-indigo-500/10 border-indigo-500/40 text-indigo-300'\n : 'bg-slate-700/50 border-slate-600 hover:border-slate-500 text-slate-300'\"\n >\n <input\n type=\"checkbox\"\n :value=\"vc.key\"\n :checked=\"form.supported_vehicle_classes.includes(vc.key)\"\n @change=\"toggleVehicleClass(vc.key)\"\n class=\"w-4 h-4 rounded border-slate-500 bg-slate-700 text-indigo-500 focus:ring-indigo-500/50\"\n />\n <span class=\"text-sm\">{{ vc.label }}</span>\n </label>\n </div>\n </div>\n\n <!-- ── Dimension B: Service Categories (Expertise Tags) ── -->\n <div class=\"mb-8\">\n <h3 class=\"text-md font-medium text-white mb-3 flex items-center gap-2\">\n <span class=\"w-6 h-6 rounded-full bg-emerald-500/20 text-emerald-400 flex items-center justify-center text-xs font-bold\">B</span>\n Szolgáltatási Kategóriák (Expertise Tags)\n </h3>\n <p class=\"text-xs text-slate-500 mb-3\">Válaszd ki a szolgáltatóhoz tartozó kategóriákat a hierarchikus fából.</p>\n\n <!-- Loading tree -->\n <div v-if=\"treeLoading\" class=\"flex items-center gap-2 text-sm text-slate-400 py-4\">\n <svg class=\"w-4 h-4 animate-spin\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <span>Kategóriák betöltése...</span>\n </div>\n\n <!-- Tree -->\n <div v-else class=\"space-y-1 max-h-96 overflow-y-auto pr-2\">\n <div v-for=\"node in categoryTree\" :key=\"node.id\" class=\"ml-0\">\n <!-- Level 0 node (root) -->\n <div class=\"flex items-center gap-2 py-1\">\n <button\n @click=\"toggleTreeNode(node.id)\"\n class=\"text-slate-500 hover:text-slate-300 transition w-4 h-4 flex items-center justify-center\"\n >\n <svg\n class=\"w-3 h-3 transition-transform\"\n :class=\"expandedNodes.has(node.id) ? 'rotate-90' : ''\"\n fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n <label class=\"flex items-center gap-2 cursor-pointer flex-1\">\n <input\n type=\"checkbox\"\n :checked=\"isCategorySelected(node.id)\"\n @change=\"toggleCategory(node.id)\"\n class=\"w-4 h-4 rounded border-slate-500 bg-slate-700 text-indigo-500 focus:ring-indigo-500/50\"\n />\n <span class=\"text-sm font-medium text-white\">{{ node.name_hu || node.name_en || node.key }}</span>\n <span class=\"text-xs text-slate-500\">(Szint {{ node.level }})</span>\n </label>\n </div>\n <!-- Children (recursive) -->\n <div v-if=\"expandedNodes.has(node.id) && node.children?.length\" class=\"ml-6 border-l border-slate-700 pl-3\">\n <div v-for=\"child in node.children\" :key=\"child.id\">\n <TreeNode\n :node=\"child\"\n :selected-ids=\"form.category_ids\"\n :expanded-ids=\"expandedNodes\"\n @toggle=\"toggleCategory\"\n @toggle-expand=\"toggleTreeNode\"\n />\n </div>\n </div>\n </div>\n </div>\n\n <!-- Selected categories summary -->\n <div v-if=\"form.category_ids.length > 0\" class=\"mt-4 flex flex-wrap gap-2\">\n <span\n v-for=\"id in form.category_ids\"\n :key=\"id\"\n class=\"inline-flex items-center gap-1 px-2 py-1 bg-indigo-500/10 text-indigo-300 rounded-full text-xs\"\n >\n {{ getCategoryName(id) }}\n <button @click=\"removeCategory(id)\" class=\"hover:text-white transition\">\n <svg class=\"w-3 h-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </span>\n </div>\n </div>\n\n <!-- ── Dimension C: Specializations ── -->\n <div class=\"mb-4\">\n <h3 class=\"text-md font-medium text-white mb-3 flex items-center gap-2\">\n <span class=\"w-6 h-6 rounded-full bg-amber-500/20 text-amber-400 flex items-center justify-center text-xs font-bold\">C</span>\n Specializációk\n </h3>\n <p class=\"text-xs text-slate-500 mb-3\">Adj meg speciális márkákat, hajtáslánc típusokat vagy egyéb címkéket.</p>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <!-- Brands -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Márkák (Brands)</label>\n <div class=\"flex flex-wrap gap-2 mb-2\">\n <span\n v-for=\"(brand, idx) in form.specializations.brands\"\n :key=\"idx\"\n class=\"inline-flex items-center gap-1 px-2 py-1 bg-amber-500/10 text-amber-300 rounded-full text-xs\"\n >\n {{ brand }}\n <button @click=\"removeBrand(idx)\" class=\"hover:text-white transition\">\n <svg class=\"w-3 h-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </span>\n </div>\n <div class=\"flex gap-2\">\n <input\n v-model=\"brandInput\"\n @keydown.enter.prevent=\"addBrand\"\n placeholder=\"pl. Volvo, Scania\"\n class=\"flex-1 px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n <button\n @click=\"addBrand\"\n :disabled=\"!brandInput.trim()\"\n class=\"px-3 py-2 bg-indigo-600 hover:bg-indigo-500 disabled:bg-indigo-600/50 text-white rounded-lg text-sm transition\"\n >\n Hozzáad\n </button>\n </div>\n </div>\n\n <!-- Propulsion -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Hajtáslánc (Propulsion)</label>\n <div class=\"flex flex-wrap gap-2 mb-2\">\n <span\n v-for=\"(prop, idx) in form.specializations.propulsion\"\n :key=\"idx\"\n class=\"inline-flex items-center gap-1 px-2 py-1 bg-emerald-500/10 text-emerald-300 rounded-full text-xs\"\n >\n {{ prop }}\n <button @click=\"removePropulsion(idx)\" class=\"hover:text-white transition\">\n <svg class=\"w-3 h-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </span>\n </div>\n <div class=\"flex gap-2\">\n <input\n v-model=\"propulsionInput\"\n @keydown.enter.prevent=\"addPropulsion\"\n placeholder=\"pl. EV, Hybrid, Diesel\"\n class=\"flex-1 px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n <button\n @click=\"addPropulsion\"\n :disabled=\"!propulsionInput.trim()\"\n class=\"px-3 py-2 bg-indigo-600 hover:bg-indigo-500 disabled:bg-indigo-600/50 text-white rounded-lg text-sm transition\"\n >\n Hozzáad\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- ═══════════════════════════════════════════════════\n TAB 3: Helyszín & Lokáció (Location)\n ═══════════════════════════════════════════════════ -->\n <div v-if=\"activeTab === 'location'\" class=\"max-w-3xl\">\n <form @submit.prevent=\"saveForm\">\n <div class=\"bg-slate-800 rounded-xl border border-slate-700 p-6 mb-6\">\n <h2 class=\"text-lg font-semibold text-white mb-4\">Cím adatok</h2>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"md:col-span-2\">\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Teljes cím</label>\n <input\n v-model=\"form.address\"\n placeholder=\"Teljes cím szövege\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Város</label>\n <input\n v-model=\"form.city\"\n placeholder=\"Budapest\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Irányítószám</label>\n <input\n v-model=\"form.address_zip\"\n placeholder=\"1011\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Utca</label>\n <input\n v-model=\"form.address_street_name\"\n placeholder=\"Egressy\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Házszám</label>\n <input\n v-model=\"form.address_house_number\"\n placeholder=\"4/b\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n <div class=\"md:col-span-2\">\n <label class=\"block text-sm font-medium text-slate-300 mb-1\">Plus Code</label>\n <input\n v-model=\"form.plus_code\"\n placeholder=\"8FVC9X8V+XV\"\n class=\"w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm\"\n />\n </div>\n </div>\n </div>\n </form>\n </div>\n\n <!-- ═══════════════════════════════════════════════════\n SAVE BUTTON (fixed bottom bar)\n ═══════════════════════════════════════════════════ -->\n <div class=\"sticky bottom-0 bg-slate-900/90 backdrop-blur-sm border-t border-slate-700 -mx-6 px-6 py-4 mt-8\">\n <div class=\"flex items-center justify-between max-w-4xl\">\n <div class=\"text-sm text-slate-400\">\n <span v-if=\"hasChanges\" class=\"text-amber-400\">● Módosítások el nem mentve</span>\n <span v-else class=\"text-slate-500\">Nincs változás</span>\n </div>\n <div class=\"flex gap-3\">\n <button\n @click=\"goBack\"\n class=\"px-4 py-2 text-sm text-slate-400 hover:text-white transition\"\n >\n Mégse\n </button>\n <button\n @click=\"saveForm\"\n :disabled=\"saveLoading || !hasChanges\"\n class=\"px-6 py-2 bg-indigo-600 hover:bg-indigo-500 disabled:bg-indigo-600/50 text-white rounded-lg text-sm font-medium transition flex items-center gap-2\"\n >\n <svg v-if=\"saveLoading\" class=\"w-4 h-4 animate-spin\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <svg v-else class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n Mentés\n </button>\n </div>\n </div>\n </div>\n </template>\n\n <!-- Toast Notification -->\n <div\n v-if=\"toast\"\n class=\"fixed top-4 right-4 z-50 px-4 py-3 rounded-lg shadow-xl text-sm font-medium transition-all duration-300\"\n :class=\"toast.type === 'success' ? 'bg-emerald-600 text-white' : 'bg-rose-600 text-white'\"\n >\n {{ toast.message }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * 🏛️ Service Provider Dedicated Edit Page\n * =========================================\n * \n * Architectural Context (P0 - Card #384):\n * ----------------------------------------\n * This page replaces the missing modal-based edit system with a full-page\n * 3-tab editor. It integrates with the existing PATCH /admin/providers/{id}\n * endpoint which supports:\n * - Basic fields: name, category, contact info\n * - 3D Matrix: supported_vehicle_classes, category_ids (expertise tags),\n * specializations (brands + propulsion)\n * - Location: address, city, zip, street, house_number, plus_code\n * \n * Data Flow:\n * ----------\n * 1. On mount: fetch provider detail from GET /admin/providers/{id}\n * 2. On mount: fetch category tree from GET /providers/categories/tree\n * 3. User edits fields across 3 tabs\n * 4. On save: PATCH /admin/providers/{id} with full payload\n * 5. On success: navigate back to /providers/{id}\n * \n * Vehicle Classes (Dimension A):\n * ------------------------------\n * The 8 system vehicle classes matching the backend enum:\n * car, motorcycle, truck, hgv, light_commercial,\n * personal, boat, other\n */\n\nimport { ref, computed, onMounted, reactive } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\n\n// ── Types ──────────────────────────────────────────────\ninterface CategoryTreeNode {\n id: number\n key: string\n name_hu?: string | null\n name_en?: string | null\n level: number\n path?: string | null\n is_official: boolean\n children: CategoryTreeNode[]\n}\n\ninterface ProviderDetail {\n id: number\n name: string\n address: string\n city?: string | null\n address_zip?: string | null\n address_street_name?: string | null\n address_street_type?: string | null\n address_house_number?: string | null\n plus_code?: string | null\n contact_phone?: string | null\n contact_email?: string | null\n website?: string | null\n category?: string | null\n status: string\n source: string\n validation_score: number\n evidence_image_path?: string | null\n added_by_user_id?: number | null\n category_ids?: number[] | null\n supported_vehicle_classes?: string[] | null\n specializations?: Record<string, any> | null\n created_at?: string | null\n}\n\n// ── Constants ──────────────────────────────────────────\n/**\n * The 8 system vehicle classes.\n * These match the backend VehicleClass enum values.\n */\nconst VEHICLE_CLASSES = [\n { key: 'car', label: 'Személyautó' },\n { key: 'motorcycle', label: 'Motorkerékpár' },\n { key: 'truck', label: 'Teherautó' },\n { key: 'hgv', label: 'Nehézgépjármű (HGV)' },\n { key: 'light_commercial', label: 'Kishaszonjármű' },\n { key: 'personal', label: 'Személyes' },\n { key: 'boat', label: 'Csónak/Vízi' },\n { key: 'other', label: 'Egyéb' },\n]\n\n// ── Route ──────────────────────────────────────────────\nconst route = useRoute()\nconst router = useRouter()\nconst providerId = computed(() => Number(route.params.id))\n\n// ── State ──────────────────────────────────────────────\nconst loading = ref(true)\nconst error = ref(false)\nconst provider = ref<ProviderDetail | null>(null)\nconst saveLoading = ref(false)\nconst toast = ref<{ message: string; type: 'success' | 'error' } | null>(null)\n\n// Tab state\nconst activeTab = ref<'basic' | 'matrix' | 'location'>('basic')\nconst tabs = [\n { key: 'basic', label: 'Alapadatok & Kapcsolat', icon: 'svg' },\n { key: 'matrix', label: 'Szolgáltatások & Járművek', icon: 'svg' },\n { key: 'location', label: 'Helyszín & Lokáció', icon: 'svg' },\n]\n\n// Category tree state\nconst categoryTree = ref<CategoryTreeNode[]>([])\nconst treeLoading = ref(false)\nconst expandedNodes = ref<Set<number>>(new Set())\n\n// Tag inputs\nconst brandInput = ref('')\nconst propulsionInput = ref('')\n\n/**\n * The reactive form model.\n * Initialized with defaults, then populated from provider data on load.\n * \n * Mapping from backend ProviderUpdateInput schema:\n * - name, city, address_zip, address_street_name, address_street_type,\n * address_house_number, plus_code, contact_phone, contact_email,\n * website, category, category_ids, supported_vehicle_classes, specializations\n */\nconst form = reactive({\n name: '',\n address: '',\n city: '',\n address_zip: '',\n address_street_name: '',\n address_street_type: '',\n address_house_number: '',\n plus_code: '',\n contact_phone: '',\n contact_email: '',\n website: '',\n category: '',\n category_ids: [] as number[],\n supported_vehicle_classes: [] as string[],\n specializations: {\n brands: [] as string[],\n propulsion: [] as string[],\n } as Record<string, string[]>,\n})\n\n// ── Computed ───────────────────────────────────────────\n\n/**\n * Deep comparison between original provider data and current form state.\n * Used to enable/disable the save button and show dirty state indicator.\n */\nconst hasChanges = computed(() => {\n if (!provider.value) return false\n const p = provider.value\n return (\n form.name !== (p.name || '') ||\n form.city !== (p.city || '') ||\n form.address_zip !== (p.address_zip || '') ||\n form.address_street_name !== (p.address_street_name || '') ||\n form.address_house_number !== (p.address_house_number || '') ||\n form.plus_code !== (p.plus_code || '') ||\n form.contact_phone !== (p.contact_phone || '') ||\n form.contact_email !== (p.contact_email || '') ||\n form.website !== (p.website || '') ||\n form.category !== (p.category || '') ||\n JSON.stringify(form.category_ids.sort()) !== JSON.stringify((p.category_ids || []).sort()) ||\n JSON.stringify(form.supported_vehicle_classes.sort()) !== JSON.stringify((p.supported_vehicle_classes || []).sort()) ||\n JSON.stringify(form.specializations) !== JSON.stringify(p.specializations || { brands: [], propulsion: [] })\n )\n})\n\n// ── Auth helpers ───────────────────────────────────────\nfunction getHeaders(): Record<string, string> {\n const token = useCookie('access_token').value\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (token) headers['Authorization'] = `Bearer ${token}`\n return headers\n}\n\n// ── API: Fetch provider ────────────────────────────────\nasync function fetchProvider() {\n loading.value = true\n error.value = false\n try {\n const res = await $fetch(`/api/v1/admin/providers/${providerId.value}`, {\n headers: getHeaders(),\n })\n provider.value = res as ProviderDetail\n mapProviderToForm(res as ProviderDetail)\n } catch (err: any) {\n console.error('Failed to fetch provider:', err)\n error.value = true\n } finally {\n loading.value = false\n }\n}\n\n/**\n * Maps the provider detail response to the reactive form.\n * Handles null/undefined values and ensures arrays/dicts have defaults.\n */\nfunction mapProviderToForm(p: ProviderDetail) {\n form.name = p.name || ''\n form.address = p.address || ''\n form.city = p.city || ''\n form.address_zip = p.address_zip || ''\n form.address_street_name = p.address_street_name || ''\n form.address_street_type = p.address_street_type || ''\n form.address_house_number = p.address_house_number || ''\n form.plus_code = p.plus_code || ''\n form.contact_phone = p.contact_phone || ''\n form.contact_email = p.contact_email || ''\n form.website = p.website || ''\n form.category = p.category || ''\n form.category_ids = p.category_ids || []\n form.supported_vehicle_classes = p.supported_vehicle_classes || []\n\n // Parse specializations - handle both object and string formats\n const spec = p.specializations || {}\n form.specializations = {\n brands: Array.isArray(spec.brands) ? spec.brands : [],\n propulsion: Array.isArray(spec.propulsion) ? spec.propulsion : [],\n }\n}\n\n// ── API: Fetch category tree ───────────────────────────\nasync function fetchCategoryTree() {\n treeLoading.value = true\n try {\n const res = await $fetch('/api/v1/providers/categories/tree', {\n headers: getHeaders(),\n })\n categoryTree.value = (res as CategoryTreeNode[]) || []\n } catch (err: any) {\n console.error('Failed to fetch category tree:', err)\n } finally {\n treeLoading.value = false\n }\n}\n\n// ── Category tree helpers ──────────────────────────────\n\n/**\n * Recursively finds a category node by ID in the tree.\n */\nfunction findCategoryById(id: number, nodes: CategoryTreeNode[]): CategoryTreeNode | null {\n for (const node of nodes) {\n if (node.id === id) return node\n if (node.children?.length) {\n const found = findCategoryById(id, node.children)\n if (found) return found\n }\n }\n return null\n}\n\n/**\n * Gets the display name for a category ID (for the selected chips).\n */\nfunction getCategoryName(id: number): string {\n const node = findCategoryById(id, categoryTree.value)\n if (!node) return `#${id}`\n return node.name_hu || node.name_en || node.key\n}\n\n// ── Dimension A: Vehicle Class toggles ─────────────────\n\n/**\n * Toggles a vehicle class in the form.supported_vehicle_classes array.\n * If already selected, removes it; otherwise adds it.\n */\nfunction toggleVehicleClass(key: string) {\n const idx = form.supported_vehicle_classes.indexOf(key)\n if (idx >= 0) {\n form.supported_vehicle_classes.splice(idx, 1)\n } else {\n form.supported_vehicle_classes.push(key)\n }\n}\n\n// ── Dimension B: Category toggles ──────────────────────\n\n/**\n * Toggles a category ID in the form.category_ids array.\n * If already selected, removes it; otherwise adds it.\n */\nfunction toggleCategory(id: number) {\n const idx = form.category_ids.indexOf(id)\n if (idx >= 0) {\n form.category_ids.splice(idx, 1)\n } else {\n form.category_ids.push(id)\n }\n}\n\n/**\n * Toggles the expanded/collapsed state of a tree node.\n */\nfunction toggleTreeNode(id: number) {\n const newSet = new Set(expandedNodes.value)\n if (newSet.has(id)) {\n newSet.delete(id)\n } else {\n newSet.add(id)\n }\n expandedNodes.value = newSet\n}\n\n/**\n * Checks if a category ID is currently selected.\n */\nfunction isCategorySelected(id: number): boolean {\n return form.category_ids.includes(id)\n}\n\n/**\n * Removes a category ID from the selection.\n */\nfunction removeCategory(id: number) {\n const idx = form.category_ids.indexOf(id)\n if (idx >= 0) {\n form.category_ids.splice(idx, 1)\n }\n}\n\n// ── Dimension C: Specialization tag management ─────────\n\n/**\n * Adds the current brandInput value to the brands array.\n */\nfunction addBrand() {\n const val = brandInput.value.trim()\n if (val && !form.specializations.brands.includes(val)) {\n form.specializations.brands.push(val)\n }\n brandInput.value = ''\n}\n\n/**\n * Removes a brand at the given index.\n */\nfunction removeBrand(idx: number) {\n form.specializations.brands.splice(idx, 1)\n}\n\n/**\n * Adds the current propulsionInput value to the propulsion array.\n */\nfunction addPropulsion() {\n const val = propulsionInput.value.trim()\n if (val && !form.specializations.propulsion.includes(val)) {\n form.specializations.propulsion.push(val)\n }\n propulsionInput.value = ''\n}\n\n/**\n * Removes a propulsion entry at the given index.\n */\nfunction removePropulsion(idx: number) {\n form.specializations.propulsion.splice(idx, 1)\n}\n\n// ── Save ───────────────────────────────────────────────\n\n/**\n * Saves the form data via PATCH /admin/providers/{id}.\n * Builds the payload matching the ProviderUpdateInput schema.\n * On success: navigates back to the provider detail page.\n * On error: shows error toast.\n */\nasync function saveForm() {\n if (saveLoading.value) return\n saveLoading.value = true\n\n const payload: Record<string, any> = {\n name: form.name,\n category: form.category || null,\n contact_phone: form.contact_phone || null,\n contact_email: form.contact_email || null,\n website: form.website || null,\n city: form.city || null,\n address_zip: form.address_zip || null,\n address_street_name: form.address_street_name || null,\n address_street_type: form.address_street_type || null,\n address_house_number: form.address_house_number || null,\n plus_code: form.plus_code || null,\n category_ids: form.category_ids,\n supported_vehicle_classes: form.supported_vehicle_classes,\n specializations: form.specializations,\n }\n\n try {\n await $fetch(`/api/v1/admin/providers/${providerId.value}`, {\n method: 'PATCH',\n headers: getHeaders(),\n body: payload,\n })\n showToast('success', 'Szolgáltató sikeresen frissítve!')\n setTimeout(() => {\n router.push(`/providers/${providerId.value}`)\n }, 1200)\n } catch (err: any) {\n console.error('Failed to save provider:', err)\n const msg = err?.data?.detail || err?.message || 'Ismeretlen hiba történt mentés közben.'\n showToast('error', `Hiba: ${msg}`)\n } finally {\n saveLoading.value = false\n }\n}\n\n// ── Navigation ─────────────────────────────────────────\n\n/**\n * Navigates back to the provider detail page.\n */\nfunction goBack() {\n router.push(`/providers/${providerId.value}`)\n}\n\n// ── Toast ──────────────────────────────────────────────\n\n/**\n * Shows a temporary toast notification that auto-hides after 3 seconds.\n */\nfunction showToast(type: 'success' | 'error', message: string) {\n toast.value = { type, message }\n setTimeout(() => {\n toast.value = null\n }, 3000)\n}\n\n// ── Lifecycle ──────────────────────────────────────────\n\nonMounted(async () => {\n await fetchProvider()\n await fetchCategoryTree()\n})\n</script>\n\n<style scoped>\n/* Custom scrollbar for the category tree */\n.overflow-y-auto::-webkit-scrollbar {\n width: 6px;\n}\n.overflow-y-auto::-webkit-scrollbar-track {\n background: transparent;\n}\n.overflow-y-auto::-webkit-scrollbar-thumb {\n background-color: rgba(100, 116, 139, 0.5);\n border-radius: 3px;\n}\n.overflow-y-auto::-webkit-scrollbar-thumb:hover {\n background-color: rgba(100, 116, 139, 0.7);\n}\n</style>"],"version":3} |