1 line
148 KiB
JSON
1 line
148 KiB
JSON
{"file":"index-CKl-ge5n.js","mappings":"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","names":["_ssrRenderAttrs","_mergeProps","$t","_ssrInterpolate","_ssrRenderList","_ssrRenderClass","_ssrRenderAttr","_ssrRenderComponent","_unref","_ssrIncludeBooleanAttr"],"sources":["../../../../components/garages/GarageGeneralTab.vue","../../../../components/garages/GarageFleetTab.vue","../../../../components/garages/GarageSubscriptionTab.vue","../../../../pages/garages/[id]/index.vue"],"sourcesContent":["<template>\n <div class=\"space-y-6\">\n <!-- Company Info -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden\">\n <div class=\"px-6 py-4 border-b border-slate-700 flex items-center gap-3\">\n <div class=\"p-2 rounded-lg bg-indigo-500/10 text-indigo-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\" />\n </svg>\n </div>\n <h3 class=\"text-base font-semibold text-white\">{{ $t('garages.details.company_info') }}</h3>\n </div>\n <div class=\"px-6 py-5\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div class=\"space-y-4\">\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.company_name') }}</p>\n <p class=\"text-sm text-white mt-1\">{{ garage.full_name }}</p>\n </div>\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.display_name') }}</p>\n <p class=\"text-sm text-white mt-1\">{{ garage.display_name || '—' }}</p>\n </div>\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.org_type') }}</p>\n <p class=\"text-sm text-white mt-1\">{{ orgTypeLabel(garage.org_type) }}</p>\n </div>\n </div>\n <div class=\"space-y-4\">\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.tax_number') }}</p>\n <p class=\"text-sm text-white mt-1\">{{ garage.tax_number || '—' }}</p>\n </div>\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.reg_number') }}</p>\n <p class=\"text-sm text-white mt-1\">{{ garage.reg_number || '—' }}</p>\n </div>\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.created_at') }}</p>\n <p class=\"text-sm text-white mt-1\">{{ formatDate(garage.created_at) }}</p>\n </div>\n </div>\n </div>\n <div class=\"mt-6 pt-6 border-t border-slate-700/50\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-3\">{{ $t('garages.details.address') }}</p>\n <p class=\"text-sm text-white\">{{ formattedAddress }}</p>\n </div>\n\n <!-- Billing Address -->\n <div v-if=\"formattedBillingAddress\" class=\"mt-4 pt-4 border-t border-slate-700/50\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-3\">{{ $t('garages.details.billing_address') }}</p>\n <p class=\"text-sm text-white\">{{ formattedBillingAddress }}</p>\n </div>\n\n <!-- Notification Address -->\n <div v-if=\"formattedNotificationAddress\" class=\"mt-4 pt-4 border-t border-slate-700/50\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-3\">{{ $t('garages.details.notification_address') }}</p>\n <p class=\"text-sm text-white\">{{ formattedNotificationAddress }}</p>\n </div>\n\n <!-- System IDs Footer -->\n <div class=\"mt-6 pt-4 border-t border-slate-700/50\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-3\">Rendszer Azonosítók</p>\n <div class=\"flex gap-6 text-xs font-mono text-slate-500\">\n <span>Garázs ID: <span class=\"text-slate-400\">{{ garage.id }}</span></span>\n <span>User ID: <span class=\"text-slate-400\">{{ garage.owner_user_id ?? 'N/A' }}</span></span>\n <span>Person ID: <span class=\"text-slate-400\">{{ garage.owner_person_id ?? 'N/A' }}</span></span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Contact Info -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden\">\n <div class=\"px-6 py-4 border-b border-slate-700 flex items-center gap-3\">\n <div class=\"p-2 rounded-lg bg-emerald-500/10 text-emerald-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n </div>\n <h3 class=\"text-base font-semibold text-white\">{{ $t('garages.details.contact_info') }}</h3>\n </div>\n <div class=\"px-6 py-5\">\n <!-- Show block if ANY contact data exists (top-level fields or primary_contact) -->\n <div v-if=\"garage.contact_person_name || garage.contact_email || garage.contact_phone || garage.primary_contact\" class=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div class=\"space-y-4\">\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.contact_name') }}</p>\n <p class=\"text-sm text-white mt-1 font-medium\">{{ garage.contact_person_name || garage.primary_contact?.full_name || '—' }}</p>\n </div>\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.contact_email') }}</p>\n <p class=\"text-sm text-white mt-1 flex items-center gap-1.5\">\n <svg class=\"w-4 h-4 text-slate-400 flex-shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\" />\n </svg>\n <span>{{ garage.contact_email || garage.primary_contact?.email || '—' }}</span>\n </p>\n </div>\n </div>\n <div class=\"space-y-4\">\n <div>\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.contact_phone') }}</p>\n <p class=\"text-sm text-white mt-1 flex items-center gap-1.5\">\n <svg class=\"w-4 h-4 text-slate-400 flex-shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z\" />\n </svg>\n <span>{{ garage.contact_phone || garage.primary_contact?.phone || '—' }}</span>\n </p>\n </div>\n <!-- Extra metadata from primary_contact if available -->\n <div v-if=\"garage.primary_contact?.role || garage.primary_contact?.department\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider\">{{ $t('garages.details.contact_role') }}</p>\n <p class=\"text-sm text-white mt-1\">{{ garage.primary_contact.role || '—' }}<span v-if=\"garage.primary_contact?.department\"> · {{ garage.primary_contact.department }}</span></p>\n </div>\n </div>\n </div>\n <div v-else class=\"text-center py-4\">\n <p class=\"text-sm text-slate-400\">{{ $t('garages.details.no_contact') }}</p>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n garage: any\n}>()\n\nfunction orgTypeLabel(type: string): string {\n const map: Record<string, string> = {\n dealership: 'Dealership',\n service: 'Service Center',\n rental: 'Rental Agency',\n fleet: 'Fleet Operator',\n individual: 'Individual',\n workshop: 'Workshop',\n garage: 'Garage',\n other: 'Other',\n }\n return map[type?.toLowerCase()] || type || '-'\n}\n\nfunction formatDate(dateStr: string | null | undefined): string {\n if (!dateStr) return '-'\n try {\n return new Intl.DateTimeFormat('hu-HU', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).format(new Date(dateStr))\n } catch {\n return dateStr\n }\n}\n\nconst formattedAddress = computed(() => {\n if (!props.garage) return ''\n const parts = [\n props.garage.address_zip,\n props.garage.address_city,\n props.garage.address_street_name,\n props.garage.address_street_type,\n props.garage.address_house_number,\n ].filter(Boolean)\n return parts.join(' ') || '-'\n})\n\nconst formattedBillingAddress = computed(() => {\n if (!props.garage) return ''\n const parts = [\n props.garage.billing_zip,\n props.garage.billing_city,\n props.garage.billing_street_name,\n props.garage.billing_street_type,\n props.garage.billing_house_number,\n ].filter(Boolean)\n return parts.join(' ') || ''\n})\n\nconst formattedNotificationAddress = computed(() => {\n if (!props.garage) return ''\n const parts = [\n props.garage.notification_zip,\n props.garage.notification_city,\n props.garage.notification_street_name,\n props.garage.notification_street_type,\n props.garage.notification_house_number,\n ].filter(Boolean)\n return parts.join(' ') || ''\n})\n</script>\n","<template>\n <div class=\"space-y-6\">\n <!-- RBAC guard: hide content without fleet:view -->\n <template v-if=\"hasOrgPermission('fleet:view')\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex items-center gap-3\">\n <div class=\"p-2 rounded-lg bg-indigo-500/10 text-indigo-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 17a2 2 0 11-4 0 2 2 0 014 0zM19 17a2 2 0 11-4 0 2 2 0 014 0z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 16V6a1 1 0 00-1-1H4a1 1 0 00-1 1v10a1 1 0 001 1h1m8-1a1 1 0 01-1 1H9m4-1V8a1 1 0 011-1h2.586a1 1 0 01.707.293l3.414 3.414a1 1 0 01.293.707V16a1 1 0 01-1 1h-1m-6-1a1 1 0 001 1h1M5 17a2 2 0 104 0m-4 0a2 2 0 114 0m6 0a2 2 0 104 0m-4 0a2 2 0 114 0\" />\n </svg>\n </div>\n <div>\n <h3 class=\"text-base font-semibold text-white\">{{ $t('garages.fleet.title') }}</h3>\n <p class=\"text-xs text-slate-400 mt-0.5\">{{ $t('garages.fleet.total_vehicles', { count: fleetVehicles.length }) }}</p>\n </div>\n </div>\n </div>\n\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden\">\n <div class=\"overflow-x-auto\">\n <table class=\"w-full text-sm\">\n <thead>\n <tr class=\"border-b border-slate-700\">\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.fleet.plate') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.fleet.brand_model') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.fleet.year') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.fleet.vin') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.fleet.status') }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"v in fleetVehicles\" :key=\"v.id\" class=\"border-b border-slate-700/50 last:border-b-0 hover:bg-slate-700/30 transition\">\n <td class=\"px-4 py-3\">\n <span class=\"text-sm font-bold text-white\">{{ v.license_plate || '—' }}</span>\n </td>\n <td class=\"px-4 py-3\">\n <span class=\"text-sm text-slate-300\">{{ v.brand || '—' }}</span>\n <span v-if=\"v.brand && v.model\" class=\"text-slate-500 mx-1\">·</span>\n <span v-if=\"v.model\" class=\"text-sm text-slate-300\">{{ v.model }}</span>\n </td>\n <td class=\"px-4 py-3 text-sm text-slate-300\">{{ v.year || '—' }}</td>\n <td class=\"px-4 py-3\">\n <span class=\"text-xs font-mono text-slate-400\">{{ v.vin || '—' }}</span>\n </td>\n <td class=\"px-4 py-3\">\n <span\n class=\"inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium\"\n :class=\"fleetStatusBadgeClass(v.status)\"\n >\n <span class=\"w-1.5 h-1.5 rounded-full\" :class=\"fleetStatusDotClass(v.status)\"></span>\n {{ fleetStatusLabel(v.status) }}\n </span>\n </td>\n </tr>\n <tr v-if=\"fleetVehicles.length === 0 && !fleetLoading\">\n <td colspan=\"5\" class=\"px-4 py-12 text-center\">\n <svg class=\"w-12 h-12 text-slate-600 mx-auto mb-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M9 17a2 2 0 11-4 0 2 2 0 014 0zM19 17a2 2 0 11-4 0 2 2 0 014 0z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M13 16V6a1 1 0 00-1-1H4a1 1 0 00-1 1v10a1 1 0 001 1h1m8-1a1 1 0 01-1 1H9m4-1V8a1 1 0 011-1h2.586a1 1 0 01.707.293l3.414 3.414a1 1 0 01.293.707V16a1 1 0 01-1 1h-1m-6-1a1 1 0 001 1h1M5 17a2 2 0 104 0m-4 0a2 2 0 114 0m6 0a2 2 0 104 0m-4 0a2 2 0 114 0\" />\n </svg>\n <p class=\"text-sm text-slate-400\">{{ $t('garages.fleet.no_vehicles') }}</p>\n </td>\n </tr>\n <tr v-if=\"fleetLoading\">\n <td colspan=\"5\" class=\"px-4 py-12 text-center\">\n <svg class=\"w-8 h-8 text-indigo-400 animate-spin mx-auto\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n <p class=\"text-sm text-slate-400 mt-2\">{{ $t('garages.details.loading') }}</p>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </template>\n <!-- RBAC: No fleet access fallback -->\n <template v-else>\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-12 text-center\">\n <svg class=\"w-12 h-12 text-slate-600 mx-auto mb-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636\" />\n </svg>\n <p class=\"text-sm text-slate-400\">{{ $t('garages.fleet.no_fleet_access') }}</p>\n </div>\n </template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useAuthStore } from '~/stores/auth'\n\nconst props = defineProps<{\n garage: any\n orgId: string\n fleetVehicles: any[]\n fleetLoading: boolean\n}>()\n\nconst auth = useAuthStore()\n\n// RBAC helper\nfunction hasOrgPermission(perm: string): boolean {\n if (auth.isAdmin) return true\n if (auth.user?.system_capabilities?.[perm]) return true\n if (auth.user?.org_capabilities?.[props.orgId]?.[perm]) return true\n return false\n}\n\nfunction fleetStatusLabel(status: string): string {\n const map: Record<string, string> = {\n active: 'Active',\n inactive: 'Inactive',\n sold: 'Sold',\n scrapped: 'Scrapped',\n pending: 'Pending',\n draft: 'Draft',\n }\n return map[status?.toLowerCase()] || status || 'Unknown'\n}\n\nfunction fleetStatusBadgeClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-500/10 text-green-400',\n inactive: 'bg-gray-500/10 text-gray-400',\n sold: 'bg-red-500/10 text-red-400',\n scrapped: 'bg-red-500/10 text-red-400',\n pending: 'bg-yellow-500/10 text-yellow-400',\n draft: 'bg-gray-500/10 text-gray-400',\n }\n return map[status?.toLowerCase()] || 'bg-gray-500/10 text-gray-400'\n}\n\nfunction fleetStatusDotClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-400',\n inactive: 'bg-gray-400',\n sold: 'bg-red-400',\n scrapped: 'bg-red-400',\n pending: 'bg-yellow-400',\n draft: 'bg-gray-400',\n }\n return map[status?.toLowerCase()] || 'bg-gray-400'\n}\n</script>\n","<template>\n <div class=\"space-y-6\">\n <!-- Current Package Card - Densified with Utilization Stats -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden\">\n <div class=\"px-6 py-4 border-b border-slate-700 flex items-center gap-3\">\n <div class=\"p-2 rounded-lg bg-amber-500/10 text-amber-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z\" />\n </svg>\n </div>\n <h3 class=\"text-base font-semibold text-white\">{{ $t('garages.details.subscription_info') }}</h3>\n </div>\n <div class=\"px-6 py-5\">\n <div v-if=\"garage.subscription\" class=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <!-- Tier Name -->\n <div class=\"bg-slate-900/30 rounded-lg p-3\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.tier_name') }}</p>\n <span class=\"inline-flex px-2.5 py-0.5 rounded-full text-xs font-medium\" :class=\"tierBadgeClass(garage.subscription.tier_name)\">\n {{ garage.subscription.tier_name }}\n </span>\n </div>\n <!-- Tier Level -->\n <div class=\"bg-slate-900/30 rounded-lg p-3\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.tier_level') }}</p>\n <p class=\"text-sm font-semibold text-white\">{{ $t('garages.details.level_n', { n: garage.subscription.tier_level }) }}</p>\n </div>\n <!-- Expiration -->\n <div class=\"bg-slate-900/30 rounded-lg p-3\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.expires_at') }}</p>\n <p v-if=\"garage.subscription.expires_at\" class=\"text-sm font-semibold text-white\">{{ formatDate(garage.subscription.expires_at) }}</p>\n <p v-else class=\"text-sm text-slate-400 italic\">{{ $t('garages.indefinite') }}</p>\n </div>\n <!-- Asset Limit -->\n <div class=\"bg-slate-900/30 rounded-lg p-3\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.asset_limit') }}</p>\n <p class=\"text-sm font-semibold text-white\">{{ garage.subscription.asset_limit }} {{ $t('garages.details.vehicles') }}</p>\n </div>\n </div>\n <!-- Utilization Stats Row -->\n <div v-if=\"garage.subscription\" class=\"mt-4 grid grid-cols-2 gap-4\">\n <!-- Vehicles Utilization -->\n <div class=\"bg-slate-900/30 rounded-lg p-3\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.vehicles_used') }}</p>\n <p class=\"text-sm font-semibold text-white\">\n {{ fleetVehicles.length }} / {{ garage.subscription?.asset_limit ?? '∞' }}\n </p>\n <div class=\"mt-2 w-full h-1.5 bg-slate-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all duration-500\"\n :class=\"vehicleQuotaPercent >= 90 ? 'bg-red-500' : vehicleQuotaPercent >= 70 ? 'bg-amber-500' : 'bg-blue-500'\"\n :style=\"{ width: Math.min(100, vehicleQuotaPercent) + '%' }\"\n ></div>\n </div>\n </div>\n <!-- Branches Utilization -->\n <div class=\"bg-slate-900/30 rounded-lg p-3\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.branches_used') }}</p>\n <p class=\"text-sm font-semibold text-white\">\n {{ garage.branches?.length || 0 }} / {{ garage.subscription?.branch_limit ?? '∞' }}\n </p>\n <div class=\"mt-2 w-full h-1.5 bg-slate-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all duration-500\"\n :class=\"branchQuotaPercent >= 90 ? 'bg-red-500' : branchQuotaPercent >= 70 ? 'bg-amber-500' : 'bg-emerald-500'\"\n :style=\"{ width: Math.min(100, branchQuotaPercent) + '%' }\"\n ></div>\n </div>\n </div>\n <!-- Employees Count (P0 ADD-ON: Now with user_limit bar) -->\n <div class=\"bg-slate-900/30 rounded-lg p-3\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.employees_used') }}</p>\n <p class=\"text-sm font-semibold text-white\">\n {{ garage.member_count || 0 }} / {{ (garage.subscription?.user_limit && garage.subscription.user_limit > 0) ? garage.subscription.user_limit : '∞' }}\n </p>\n <div v-if=\"garage.subscription?.user_limit && garage.subscription.user_limit > 0\" class=\"mt-2 w-full h-1.5 bg-slate-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all duration-500\"\n :class=\"employeeQuotaPercent >= 90 ? 'bg-red-500' : employeeQuotaPercent >= 70 ? 'bg-amber-500' : 'bg-purple-500'\"\n :style=\"{ width: Math.min(100, employeeQuotaPercent) + '%' }\"\n ></div>\n </div>\n </div>\n <!-- Status Badge -->\n <div class=\"bg-slate-900/30 rounded-lg p-3 flex flex-col justify-center\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.details.status') }}</p>\n <span\n class=\"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium self-start\"\n :class=\"statusBadgeClass(garage.status)\"\n >\n <span class=\"w-1.5 h-1.5 rounded-full\" :class=\"statusDotClass(garage.status)\"></span>\n {{ statusLabel(garage.status) }}\n </span>\n </div>\n </div>\n <!-- P0 UI/UX: Active Add-ons section inside the Subscription Status card -->\n <div v-if=\"garage.subscription?.addons?.length\" class=\"mt-4 border-t border-slate-700/50 pt-4\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-3\">{{ $t('garages.active_addons') }}</p>\n <div class=\"overflow-hidden border border-slate-700/50 rounded-lg\">\n <table class=\"w-full text-sm\">\n <thead>\n <tr class=\"bg-slate-900/40\">\n <th class=\"px-3 py-2 text-left text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.addon_type') }}</th>\n <th class=\"px-3 py-2 text-center text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.addon_quantity') }}</th>\n <th class=\"px-3 py-2 text-right text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.addon_expires') }}</th>\n </tr>\n </thead>\n <tbody class=\"divide-y divide-slate-700/50\">\n <tr v-for=\"addon in garage.subscription.addons\" :key=\"addon.type\" class=\"bg-slate-900/20 hover:bg-slate-900/40 transition\">\n <td class=\"px-3 py-2.5 text-slate-300\">{{ addonLabel(addon.type) }}</td>\n <td class=\"px-3 py-2.5 text-center\">\n <span class=\"inline-flex items-center justify-center w-7 h-7 rounded-full bg-indigo-500/20 text-indigo-300 text-xs font-bold\">{{ addon.quantity }}</span>\n </td>\n <td class=\"px-3 py-2.5 text-right text-slate-500\">\n <span v-if=\"addon.expires_at || addon.valid_until\">{{ formatDate(addon.expires_at || addon.valid_until) }}</span>\n <span v-else class=\"italic\">{{ $t('garages.indefinite') }}</span>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n <div v-else-if=\"garage.subscription\" class=\"mt-4 border-t border-slate-700/50 pt-4\">\n <p class=\"text-xs text-slate-500 uppercase tracking-wider mb-1\">{{ $t('garages.active_addons') }}</p>\n <div class=\"bg-slate-900/20 border border-slate-700/30 rounded-lg px-4 py-3 text-center\">\n <p class=\"text-xs text-slate-500 italic\">{{ $t('garages.no_active_addons') }}</p>\n </div>\n </div>\n <div v-else class=\"text-center py-4\">\n <p class=\"text-sm text-slate-400\">{{ $t('garages.details.no_subscription') }}</p>\n </div>\n </div>\n </div>\n\n <!-- Change Package Section -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden\">\n <div class=\"px-6 py-4 border-b border-slate-700 flex items-center gap-3\">\n <div class=\"p-2 rounded-lg bg-indigo-500/10 text-indigo-400\">\n <svg class=\"w-5 h-5\" 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 </div>\n <h3 class=\"text-base font-semibold text-white\">{{ $t('garages.change_package') }}</h3>\n </div>\n <div class=\"px-6 py-5 space-y-5\">\n <!-- Tier Selection -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-2\">{{ $t('garages.select_package') }}</label>\n <select\n v-model=\"selectedTierId\"\n class=\"w-full px-3 py-2.5 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition\"\n >\n <option value=\"\" disabled>{{ $t('garages.select_package_placeholder') }}</option>\n <option\n v-for=\"tier in availableTiers\"\n :key=\"tier.id\"\n :value=\"tier.id\"\n >\n {{ tier.name }} (Level {{ tier.tier_level }})\n </option>\n </select>\n </div>\n\n <!-- Custom Expiration Date -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-2\">\n {{ $t('garages.custom_expiration') }}\n <span class=\"text-xs text-slate-500 ml-1\">({{ $t('garages.optional') }})</span>\n </label>\n <input\n v-model=\"customExpiresAt\"\n type=\"date\"\n class=\"w-full px-3 py-2.5 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition\"\n />\n <p class=\"text-xs text-slate-500 mt-1.5\">{{ $t('garages.custom_expiration_hint') }}</p>\n </div>\n\n <!-- ── P0 ITEMIZED ADD-ON: Add-on editor with individual date pickers ── -->\n <div>\n <label class=\"block text-sm font-medium text-slate-300 mb-3\">\n {{ $t('garages.addons_title') }}\n <span class=\"text-xs text-slate-500 ml-1\">({{ $t('garages.optional') }})</span>\n </label>\n\n <!-- Add-on editor: number inputs with +/- buttons and individual date pickers -->\n <div class=\"grid grid-cols-1 md:grid-cols-3 gap-3\">\n <!-- Extra Vehicles -->\n <div class=\"bg-slate-900/30 border border-slate-700/50 rounded-lg p-3\">\n <label class=\"block text-xs text-slate-400 mb-1.5\">{{ $t('garages.addon_vehicles') }}</label>\n <div class=\"flex items-center gap-2\">\n <button\n @click=\"extraVehicles = Math.max(0, extraVehicles - 1)\"\n class=\"w-8 h-8 rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-300 flex items-center justify-center transition text-sm font-bold\"\n >−</button>\n <input\n v-model.number=\"extraVehicles\"\n type=\"number\"\n min=\"0\"\n max=\"999\"\n class=\"w-full px-2 py-1.5 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white text-center focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none\"\n />\n <button\n @click=\"extraVehicles = Math.min(999, extraVehicles + 1)\"\n class=\"w-8 h-8 rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-300 flex items-center justify-center transition text-sm font-bold\"\n >+</button>\n </div>\n <label class=\"block text-xs text-slate-500 mt-2 mb-1\">{{ $t('garages.addon_vehicles_expiration') }}</label>\n <input\n v-model=\"addonDates.vehicles\"\n type=\"date\"\n class=\"w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition\"\n />\n </div>\n <!-- Extra Branches -->\n <div class=\"bg-slate-900/30 border border-slate-700/50 rounded-lg p-3\">\n <label class=\"block text-xs text-slate-400 mb-1.5\">{{ $t('garages.addon_branches') }}</label>\n <div class=\"flex items-center gap-2\">\n <button\n @click=\"extraBranches = Math.max(0, extraBranches - 1)\"\n class=\"w-8 h-8 rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-300 flex items-center justify-center transition text-sm font-bold\"\n >−</button>\n <input\n v-model.number=\"extraBranches\"\n type=\"number\"\n min=\"0\"\n max=\"999\"\n class=\"w-full px-2 py-1.5 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white text-center focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none\"\n />\n <button\n @click=\"extraBranches = Math.min(999, extraBranches + 1)\"\n class=\"w-8 h-8 rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-300 flex items-center justify-center transition text-sm font-bold\"\n >+</button>\n </div>\n <label class=\"block text-xs text-slate-500 mt-2 mb-1\">{{ $t('garages.addon_branches_expiration') }}</label>\n <input\n v-model=\"addonDates.branches\"\n type=\"date\"\n class=\"w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition\"\n />\n </div>\n <!-- Extra Users -->\n <div class=\"bg-slate-900/30 border border-slate-700/50 rounded-lg p-3\">\n <label class=\"block text-xs text-slate-400 mb-1.5\">{{ $t('garages.addon_users') }}</label>\n <div class=\"flex items-center gap-2\">\n <button\n @click=\"extraUsers = Math.max(0, extraUsers - 1)\"\n class=\"w-8 h-8 rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-300 flex items-center justify-center transition text-sm font-bold\"\n >−</button>\n <input\n v-model.number=\"extraUsers\"\n type=\"number\"\n min=\"0\"\n max=\"999\"\n class=\"w-full px-2 py-1.5 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white text-center focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none\"\n />\n <button\n @click=\"extraUsers = Math.min(999, extraUsers + 1)\"\n class=\"w-8 h-8 rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-300 flex items-center justify-center transition text-sm font-bold\"\n >+</button>\n </div>\n <label class=\"block text-xs text-slate-500 mt-2 mb-1\">{{ $t('garages.addon_users_expiration') }}</label>\n <input\n v-model=\"addonDates.users\"\n type=\"date\"\n class=\"w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition\"\n />\n </div>\n </div>\n\n <p class=\"text-xs text-slate-500 mt-3\">{{ $t('garages.addon_expiration_hint') }}</p>\n </div>\n\n <!-- Save Error -->\n <div\n v-if=\"subscriptionSaveError\"\n class=\"bg-red-500/10 border border-red-500/20 rounded-lg px-4 py-3\"\n >\n <p class=\"text-sm text-red-400\">{{ subscriptionSaveError }}</p>\n </div>\n\n <!-- Save Button -->\n <div class=\"flex items-center justify-end gap-3 pt-2\">\n <button\n @click=\"updateSubscription\"\n :disabled=\"subscriptionSaving || (!selectedTierId && !addonsChanged)\"\n class=\"px-5 py-2 text-sm font-medium rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed\"\n :class=\"subscriptionSaving\n ? 'bg-indigo-600/50 text-indigo-200 cursor-wait'\n : 'bg-indigo-600 text-white hover:bg-indigo-500'\"\n >\n <span v-if=\"subscriptionSaving\" class=\"flex items-center gap-2\">\n <svg class=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n {{ $t('garages.saving') }}\n </span>\n <span v-else>{{ $t('garages.save') }}</span>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Subscription History Section -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden\">\n <div class=\"px-6 py-4 border-b border-slate-700 flex items-center gap-3\">\n <div class=\"p-2 rounded-lg bg-cyan-500/10 text-cyan-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n </div>\n <h3 class=\"text-base font-semibold text-white\">{{ $t('garages.details.subscription_history') }}</h3>\n </div>\n <div class=\"px-6 py-5\">\n <div class=\"overflow-x-auto\">\n <table class=\"w-full text-sm\">\n <thead>\n <tr class=\"border-b border-slate-700\">\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.details.history_date') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.details.history_package') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.details.history_action') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.details.history_status') }}</th>\n </tr>\n </thead>\n <tbody>\n <template v-if=\"garage?.subscription_history?.length\">\n <tr v-for=\"hist in garage.subscription_history\" :key=\"hist.id\" class=\"border-b border-slate-700/50 last:border-b-0 hover:bg-slate-700/30 transition\">\n <td class=\"px-4 py-3 text-sm text-slate-300\">\n {{ formatDate(hist.timestamp) }}\n </td>\n <td class=\"px-4 py-3 text-sm text-slate-300\">\n {{ hist.tier_name || '—' }}\n </td>\n <td class=\"px-4 py-3 text-sm text-slate-300 max-w-xs\">\n <!-- P0 AUDIT DETAILS: Show parsed data diff instead of generic changes_summary -->\n <div class=\"space-y-1\">\n <span class=\"text-xs text-slate-400 block\">{{ hist.action || '—' }}</span>\n <div v-if=\"formatChanges(hist)\" class=\"text-xs text-slate-300 space-y-0.5\">\n <div v-for=\"(line, li) in formatChanges(hist)\" :key=\"li\" class=\"flex items-start gap-1\">\n <span class=\"text-cyan-400 shrink-0\">›</span>\n <span>{{ line }}</span>\n </div>\n </div>\n <span v-else class=\"text-xs text-slate-500 italic\">Nincs részletes adat</span>\n </div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"flex flex-col gap-1\">\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-500/10 text-green-400\"\n >\n Sikeres\n </span>\n <!-- P0 AUDIT DETAILS: Show admin_user_id -->\n <span v-if=\"hist.admin_user_id\" class=\"text-[10px] text-slate-500 text-center\">\n Admin #{{ hist.admin_user_id }}\n </span>\n </div>\n </td>\n </tr>\n </template>\n <template v-else>\n <tr>\n <td colspan=\"4\" class=\"px-4 py-12 text-center\">\n <div class=\"flex flex-col items-center gap-3\">\n <svg class=\"w-10 h-10 text-slate-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <p class=\"text-sm text-slate-400\">{{ $t('garages.details.no_subscription_history') }}</p>\n </div>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted, watch } from 'vue'\nimport { useAuthStore } from '~/stores/auth'\n\nconst props = defineProps<{\n garage: any\n fleetVehicles: any[]\n}>()\n\nconst emit = defineEmits<{\n refresh: []\n}>()\n\nconst auth = useAuthStore()\n\n// ── Subscription tab state ──\nconst availableTiers = ref<any[]>([])\n\n// ── Fetch tiers on mount so the dropdown is populated ──\nonMounted(() => {\n fetchTiers()\n})\nconst selectedTierId = ref<number | ''>('')\nconst customExpiresAt = ref('')\nconst subscriptionSaving = ref(false)\nconst subscriptionSaveError = ref<string | null>(null)\n\n// ── P0 CRITICAL FIX: Initialize add-on refs from existing subscription data ──\n// Previously these were hardcoded to 0, which caused existing add-ons to be\n// deleted on save (the frontend sent 0 for all add-on types, overwriting them).\nconst extraVehicles = ref(0)\nconst extraBranches = ref(0)\nconst extraUsers = ref(0)\nconst addonDates = reactive({\n vehicles: '',\n branches: '',\n users: '',\n})\n\n// ── P0 CRITICAL FIX: Sync add-on refs when garage subscription data loads ──\n// This ensures the form inputs reflect the ACTUAL stored values, not zero.\nfunction syncAddonFromSubscription() {\n const sub = props.garage?.subscription\n if (!sub) return\n const allowances = sub.extra_allowances || {}\n extraVehicles.value = allowances.extra_vehicles ?? 0\n extraBranches.value = allowances.extra_branches ?? 0\n extraUsers.value = allowances.extra_users ?? 0\n // Also sync add-on dates from the addons array if available\n if (sub.addons?.length) {\n for (const addon of sub.addons) {\n if (addon.type === 'extra_vehicles' && addon.expires_at) {\n addonDates.vehicles = addon.expires_at.slice(0, 10)\n } else if (addon.type === 'extra_branches' && addon.expires_at) {\n addonDates.branches = addon.expires_at.slice(0, 10)\n } else if (addon.type === 'extra_users' && addon.expires_at) {\n addonDates.users = addon.expires_at.slice(0, 10)\n }\n }\n }\n}\n\n// Watch for garage subscription changes and sync add-on values\nwatch(() => props.garage?.subscription, (newSub) => {\n if (newSub) {\n syncAddonFromSubscription()\n }\n}, { immediate: true })\n\n// ── Computed ──\nconst vehicleQuotaLimit = computed(() => {\n if (!props.garage?.subscription?.asset_limit) return 5\n return props.garage.subscription.asset_limit\n})\n\nconst vehicleQuotaPercent = computed(() => {\n const limit = vehicleQuotaLimit.value\n if (limit <= 0) return 0\n return Math.min(100, Math.round((props.fleetVehicles.length / limit) * 100))\n})\n\nconst branchQuotaPercent = computed(() => {\n const branches = props.garage?.branches?.length || 0\n const limit = props.garage?.subscription?.branch_limit\n if (!limit || limit <= 0) return 0\n return Math.min(100, Math.round((branches / limit) * 100))\n})\n\nconst employeeQuotaPercent = computed(() => {\n const count = props.garage?.member_count || 0\n const limit = props.garage?.subscription?.user_limit\n if (!limit || limit <= 0) return 0\n return Math.min(100, Math.round((count / limit) * 100))\n})\n\nconst addonsChanged = computed(() => {\n if (!props.garage?.subscription) return false\n const sub = props.garage.subscription\n const baselineVehicles = sub.extra_allowances?.extra_vehicles ?? 0\n const baselineBranches = sub.extra_allowances?.extra_branches ?? 0\n const baselineUsers = sub.extra_allowances?.extra_users ?? 0\n return (\n extraVehicles.value !== baselineVehicles ||\n extraBranches.value !== baselineBranches ||\n extraUsers.value !== baselineUsers\n )\n})\n\n// ── P0 AUDIT DETAILS: Parse old_data/new_data into human-readable diff lines ──\nfunction formatChanges(hist: any): string[] | null {\n if (!hist) return null\n const oldData = hist.old_data || {}\n const newData = hist.new_data || {}\n const lines: string[] = []\n\n // SUBSCRIPTION_TIER_CHANGE: Show tier_id change\n if (hist.action === 'SUBSCRIPTION_TIER_CHANGE') {\n const oldTier = oldData.tier_id\n const newTier = newData.tier_id\n const newTierName = newData.tier_name\n if (oldTier !== undefined || newTier !== undefined) {\n lines.push(`Csomag: #${oldTier ?? '?'} → ${newTierName ?? '#' + newTier}`)\n }\n // Show addon changes within tier change\n const oldAddons = oldData.addons || {}\n const newAddons = newData.addons || {}\n for (const key of ['extra_vehicles', 'extra_branches', 'extra_users']) {\n const oldVal = oldAddons[key] ?? 0\n const newVal = newAddons[key] ?? 0\n if (oldVal !== newVal) {\n const label = key === 'extra_vehicles' ? 'Extra Jármű'\n : key === 'extra_branches' ? 'Extra Telephely'\n : 'Extra Dolgozó'\n lines.push(`${label}: ${oldVal} → ${newVal}`)\n }\n }\n return lines.length > 0 ? lines : null\n }\n\n // SUBSCRIPTION_ADDON_OVERRIDE: Show individual add-on changes\n if (hist.action === 'SUBSCRIPTION_ADDON_OVERRIDE') {\n const oldAddons = oldData.addons || {}\n const newAddons = newData.addons || {}\n let hasChanges = false\n for (const key of ['extra_vehicles', 'extra_branches', 'extra_users']) {\n const oldVal = oldAddons[key] ?? 0\n const newVal = newAddons[key] ?? 0\n if (oldVal !== newVal) {\n hasChanges = true\n const label = key === 'extra_vehicles' ? 'Extra Jármű'\n : key === 'extra_branches' ? 'Extra Telephely'\n : 'Extra Dolgozó'\n lines.push(`${label}: ${oldVal} → ${newVal}`)\n }\n }\n return hasChanges ? lines : null\n }\n\n // Generic fallback: show any differing keys between old_data and new_data\n const allKeys = new Set([...Object.keys(oldData), ...Object.keys(newData)])\n for (const key of allKeys) {\n if (key === 'addons') continue // already handled above\n const oldVal = JSON.stringify(oldData[key] ?? null)\n const newVal = JSON.stringify(newData[key] ?? null)\n if (oldVal !== newVal) {\n lines.push(`${key}: ${oldVal} → ${newVal}`)\n }\n }\n\n return lines.length > 0 ? lines : null\n}\n\n// ── Helpers ──\nfunction formatDate(dateStr: string | null | undefined): string {\n if (!dateStr) return '-'\n try {\n return new Intl.DateTimeFormat('hu-HU', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).format(new Date(dateStr))\n } catch {\n return dateStr\n }\n}\n\nfunction addonLabel(type: string): string {\n const map: Record<string, string> = {\n extra_vehicles: 'Extra Jármű',\n extra_branches: 'Extra Telephely',\n extra_users: 'Extra Dolgozó',\n }\n return map[type] || type\n}\n\nfunction tierBadgeClass(tier: string | null | undefined): string {\n const map: Record<string, string> = {\n basic: 'bg-gray-100 text-gray-800',\n premium: 'bg-yellow-100 text-yellow-800',\n enterprise: 'bg-purple-100 text-purple-800',\n trial: 'bg-blue-100 text-blue-800',\n }\n return map[tier?.toLowerCase()] || 'bg-gray-100 text-gray-800'\n}\n\nfunction statusLabel(status: string): string {\n const map: Record<string, string> = {\n active: 'Active',\n inactive: 'Inactive',\n suspended: 'Suspended',\n pending: 'Pending',\n }\n return map[status?.toLowerCase()] || status\n}\n\nfunction statusBadgeClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-100 text-green-800',\n inactive: 'bg-gray-100 text-gray-800',\n suspended: 'bg-red-100 text-red-800',\n pending: 'bg-yellow-100 text-yellow-800',\n }\n return map[status?.toLowerCase()] || 'bg-gray-100 text-gray-800'\n}\n\nfunction statusDotClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-400',\n inactive: 'bg-gray-400',\n suspended: 'bg-red-400',\n pending: 'bg-yellow-400',\n }\n return map[status?.toLowerCase()] || 'bg-gray-400'\n}\n\n// ── Subscription Tab Functions ──\n\nasync function fetchTiers() {\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n console.log('[GarageSubscriptionTab] Fetching tiers...')\n const res = await fetch('/api/v1/admin/packages?include_hidden=true&limit=100', {\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n })\n if (!res.ok) {\n const errBody = await res.text().catch(() => '')\n console.error(`[GarageSubscriptionTab] Fetch tiers failed: ${res.status} ${res.statusText}`, errBody)\n throw new Error(`Failed to fetch tiers: ${res.status} ${errBody}`)\n }\n const data = await res.json()\n console.log('[GarageSubscriptionTab] Fetched tiers response:', JSON.stringify(data))\n availableTiers.value = data.tiers || []\n console.log('[GarageSubscriptionTab] availableTiers set:', availableTiers.value.length, 'items')\n } catch (e: any) {\n console.error('[GarageSubscriptionTab] Failed to fetch tiers:', e)\n subscriptionSaveError.value = `Hiba a csomagok betöltésekor: ${e.message}`\n }\n}\n\nasync function updateSubscription() {\n if (!selectedTierId.value && !addonsChanged.value) return\n\n subscriptionSaving.value = true\n subscriptionSaveError.value = null\n\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n const orgId = props.garage?.id\n\n const payload: Record<string, unknown> = {}\n\n if (selectedTierId.value) {\n payload.tier_id = selectedTierId.value\n }\n\n if (customExpiresAt.value) {\n payload.expires_at = new Date(customExpiresAt.value).toISOString()\n }\n\n payload.extra_vehicles = extraVehicles.value\n payload.extra_branches = extraBranches.value\n payload.extra_users = extraUsers.value\n\n // P0 ITEMIZED ADD-ON: Send individual expiration dates per add-on type\n payload.extra_vehicles_expires_at = addonDates.vehicles || null\n payload.extra_branches_expires_at = addonDates.branches || null\n payload.extra_users_expires_at = addonDates.users || null\n\n // ── P0 DEBUG: Log the exact payload being sent to the backend ──\n console.log('[GarageSubscriptionTab] PATCH Payload:', JSON.stringify(payload, null, 2))\n\n const res = await fetch(`/api/v1/admin/organizations/${orgId}/subscription`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n })\n\n if (!res.ok) {\n const errData = await res.json().catch(() => ({}))\n throw new Error(errData.detail || `Update subscription failed: ${res.status}`)\n }\n\n // Reset form state\n selectedTierId.value = ''\n emit('refresh')\n } catch (e: any) {\n subscriptionSaveError.value = e.message || 'Failed to update subscription'\n } finally {\n subscriptionSaving.value = false\n }\n}\n\n// Expose fetchTiers so the parent can call it on tab activation\ndefineExpose({ fetchTiers })\n</script>\n","<template>\n <div>\n <!-- Loading State -->\n <div v-if=\"loading\" class=\"flex items-center justify-center py-20\">\n <div class=\"flex flex-col items-center gap-3\">\n <svg class=\"w-8 h-8 text-indigo-400 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n <p class=\"text-slate-400 text-sm\">{{ $t('garages.details.loading') }}</p>\n </div>\n </div>\n\n <!-- Error State -->\n <div v-else-if=\"error\" class=\"flex flex-col items-center justify-center py-20 text-center\">\n <svg class=\"w-12 h-12 text-red-500 mb-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z\" />\n </svg>\n <p class=\"text-red-400 text-sm mb-2\">{{ error }}</p>\n <button @click=\"fetchDetails\" class=\"px-4 py-2 text-sm bg-indigo-600/20 text-indigo-300 hover:bg-indigo-600/30 rounded-lg transition\">\n {{ $t('garages.details.retry') }}\n </button>\n </div>\n\n <!-- Content -->\n <template v-else-if=\"garage\">\n <!-- Missing Data Alerter -->\n <div\n v-if=\"missingFields.length > 0\"\n class=\"mb-6 p-4 bg-amber-500/10 border border-amber-500/30 rounded-xl\"\n >\n <div class=\"flex items-start gap-3\">\n <div class=\"p-1.5 rounded-lg bg-amber-500/20 text-amber-400 flex-shrink-0\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z\" />\n </svg>\n </div>\n <div class=\"flex-1 min-w-0\">\n <div class=\"flex items-center justify-between\">\n <p class=\"text-sm font-semibold text-amber-300\">{{ $t('garages.details.missing_data_title') }}</p>\n <span class=\"text-xs text-amber-400/70\">{{ $t('garages.details.missing_data_count', { count: missingFields.length }) }}</span>\n </div>\n <p class=\"text-xs text-amber-400/80 mt-1\">\n {{ garage.status !== 'active' ? $t('garages.details.missing_data_activation_required') : $t('garages.details.missing_data_desc') }}\n </p>\n <div class=\"flex flex-wrap gap-2 mt-3\">\n <span\n v-for=\"field in missingFields\"\n :key=\"field.key\"\n class=\"inline-flex items-center gap-1 px-2.5 py-1 rounded-md text-xs font-medium bg-amber-500/10 text-amber-300\"\n >\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 {{ $t(field.label) }}\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- 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 {{ $t('garages.details.back') }}\n </button>\n\n <div class=\"flex items-center justify-between\">\n <div class=\"flex items-center gap-4\">\n <div\n class=\"w-12 h-12 rounded-xl flex items-center justify-center text-lg font-bold text-white\"\n :class=\"getInitialsColor(garageDisplayName())\"\n >\n {{ getInitials(garageDisplayName()) }}\n </div>\n <div>\n <div class=\"flex items-center gap-3\">\n <h1 class=\"text-2xl font-bold text-white\">{{ cleanGarageName }}</h1>\n <span\n class=\"inline-flex items-center px-3 py-1 rounded-full text-xs font-medium\"\n :class=\"statusBadgeClass(garage.status)\"\n >\n <span class=\"w-1.5 h-1.5 rounded-full mr-1.5\" :class=\"statusDotClass(garage.status)\"></span>\n {{ statusLabel(garage.status) }}\n </span>\n </div>\n <p class=\"text-sm text-slate-400 mt-0.5\">\n {{ garage.full_name }}\n <span v-if=\"garage.tax_number\" class=\"ml-2 text-slate-500\">· {{ $t('garages.details.tax_number') }}: {{ garage.tax_number }}</span>\n </p>\n </div>\n </div>\n <div class=\"flex items-center gap-3\">\n <button\n v-if=\"hasOrgPermission('org:edit')\"\n @click=\"openEditModal\"\n class=\"inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium bg-indigo-600/20 text-indigo-300 hover:bg-indigo-600/30 rounded-lg transition\"\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=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n {{ $t('garages.details.edit_details') }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Tab Navigation -->\n <div class=\"border-b border-slate-700 mb-6\">\n <nav class=\"flex gap-6\">\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 transition border-b-2 -mb-px\"\n :class=\"activeTab === tab.key\n ? 'text-indigo-400 border-indigo-400'\n : 'text-slate-400 border-transparent hover:text-slate-300'\"\n >\n {{ $t(tab.label) }}\n </button>\n </nav>\n </div>\n\n <!-- ============================================================ -->\n <!-- General Tab - Extracted Component -->\n <!-- ============================================================ -->\n <GaragesGarageGeneralTab v-if=\"activeTab === 'general'\" :garage=\"garage\" />\n\n <!-- ============================================================ -->\n <!-- Employees Tab (Dolgozók) -->\n <!-- ============================================================ -->\n <div v-if=\"activeTab === 'employees'\" class=\"space-y-6\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex items-center gap-3\">\n <div class=\"p-2 rounded-lg bg-cyan-500/10 text-cyan-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z\" />\n </svg>\n </div>\n <div>\n <h3 class=\"text-base font-semibold text-white\">{{ $t('garages.employees.title') }}</h3>\n <p class=\"text-xs text-slate-400 mt-0.5\">{{ $t('garages.employees.total_count', { count: members.length }) }}</p>\n </div>\n </div>\n <button\n v-if=\"hasOrgPermission('org:manage-members')\"\n @click=\"openAddEmployeeModal\"\n class=\"inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium bg-emerald-600/20 text-emerald-300 hover:bg-emerald-600/30 rounded-lg transition\"\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=\"M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z\" />\n </svg>\n {{ $t('garages.employees.add_employee') }}\n </button>\n </div>\n\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden\">\n <div class=\"overflow-x-auto\">\n <table class=\"w-full text-sm\">\n <thead>\n <tr class=\"border-b border-slate-700\">\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.employees.name') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.employees.email_phone') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.employees.role') }}</th>\n <th class=\"text-left px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.employees.status') }}</th>\n <th class=\"text-right px-4 py-3 text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.employees.actions') }}</th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"member in members\" :key=\"member.id\" class=\"border-b border-slate-700/50 last:border-b-0 hover:bg-slate-700/30 transition\">\n <td class=\"px-4 py-3\">\n <div class=\"flex items-center gap-3\">\n <div class=\"w-8 h-8 rounded-lg flex items-center justify-center text-xs font-bold text-white flex-shrink-0\" :class=\"getInitialsColor(memberFullName(member))\">\n {{ getInitials(memberFullName(member)) }}\n </div>\n <div>\n <p class=\"text-sm font-medium text-white\">{{ memberFullName(member) }}</p>\n <p class=\"text-xs text-slate-500\">ID: {{ member.user_id || member.id }}</p>\n <div class=\"flex gap-3 mt-0.5 text-xs text-slate-500 font-mono\">\n <span>User_id: <span class=\"text-slate-400\">{{ member.user_id || 'N/A' }}</span></span>\n <span>Person_id: <span class=\"text-slate-400\">{{ member.person?.id || 'N/A' }}</span></span>\n </div>\n </div>\n </div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"space-y-0.5\">\n <p v-if=\"member.person?.email\" class=\"text-sm text-slate-300\">{{ member.person.email }}</p>\n <p v-else class=\"text-sm text-slate-500 italic\">—</p>\n <p v-if=\"member.person?.phone\" class=\"text-xs text-slate-400\">{{ member.person.phone }}</p>\n </div>\n </td>\n <td class=\"px-4 py-3\">\n <span class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\" :class=\"roleBadgeClass(member.role)\">\n {{ roleLabel(member.role) }}\n </span>\n </td>\n <td class=\"px-4 py-3\">\n <span class=\"inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium\" :class=\"memberStatusBadgeClass(member.status)\">\n <span class=\"w-1.5 h-1.5 rounded-full\" :class=\"memberStatusDotClass(member.status)\"></span>\n {{ memberStatusLabel(member.status) }}\n </span>\n </td>\n <td class=\"px-4 py-3 text-right\">\n <div class=\"flex items-center justify-end gap-2\">\n <button\n v-if=\"hasOrgPermission('org:manage-members')\"\n @click=\"openEditRole(member)\"\n class=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-indigo-300 bg-indigo-500/10 hover:bg-indigo-500/20 rounded-lg transition\"\n >\n <svg class=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n {{ $t('garages.employees.edit_role') }}\n </button>\n <button\n v-if=\"hasOrgPermission('org:manage-members')\"\n @click=\"confirmRemoveMember(member)\"\n class=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-red-300 bg-red-500/10 hover:bg-red-500/20 rounded-lg transition\"\n >\n <svg class=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n {{ $t('garages.employees.remove') }}\n </button>\n </div>\n </td>\n </tr>\n <tr v-if=\"members.length === 0\">\n <td colspan=\"5\" class=\"px-4 py-12 text-center\">\n <svg class=\"w-10 h-10 text-slate-600 mx-auto mb-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n <p class=\"text-sm text-slate-400\">{{ $t('garages.employees.no_employees') }}</p>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <!-- ============================================================ -->\n <!-- Fleet Tab - Extracted Component -->\n <!-- ============================================================ -->\n <GaragesGarageFleetTab\n v-if=\"activeTab === 'fleet'\"\n :garage=\"garage\"\n :org-id=\"orgId\"\n :fleet-vehicles=\"fleetVehicles\"\n :fleet-loading=\"fleetLoading\"\n />\n\n <!-- ============================================================ -->\n <!-- Subscription Tab - Extracted Component -->\n <!-- ============================================================ -->\n <GaragesGarageSubscriptionTab\n v-if=\"activeTab === 'subscription'\"\n ref=\"subscriptionTabRef\"\n :garage=\"garage\"\n :fleet-vehicles=\"fleetVehicles\"\n @refresh=\"fetchDetails\"\n />\n\n <!-- ============================================================ -->\n <!-- Analytics Tab - Full Dashboard with Gamification -->\n <!-- ============================================================ -->\n <div v-if=\"activeTab === 'analytics'\" class=\"space-y-6\">\n\n <!-- SECTION 1: Financial & Revenue (Top Row - 3 Cards) -->\n <div class=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <!-- Card 1: LTV - Élettartam Érték -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-3\">\n <div class=\"p-2 rounded-lg bg-emerald-500/10 text-emerald-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 7h8m0 0v8m0-8l-8 8-4-4-6 6\" />\n </svg>\n </div>\n <span class=\"text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.analytics.ltv') }}</span>\n </div>\n <p class=\"text-2xl font-bold text-white\">150 000 Ft</p>\n <p class=\"text-xs text-emerald-400 mt-1 flex items-center gap-1\">\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=\"M5 10l7-7m0 0l7 7m-7-7v18\" />\n </svg>\n +12% ezen a hónapon\n </p>\n </div>\n\n <!-- Card 2: MRR - Havi Bevétel -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-3\">\n <div class=\"p-2 rounded-lg bg-blue-500/10 text-blue-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n </div>\n <span class=\"text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.analytics.mrr') }}</span>\n </div>\n <p class=\"text-2xl font-bold text-white\">15 000 Ft</p>\n <p class=\"text-xs text-slate-400 mt-1\">{{ $t('garages.analytics.monthly_recurring') }}</p>\n </div>\n\n <!-- Card 3: Kintlévőség -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-3\">\n <div class=\"p-2 rounded-lg bg-amber-500/10 text-amber-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 14l6-6m-5.5.5h.01m4.99 5h.01M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16l3.5-2 3.5 2 3.5-2 3.5 2zM10 8.5a.5.5 0 11-1 0 .5.5 0 011 0zm5 5a.5.5 0 11-1 0 .5.5 0 011 0z\" />\n </svg>\n </div>\n <span class=\"text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.analytics.outstanding') }}</span>\n </div>\n <p class=\"text-2xl font-bold text-white\">0 Ft</p>\n <p class=\"text-xs text-emerald-400 mt-1 flex items-center gap-1\">\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=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n {{ $t('garages.analytics.all_settled') }}\n </p>\n </div>\n </div>\n\n <!-- SECTION 2: Gamification & Rewards (Second Row - 3 Cards) -->\n <div class=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <!-- Card 1: Szerzett Kreditek -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-3\">\n <div class=\"p-2 rounded-lg bg-yellow-500/10 text-yellow-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z\" />\n </svg>\n </div>\n <span class=\"text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.analytics.earned_credits') }}</span>\n </div>\n <p class=\"text-2xl font-bold text-yellow-300\">450 XP</p>\n <p class=\"text-xs text-slate-400 mt-1\">{{ $t('garages.analytics.contribution_xp') }}</p>\n </div>\n\n <!-- Card 2: Meghívott Cégek -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-3\">\n <div class=\"p-2 rounded-lg bg-purple-500/10 text-purple-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z\" />\n </svg>\n </div>\n <span class=\"text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.analytics.invited_companies') }}</span>\n </div>\n <p class=\"text-2xl font-bold text-white\">12</p>\n <p class=\"text-xs text-slate-400 mt-1\">{{ $t('garages.analytics.companies_joined') }}</p>\n </div>\n\n <!-- Card 3: Validált Garázsok -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-3\">\n <div class=\"p-2 rounded-lg bg-cyan-500/10 text-cyan-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z\" />\n </svg>\n </div>\n <span class=\"text-xs font-medium text-slate-400 uppercase tracking-wider\">{{ $t('garages.analytics.validated_garages') }}</span>\n </div>\n <p class=\"text-2xl font-bold text-white\">8</p>\n <p class=\"text-xs text-slate-400 mt-1\">{{ $t('garages.analytics.garages_confirmed') }}</p>\n </div>\n </div>\n\n <!-- SECTION 3 & 4: Bottom Row - Utilization + Marketplace -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- SECTION 3: Utilization Bars (Bottom Left) -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-4\">\n <div class=\"p-2 rounded-lg bg-indigo-500/10 text-indigo-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\" />\n </svg>\n </div>\n <h3 class=\"text-sm font-semibold text-white\">{{ $t('garages.analytics.utilization') }}</h3>\n </div>\n\n <!-- Vehicle Quota Bar -->\n <div class=\"mb-4\">\n <div class=\"flex items-center justify-between mb-1.5\">\n <span class=\"text-xs text-slate-400\">{{ $t('garages.analytics.vehicle_quota') }}</span>\n <span class=\"text-xs text-slate-500\">{{ fleetVehicles.length }} / {{ vehicleQuotaLimit }}</span>\n </div>\n <div class=\"w-full h-2 bg-slate-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all duration-500\"\n :class=\"vehicleQuotaPercent >= 90 ? 'bg-red-500' : vehicleQuotaPercent >= 70 ? 'bg-amber-500' : 'bg-blue-500'\"\n :style=\"{ width: vehicleQuotaPercent + '%' }\"\n ></div>\n </div>\n <p class=\"text-xs text-slate-500 mt-1\">{{ vehicleQuotaPercent }}% {{ $t('garages.analytics.utilized') }}</p>\n </div>\n\n </div>\n\n <!-- SECTION 4: Marketplace & Engagement (Bottom Right) -->\n <div class=\"bg-slate-800/50 border border-slate-700 rounded-xl p-5\">\n <div class=\"flex items-center gap-3 mb-4\">\n <div class=\"p-2 rounded-lg bg-pink-500/10 text-pink-400\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11 3.055A9.001 9.001 0 1020.945 13H11V3.055z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.488 9H15V3.512A9.025 9.025 0 0120.488 9z\" />\n </svg>\n </div>\n <h3 class=\"text-sm font-semibold text-white\">{{ $t('garages.analytics.marketplace_engagement') }}</h3>\n </div>\n\n <!-- Average Rating -->\n <div class=\"flex items-center justify-between py-2 border-b border-slate-700/50\">\n <span class=\"text-xs text-slate-400\">{{ $t('garages.analytics.avg_rating') }}</span>\n <div class=\"flex items-center gap-1\">\n <svg class=\"w-4 h-4 text-yellow-400\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z\" />\n </svg>\n <span class=\"text-sm font-medium text-white\">4.8</span>\n </div>\n </div>\n\n <!-- Total Reviews -->\n <div class=\"flex items-center justify-between py-2 border-b border-slate-700/50\">\n <span class=\"text-xs text-slate-400\">{{ $t('garages.analytics.total_reviews') }}</span>\n <span class=\"text-sm font-medium text-white\">124</span>\n </div>\n\n <!-- Service Requests -->\n <div class=\"flex items-center justify-between py-2 border-b border-slate-700/50\">\n <span class=\"text-xs text-slate-400\">{{ $t('garages.analytics.service_requests') }}</span>\n <span class=\"text-sm font-medium text-white\">47</span>\n </div>\n\n <!-- Response Rate -->\n <div class=\"flex items-center justify-between py-2\">\n <span class=\"text-xs text-slate-400\">{{ $t('garages.analytics.response_rate') }}</span>\n <span class=\"text-sm font-medium text-emerald-400\">92%</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- ============================================================ -->\n <!-- STEP 5: Comprehensive Edit Modal with tabs -->\n <!-- ============================================================ -->\n <div\n v-if=\"showEditModal\"\n class=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n >\n <!-- Backdrop -->\n <div class=\"absolute inset-0 bg-black/60 backdrop-blur-sm\" @click=\"closeEditModal\"></div>\n\n <!-- Modal -->\n <div class=\"relative w-full max-w-2xl bg-slate-800 border border-slate-700 rounded-2xl shadow-2xl max-h-[90vh] overflow-hidden flex flex-col\">\n <!-- Header -->\n <div class=\"px-6 py-4 border-b border-slate-700 flex items-center justify-between flex-shrink-0\">\n <h3 class=\"text-lg font-semibold text-white\">{{ $t('garages.details.edit_details') }}</h3>\n <button @click=\"closeEditModal\" class=\"p-1.5 rounded-lg text-slate-400 hover:text-white hover:bg-slate-700 transition\">\n <svg class=\"w-5 h-5\" 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 </div>\n\n <!-- Tab Navigation -->\n <div class=\"px-6 pt-4 border-b border-slate-700 flex-shrink-0\">\n <nav class=\"flex gap-4\">\n <button\n v-for=\"tab in editModalTabs\"\n :key=\"tab.key\"\n @click=\"editModalTab = tab.key\"\n class=\"pb-3 text-sm font-medium transition border-b-2 -mb-px\"\n :class=\"editModalTab === tab.key\n ? 'text-indigo-400 border-indigo-400'\n : 'text-slate-400 border-transparent hover:text-slate-300'\"\n >\n {{ $t(tab.label) }}\n </button>\n </nav>\n </div>\n\n <!-- Scrollable Body -->\n <div class=\"flex-1 overflow-y-auto p-6 space-y-6\">\n <!-- Alapadatok Tab -->\n <div v-if=\"editModalTab === 'basic'\" class=\"space-y-5\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.company_name') }}</label>\n <input\n v-model=\"editForm.full_name\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.display_name') }}</label>\n <input\n v-model=\"editForm.display_name\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.tax_number') }}</label>\n <input\n v-model=\"editForm.tax_number\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.reg_number') }}</label>\n <input\n v-model=\"editForm.reg_number\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.zip') }}</label>\n <input\n v-model=\"editForm.address_zip\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.city') }}</label>\n <input\n v-model=\"editForm.address_city\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.street_name') }}</label>\n <input\n v-model=\"editForm.address_street_name\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.street_type') }}</label>\n <input\n v-model=\"editForm.address_street_type\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.house_number') }}</label>\n <input\n v-model=\"editForm.address_house_number\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n </div>\n </div>\n\n <!-- Contact Tab -->\n <div v-if=\"editModalTab === 'contact'\" class=\"space-y-5\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.contact_person') }}</label>\n <input\n v-model=\"editForm.contact_person_name\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.contact_email') }}</label>\n <input\n v-model=\"editForm.contact_email\"\n type=\"email\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.contact_phone') }}</label>\n <input\n v-model=\"editForm.contact_phone\"\n type=\"text\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n />\n </div>\n </div>\n </div>\n\n <!-- Addresses Tab -->\n <div v-if=\"editModalTab === 'addresses'\" class=\"space-y-8\">\n <!-- Billing Address -->\n <div>\n <h4 class=\"text-sm font-semibold text-white mb-3\">{{ $t('garages.details.billing_address') }}</h4>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.zip') }}</label>\n <input v-model=\"editForm.billing_zip\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.city') }}</label>\n <input v-model=\"editForm.billing_city\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.street_name') }}</label>\n <input v-model=\"editForm.billing_street_name\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.street_type') }}</label>\n <input v-model=\"editForm.billing_street_type\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n </div>\n <div class=\"mt-4\">\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.house_number') }}</label>\n <input v-model=\"editForm.billing_house_number\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n </div>\n\n <!-- Notification Address -->\n <div>\n <h4 class=\"text-sm font-semibold text-white mb-3\">{{ $t('garages.details.notification_address') }}</h4>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.zip') }}</label>\n <input v-model=\"editForm.notification_zip\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.city') }}</label>\n <input v-model=\"editForm.notification_city\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.street_name') }}</label>\n <input v-model=\"editForm.notification_street_name\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.street_type') }}</label>\n <input v-model=\"editForm.notification_street_type\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n </div>\n <div class=\"mt-4\">\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.details.house_number') }}</label>\n <input v-model=\"editForm.notification_house_number\" type=\"text\" class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\" />\n </div>\n </div>\n </div>\n </div>\n\n <!-- Footer -->\n <div class=\"px-6 py-4 border-t border-slate-700 flex items-center justify-end gap-3 flex-shrink-0\">\n <button @click=\"closeEditModal\" class=\"px-4 py-2 text-sm font-medium text-slate-300 hover:text-white bg-slate-700/50 hover:bg-slate-700 rounded-lg transition\">\n {{ $t('garages.details.cancel') }}\n </button>\n <button @click=\"saveEdit\" :disabled=\"saving\" class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-500 rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed\">\n <svg v-if=\"saving\" class=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n {{ saving ? $t('garages.details.saving') : $t('garages.details.save') }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- ============================================================ -->\n <!-- Add Employee Modal -->\n <!-- ============================================================ -->\n <div v-if=\"showAddEmployeeModal\" class=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div class=\"absolute inset-0 bg-black/60 backdrop-blur-sm\" @click=\"showAddEmployeeModal = false\"></div>\n <div class=\"relative w-full max-w-md bg-slate-800 border border-slate-700 rounded-2xl shadow-2xl p-6\">\n <h3 class=\"text-lg font-semibold text-white mb-4\">{{ $t('garages.employees.add_employee') }}</h3>\n <div class=\"space-y-4\">\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.employees.email') }}</label>\n <input\n v-model=\"newMemberEmail\"\n type=\"email\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 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\"\n :placeholder=\"$t('garages.employees.email_placeholder')\"\n />\n </div>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.employees.role') }}</label>\n <select\n v-model=\"newMemberRole\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500\"\n >\n <option value=\"member\">{{ $t('garages.roles.member') }}</option>\n <option value=\"manager\">{{ $t('garages.roles.manager') }}</option>\n <option value=\"admin\">{{ $t('garages.roles.admin') }}</option>\n </select>\n </div>\n </div>\n <div class=\"flex justify-end gap-3 mt-6\">\n <button @click=\"showAddEmployeeModal = false\" class=\"px-4 py-2 text-sm font-medium text-slate-300 hover:text-white bg-slate-700/50 hover:bg-slate-700 rounded-lg transition\">\n {{ $t('garages.employees.cancel') }}\n </button>\n <button @click=\"addEmployee\" :disabled=\"addingMember || !newMemberEmail\" class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-emerald-600 hover:bg-emerald-500 rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed\">\n <svg v-if=\"addingMember\" class=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n {{ addingMember ? $t('garages.employees.adding') : $t('garages.employees.add') }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- ============================================================ -->\n <!-- Edit Role Modal -->\n <!-- ============================================================ -->\n <div v-if=\"showEditRoleModal\" class=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div class=\"absolute inset-0 bg-black/60 backdrop-blur-sm\" @click=\"showEditRoleModal = false\"></div>\n <div class=\"relative w-full max-w-md bg-slate-800 border border-slate-700 rounded-2xl shadow-2xl p-6\">\n <h3 class=\"text-lg font-semibold text-white mb-4\">{{ $t('garages.employees.edit_role') }}</h3>\n <div>\n <label class=\"block text-xs font-medium text-slate-400 mb-1.5\">{{ $t('garages.employees.role') }}</label>\n <select\n v-model=\"editingRole\"\n class=\"w-full px-3 py-2 text-sm bg-slate-700/50 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500\"\n >\n <option value=\"member\">{{ $t('garages.roles.member') }}</option>\n <option value=\"manager\">{{ $t('garages.roles.manager') }}</option>\n <option value=\"admin\">{{ $t('garages.roles.admin') }}</option>\n </select>\n </div>\n <div class=\"flex justify-end gap-3 mt-6\">\n <button @click=\"showEditRoleModal = false\" class=\"px-4 py-2 text-sm font-medium text-slate-300 hover:text-white bg-slate-700/50 hover:bg-slate-700 rounded-lg transition\">\n {{ $t('garages.employees.cancel') }}\n </button>\n <button @click=\"saveRoleEdit\" :disabled=\"savingRole\" class=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-500 rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed\">\n <svg v-if=\"savingRole\" class=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n {{ savingRole ? $t('garages.employees.saving') : $t('garages.employees.save') }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- ============================================================ -->\n <!-- Remove Confirmation Modal -->\n <!-- ============================================================ -->\n <div v-if=\"showRemoveModal\" class=\"fixed inset-0 z-50 overflow-y-auto\" aria-labelledby=\"modal-title\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0\">\n <div class=\"fixed inset-0 bg-black/60 backdrop-blur-sm transition-opacity\" @click=\"showRemoveModal = false\"></div>\n <span class=\"hidden sm:inline-block sm:align-middle sm:h-screen\" aria-hidden=\"true\">​</span>\n <div class=\"inline-block align-bottom bg-slate-800 rounded-2xl px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl border border-slate-700 transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6\">\n <div class=\"sm:flex sm:items-start\">\n <div class=\"mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-500/20 sm:mx-0 sm:h-10 sm:w-10\">\n <svg class=\"h-6 w-6 text-red-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z\" />\n </svg>\n </div>\n <div class=\"mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left\">\n <h3 class=\"text-lg leading-6 font-medium text-white\">\n {{ $t('garages.employees.removeTitle') }}\n </h3>\n <div class=\"mt-2\">\n <p class=\"text-sm text-slate-400\">\n {{ $t('garages.employees.removeConfirm', { name: memberFullName(removingMember) }) }}\n </p>\n </div>\n </div>\n </div>\n <div class=\"mt-5 sm:mt-4 sm:flex sm:flex-row-reverse gap-2\">\n <button @click=\"executeRemove\" :disabled=\"removing\" type=\"button\" class=\"w-full inline-flex justify-center rounded-xl border border-transparent shadow-sm px-4 py-2.5 bg-red-600 text-base font-medium text-white hover:bg-red-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm disabled:opacity-50 disabled:cursor-not-allowed transition\">\n <svg v-if=\"removing\" class=\"w-4 h-4 animate-spin mr-2\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n {{ removing ? $t('garages.employees.removing') : $t('garages.employees.remove') }}\n </button>\n <button @click=\"showRemoveModal = false\" type=\"button\" class=\"mt-3 w-full inline-flex justify-center rounded-xl border border-slate-600 shadow-sm px-4 py-2.5 bg-slate-700/50 text-base font-medium text-slate-300 hover:bg-slate-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:w-auto sm:text-sm transition\">\n {{ $t('garages.employees.cancel') }}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Notification Toast (Dark Theme) -->\n <transition enter-active-class=\"transition ease-out duration-300\" enter-from-class=\"translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2\" enter-to-class=\"translate-y-0 opacity-100 sm:translate-x-0\" leave-active-class=\"transition ease-in duration-100\" leave-from-class=\"opacity-100\" leave-to-class=\"opacity-0\">\n <div v-if=\"notification.show\" class=\"fixed top-4 right-4 z-[100] max-w-sm w-full bg-slate-800 border border-slate-700 shadow-lg rounded-xl pointer-events-auto overflow-hidden\">\n <div class=\"p-4\">\n <div class=\"flex items-start\">\n <div class=\"flex-shrink-0\">\n <svg v-if=\"notification.type === 'success'\" class=\"h-6 w-6 text-green-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <svg v-if=\"notification.type === 'error'\" class=\"h-6 w-6 text-red-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\" />\n </svg>\n </div>\n <div class=\"ml-3 w-0 flex-1 pt-0.5\">\n <p class=\"text-sm font-medium text-white\">{{ notification.message }}</p>\n </div>\n <div class=\"ml-4 flex-shrink-0 flex\">\n <button @click=\"notification.show = false\" class=\"bg-slate-700/50 rounded-md inline-flex text-slate-400 hover:text-slate-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500\">\n <span class=\"sr-only\">Close</span>\n <svg class=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n </transition>\n </template>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useAuthStore } from '~/stores/auth'\n\nconst route = useRoute()\nconst router = useRouter()\nconst auth = useAuthStore()\n\nconst orgId = route.params.id as string\n\n// State\nconst loading = ref(true)\nconst error = ref<string | null>(null)\nconst garage = ref<any>(null)\nconst members = ref<any[]>([])\nconst activeTab = ref('general')\nconst fleetVehicles = ref<any[]>([])\nconst fleetLoading = ref(false)\n\n// Template refs for child components\nconst subscriptionTabRef = ref<InstanceType<typeof GaragesGarageSubscriptionTab> | null>(null)\n\n// Edit Modal\nconst showEditModal = ref(false)\nconst editModalTab = ref('basic')\nconst saving = ref(false)\nconst editForm = ref({\n full_name: '',\n name: '',\n display_name: '',\n email: '',\n phone: '',\n tax_number: '',\n reg_number: '',\n org_type: '',\n address_zip: '',\n address_city: '',\n address_street_name: '',\n address_street_type: '',\n address_house_number: '',\n contact_person_name: '',\n contact_email: '',\n contact_phone: '',\n billing_zip: '',\n billing_city: '',\n billing_street_name: '',\n billing_street_type: '',\n billing_house_number: '',\n notification_zip: '',\n notification_city: '',\n notification_street_name: '',\n notification_street_type: '',\n notification_house_number: '',\n})\n\n// Add Employee Modal\nconst showAddEmployeeModal = ref(false)\nconst newMemberEmail = ref('')\nconst newMemberRole = ref('member')\nconst addingMember = ref(false)\n\n// Edit Role Modal\nconst showEditRoleModal = ref(false)\nconst editingMember = ref<any>(null)\nconst editingRole = ref('member')\nconst savingRole = ref(false)\n\n// Remove Modal\nconst showRemoveModal = ref(false)\nconst removingMember = ref<any>(null)\nconst removing = ref(false)\n\n// Notification\nconst notification = ref({ show: false, type: 'success' as 'success' | 'error', message: '' })\n\n// Tab definitions\nconst tabs = [\n { key: 'general', label: 'garages.details.generalTab' },\n { key: 'employees', label: 'garages.details.employeesTab' },\n { key: 'fleet', label: 'garages.details.fleetTab' },\n { key: 'subscription', label: 'garages.details.subscriptionTab' },\n { key: 'analytics', label: 'garages.details.analyticsTab' },\n]\n\nconst editModalTabs = [\n { key: 'basic', label: 'garages.details.editBasicTab' },\n { key: 'contact', label: 'garages.details.editContactTab' },\n { key: 'addresses', label: 'garages.details.editAddressTab' },\n]\n\n// RBAC helper\nfunction hasOrgPermission(perm: string): boolean {\n if (auth.isAdmin) return true\n if (auth.user?.system_capabilities?.[perm]) return true\n if (auth.user?.org_capabilities?.[orgId]?.[perm]) return true\n return false\n}\n\n// Computed\nconst vehicleQuotaLimit = computed(() => {\n if (!garage.value?.subscription?.asset_limit) return 5\n return garage.value.subscription.asset_limit\n})\n\nconst vehicleQuotaPercent = computed(() => {\n const limit = vehicleQuotaLimit.value\n if (limit <= 0) return 0\n return Math.min(100, Math.round((fleetVehicles.value.length / limit) * 100))\n})\n\nconst branchQuotaPercent = computed(() => {\n const branches = garage.value?.branches?.length || 0\n const limit = garage.value?.subscription?.branch_limit\n if (!limit || limit <= 0) return 0\n return Math.min(100, Math.round((branches / limit) * 100))\n})\n\nconst employeeQuotaPercent = computed(() => {\n const count = garage.value?.member_count || 0\n const limit = garage.value?.subscription?.user_limit\n if (!limit || limit <= 0) return 0\n return Math.min(100, Math.round((count / limit) * 100))\n})\n\nconst missingFields = computed(() => {\n if (!garage.value) return []\n const missing: { key: string; label: string }[] = []\n const g = garage.value\n const isIndividual = g.org_type === 'individual'\n\n if (!isIndividual) {\n if (!g.tax_number) missing.push({ key: 'tax_number', label: 'garages.details.missing_tax_number' })\n }\n\n if (!g.contact_email && !g.email) missing.push({ key: 'contact_email', label: 'garages.details.missing_contact_email' })\n if (!g.contact_phone && !g.phone) missing.push({ key: 'contact_phone', label: 'garages.details.missing_contact_phone' })\n\n if (!isIndividual) {\n if (!g.billing_city || !g.billing_zip) missing.push({ key: 'billing', label: 'garages.details.missing_billing' })\n }\n\n return missing\n})\n\n// API calls\nasync function fetchDetails() {\n loading.value = true\n error.value = null\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n }\n\n const res = await fetch(`/api/v1/admin/organizations/${orgId}/details`, { headers })\n\n if (!res.ok) throw new Error(`Failed to fetch organization: ${res.status}`)\n\n const data = await res.json()\n garage.value = data\n members.value = data.members || []\n } catch (e: any) {\n error.value = e.message || 'Failed to load garage details'\n } finally {\n loading.value = false\n }\n}\n\nasync function fetchFleetVehicles() {\n fleetLoading.value = true\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n const res = await fetch(`/api/v1/admin/organizations/${orgId}/vehicles`, {\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n })\n if (!res.ok) throw new Error(`Failed to fetch fleet: ${res.status}`)\n const data = await res.json()\n fleetVehicles.value = data.vehicles || []\n } catch (e: any) {\n console.error('Fleet fetch error:', e)\n fleetVehicles.value = []\n } finally {\n fleetLoading.value = false\n }\n}\n\n// Edit Modal\nfunction openEditModal() {\n if (!garage.value) return\n editForm.value = {\n full_name: garage.value.full_name || '',\n name: garage.value.name || '',\n display_name: garage.value.display_name || '',\n email: garage.value.email || '',\n phone: garage.value.phone || '',\n tax_number: garage.value.tax_number || '',\n reg_number: garage.value.reg_number || '',\n org_type: garage.value.org_type || '',\n address_zip: garage.value.address_zip || '',\n address_city: garage.value.address_city || '',\n address_street_name: garage.value.address_street_name || '',\n address_street_type: garage.value.address_street_type || '',\n address_house_number: garage.value.address_house_number || '',\n contact_person_name: garage.value.contact_person_name || '',\n contact_email: garage.value.contact_email || '',\n contact_phone: garage.value.contact_phone || '',\n billing_zip: garage.value.billing_zip || '',\n billing_city: garage.value.billing_city || '',\n billing_street_name: garage.value.billing_street_name || '',\n billing_street_type: garage.value.billing_street_type || '',\n billing_house_number: garage.value.billing_house_number || '',\n notification_zip: garage.value.notification_zip || '',\n notification_city: garage.value.notification_city || '',\n notification_street_name: garage.value.notification_street_name || '',\n notification_street_type: garage.value.notification_street_type || '',\n notification_house_number: garage.value.notification_house_number || '',\n }\n editModalTab.value = 'basic'\n showEditModal.value = true\n}\n\nfunction closeEditModal() {\n showEditModal.value = false\n}\n\nasync function saveEdit() {\n saving.value = true\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n\n const payload: Record<string, any> = {}\n for (const [key, value] of Object.entries(editForm.value)) {\n if (value !== '' && value !== null && value !== undefined) {\n payload[key] = value\n }\n }\n\n if (garage.value?.org_type === 'individual') {\n if (payload.contact_email && !payload.email) payload.email = payload.contact_email\n if (payload.contact_phone && !payload.phone) payload.phone = payload.contact_phone\n }\n\n const res = await fetch(`/api/v1/admin/organizations/${orgId}`, {\n method: 'PUT',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n })\n if (!res.ok) throw new Error(`Save failed: ${res.status}`)\n const result = await res.json()\n if (result.organization) {\n garage.value = { ...garage.value, ...result.organization }\n } else {\n garage.value = { ...garage.value, ...result }\n }\n closeEditModal()\n showNotification('success', 'Garage updated successfully')\n await fetchDetails()\n } catch (e: any) {\n showNotification('error', e.message || 'Failed to save')\n } finally {\n saving.value = false\n }\n}\n\n// Employee actions\nasync function addEmployee() {\n if (!newMemberEmail.value) return\n addingMember.value = true\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n const res = await fetch(`/api/v1/admin/organizations/${orgId}/members`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: newMemberEmail.value,\n role: newMemberRole.value,\n }),\n })\n if (!res.ok) {\n const errData = await res.json().catch(() => ({}))\n throw new Error(errData.detail || `Add member failed: ${res.status}`)\n }\n showAddEmployeeModal.value = false\n newMemberEmail.value = ''\n newMemberRole.value = 'member'\n showNotification('success', 'Member added successfully')\n await fetchDetails()\n } catch (e: any) {\n showNotification('error', e.message || 'Failed to add member')\n } finally {\n addingMember.value = false\n }\n}\n\nfunction openEditRole(member: any) {\n editingMember.value = member\n editingRole.value = member.role || 'member'\n showEditRoleModal.value = true\n}\n\nasync function saveRoleEdit() {\n if (!editingMember.value) return\n savingRole.value = true\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n const res = await fetch(`/api/v1/admin/organizations/${orgId}/members/${editingMember.value.id}`, {\n method: 'PUT',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ role: editingRole.value }),\n })\n if (!res.ok) throw new Error(`Update role failed: ${res.status}`)\n showEditRoleModal.value = false\n editingMember.value = null\n showNotification('success', 'Role updated successfully')\n await fetchDetails()\n } catch (e: any) {\n showNotification('error', e.message || 'Failed to update role')\n } finally {\n savingRole.value = false\n }\n}\n\nfunction confirmRemoveMember(member: any) {\n removingMember.value = member\n showRemoveModal.value = true\n}\n\nasync function executeRemove() {\n if (!removingMember.value) return\n removing.value = true\n try {\n const tokenCookie = useCookie('access_token')\n const token = (tokenCookie.value || auth.token || '').trim()\n const res = await fetch(`/api/v1/admin/organizations/${orgId}/members/${removingMember.value.id}`, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${token}`,\n },\n })\n if (!res.ok) throw new Error(`Remove failed: ${res.status}`)\n showRemoveModal.value = false\n removingMember.value = null\n showNotification('success', 'Member removed successfully')\n await fetchDetails()\n } catch (e: any) {\n showNotification('error', e.message || 'Failed to remove member')\n } finally {\n removing.value = false\n }\n}\n\n// Notification helper\nfunction showNotification(type: 'success' | 'error', message: string) {\n notification.value = { show: true, type, message }\n setTimeout(() => {\n notification.value.show = false\n }, 4000)\n}\n\n// Navigation\nfunction goBack() {\n router.push('/garages')\n}\n\n// Helpers\nconst cleanGarageName = computed(() => {\n if (!garage.value) return ''\n const raw = garage.value.display_name || garage.value.name || garage.value.full_name || ''\n return raw.replace(/[\\s-]*#\\d+\\s*$/g, '').trim() || 'Garage #' + garage.value.id\n})\n\nfunction garageDisplayName() {\n if (!garage.value) return ''\n return garage.value.name || garage.value.email || garage.value.full_name || 'Garage #' + garage.value.id\n}\n\nfunction getInitials(name: string): string {\n if (!name) return '?'\n return name.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2)\n}\n\nfunction getInitialsColor(name: string): string {\n const colors = [\n 'bg-red-500', 'bg-yellow-500', 'bg-green-500', 'bg-blue-500',\n 'bg-indigo-500', 'bg-purple-500', 'bg-pink-500', 'bg-teal-500',\n ]\n let hash = 0\n for (let i = 0; i < (name || '').length; i++) {\n hash = name.charCodeAt(i) + ((hash << 5) - hash)\n }\n return colors[Math.abs(hash) % colors.length]\n}\n\nfunction statusLabel(status: string): string {\n const map: Record<string, string> = {\n active: 'Active',\n inactive: 'Inactive',\n suspended: 'Suspended',\n pending: 'Pending',\n }\n return map[status?.toLowerCase()] || status\n}\n\nfunction statusBadgeClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-100 text-green-800',\n inactive: 'bg-gray-100 text-gray-800',\n suspended: 'bg-red-100 text-red-800',\n pending: 'bg-yellow-100 text-yellow-800',\n }\n return map[status?.toLowerCase()] || 'bg-gray-100 text-gray-800'\n}\n\nfunction statusDotClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-400',\n inactive: 'bg-gray-400',\n suspended: 'bg-red-400',\n pending: 'bg-yellow-400',\n }\n return map[status?.toLowerCase()] || 'bg-gray-400'\n}\n\nfunction memberFullName(member: any): string {\n if (!member) return ''\n if (member.display_name) return member.display_name\n if (member.name) return member.name\n if (member.email) return member.email\n if (member.person) {\n const first = member.person.first_name || ''\n const last = member.person.last_name || ''\n const full = `${last} ${first}`.trim()\n if (full) return full\n if (member.person.email) return member.person.email\n }\n if (member.user_id) return String(member.user_id)\n return 'Unknown'\n}\n\nfunction roleLabel(role: string): string {\n const map: Record<string, string> = {\n admin: 'Admin',\n manager: 'Manager',\n member: 'Member',\n owner: 'Owner',\n }\n return map[role?.toLowerCase()] || role || 'Member'\n}\n\nfunction roleBadgeClass(role: string): string {\n const map: Record<string, string> = {\n admin: 'bg-purple-100 text-purple-800',\n manager: 'bg-blue-100 text-blue-800',\n member: 'bg-green-100 text-green-800',\n owner: 'bg-yellow-100 text-yellow-800',\n }\n return map[role?.toLowerCase()] || 'bg-gray-100 text-gray-800'\n}\n\nfunction memberStatusLabel(status: string): string {\n const map: Record<string, string> = {\n active: 'Active',\n invited: 'Invited',\n suspended: 'Suspended',\n inactive: 'Inactive',\n }\n return map[status?.toLowerCase()] || status || 'Unknown'\n}\n\nfunction memberStatusBadgeClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-100 text-green-800',\n invited: 'bg-blue-100 text-blue-800',\n suspended: 'bg-red-100 text-red-800',\n inactive: 'bg-gray-100 text-gray-800',\n }\n return map[status?.toLowerCase()] || 'bg-gray-100 text-gray-800'\n}\n\nfunction memberStatusDotClass(status: string): string {\n const map: Record<string, string> = {\n active: 'bg-green-400',\n invited: 'bg-blue-400',\n suspended: 'bg-red-400',\n inactive: 'bg-gray-400',\n }\n return map[status?.toLowerCase()] || 'bg-gray-400'\n}\n\n// Lifecycle\nonMounted(() => {\n fetchDetails()\n})\n\n// Watch activeTab to trigger data fetching\nwatch(activeTab, (newTab) => {\n // Fetch fleet data for fleet tab, analytics tab, or subscription tab (for utilization stats)\n if (newTab === 'fleet' || newTab === 'analytics' || newTab === 'subscription') {\n if (fleetVehicles.value.length === 0) {\n fetchFleetVehicles()\n }\n }\n // Trigger child component data fetching via template refs\n if (newTab === 'subscription') {\n subscriptionTabRef.value?.fetchTiers()\n }\n})\n</script>\n"],"version":3} |