admin felület bekötése. pontosítások2
This commit is contained in:
114
.roo/history.md
114
.roo/history.md
@@ -709,3 +709,117 @@ A frontend által hívott `GET /api/v1/admin/organizations/43/vehicles` végpont
|
|||||||
### ✅ Verifikáció
|
### ✅ Verifikáció
|
||||||
- `GET /api/v1/admin/organizations/43/vehicles` → **200 OK**
|
- `GET /api/v1/admin/organizations/43/vehicles` → **200 OK**
|
||||||
- Visszaadott 3 jármű helyes adatokkal (brand, model, year, license_plate, branch_name)
|
- Visszaadott 3 jármű helyes adatokkal (brand, model, year, license_plate, branch_name)
|
||||||
|
|
||||||
|
## 2026-06-26 - P0 HOTFIX: Corporate 500 Error & Shrinking Filter Paradox
|
||||||
|
|
||||||
|
### 🎯 Cél
|
||||||
|
Két kritikus bug javítása: (1) `org_type_filter=corporate` 500-as hibát dobott a backendben, mert a "corporate" nem létező érték a `fleet.orgtype` PostgreSQL enum-ban. (2) A frontend előfizetési csomag legördülő menüje összezsugorodott szűréskor, mert a `uniqueTiers` computed property a szűrt `garages` tömbből számolt.
|
||||||
|
|
||||||
|
### 🔧 Változtatások
|
||||||
|
|
||||||
|
**Backend** (`backend/app/api/v1/endpoints/admin_organizations.py:219`):
|
||||||
|
- `org_type_filter=corporate` esetén a backend most az összes nem-individual `OrgType` értékre szűr (`business`, `fleet_owner`, `service`, `service_provider`, `club`)
|
||||||
|
- A `OrgType` enum dinamikus lekérdezése biztosítja, hogy új típus hozzáadásakor is működjön
|
||||||
|
|
||||||
|
**Frontend** (`frontend_admin/pages/garages/index.vue`):
|
||||||
|
- `uniqueTiers` computed property eltávolítva
|
||||||
|
- Helyette `availableTierNames` ref + watcher, ami csak bővül, sosem zsugorodik
|
||||||
|
- `watch(garages, ...)` `immediate: true, deep: true` paraméterekkel
|
||||||
|
|
||||||
|
### ✅ Verifikáció
|
||||||
|
- `GET /api/v1/admin/organizations?org_type_filter=corporate` → **200 OK**, 8 garázs (business, fleet_owner, service_provider)
|
||||||
|
- `GET /api/v1/admin/organizations?org_type_filter=individual` → **200 OK**, 17 garázs (individual)
|
||||||
|
- Admin frontend újraindítva, build hiba nélkül
|
||||||
|
|
||||||
|
## 2026-06-26 - P0 UX/UI Polish: Subscription Tab, History & Header ID Fix
|
||||||
|
|
||||||
|
### 🎯 Cél
|
||||||
|
Admin garázs részletek oldal UX/UI javítása: Header ID bug fix, kattintható garázsnevek listában, Subscription card sűrítése utilization statokkal, Subscription History szekció hozzáadása.
|
||||||
|
|
||||||
|
### 🔧 Módosított fájlok
|
||||||
|
|
||||||
|
**Frontend** (`frontend_admin/pages/garages/[id]/index.vue`):
|
||||||
|
- **Header ID Fix**: Eltávolítva a duplikált `#{{ garage.id }}` a subtitle-ből. `garageDisplayName()` fallback javítva: `'Garage #' + garage.value.id` formátumra.
|
||||||
|
- **Subscription Card Densification**: 4-oszlopos grid layout utilization statokkal (Járművek, Telephelyek, Dolgozók) progress bar-okkal, színkódolt threshold-okkal (piros ≥90%, borostyán ≥70%).
|
||||||
|
- **Subscription History Section**: Új kártya adat táblával és üres állapottal (clock SVG ikon + "Még nincsenek előfizetési előzmények" üzenet).
|
||||||
|
- **Új computed properties**: `employeeQuotaLimit`, `branchQuotaPercent`, `employeeQuotaPercent`.
|
||||||
|
|
||||||
|
**Frontend** (`frontend_admin/pages/garages/index.vue`):
|
||||||
|
- **Kattintható garázsnevek**: A garázs név `<NuxtLink>`-be csomagolva, hover stylinggal (`hover:underline cursor-pointer hover:text-indigo-400`).
|
||||||
|
|
||||||
|
**Frontend i18n** (`frontend_admin/i18n/locales/en.json`, `frontend_admin/i18n/locales/hu.json`):
|
||||||
|
- 10 új i18n kulcs hozzáadva: `vehicles_used`, `branches_used`, `employees_used`, `status`, `subscription_history`, `history_date`, `history_package`, `history_action`, `history_status`, `no_subscription_history`.
|
||||||
|
|
||||||
|
### ✅ Verifikáció
|
||||||
|
- `docker compose exec sf_public_frontend npm run build` → **✓ built in 7.13s**, hiba nélkül
|
||||||
|
|
||||||
|
## 2026-06-26 - Admin Garage System Identifiers Bugfix
|
||||||
|
|
||||||
|
### 🎯 Cél
|
||||||
|
Admin garázs részletek oldalon a "Rendszer Azonosítók" szekcióban a User ID és Person ID mezők "N/A"-t mutattak, mert a backend `GarageDetailsResponse` nem tartalmazott `owner_user_id` mezőt, a frontend pedig egy nem létező `garage.owner?.id` property-t próbált olvasni.
|
||||||
|
|
||||||
|
### 🔧 Változtatások
|
||||||
|
|
||||||
|
**Backend** (`backend/app/api/v1/endpoints/admin_organizations.py`):
|
||||||
|
- `GarageDetailsResponse` osztályhoz hozzáadva: `owner_user_id: Optional[int] = None` (169. sor)
|
||||||
|
- Visszatérési értékhez hozzáadva: `owner_user_id=owner.id if owner else None` (650. sor)
|
||||||
|
|
||||||
|
**Frontend** (`frontend_admin/pages/garages/[id]/index.vue`):
|
||||||
|
- 200. sor: `garage.owner?.id || 'N/A'` → `garage.owner_user_id ?? 'N/A'`
|
||||||
|
|
||||||
|
### ✅ Verifikáció
|
||||||
|
- `GET /api/v1/admin/organizations/43/details` → `owner_user_id: 79`, `owner_person_id: 86` (korábban hiányzott)
|
||||||
|
|
||||||
|
## 2026-06-26 — Bug Analysis: Admin Garage Subscription Tab Shows Wrong Package Data
|
||||||
|
|
||||||
|
**Gitea Issue:** #301
|
||||||
|
**Scope:** Backend + Frontend
|
||||||
|
**Type:** Bug
|
||||||
|
|
||||||
|
### What was found
|
||||||
|
Investigated why the admin frontend's garage detail page subscription tab doesn't display data matching the selected package.
|
||||||
|
|
||||||
|
**Root Causes:**
|
||||||
|
1. `SubscriptionSummary` Pydantic model (admin_organizations.py:116-124) missing `branch_limit` field — frontend (index.vue:526) accesses `garage.subscription?.branch_limit` which is always undefined, showing `∞`
|
||||||
|
2. `asset_limit` extraction fragile (admin_organizations.py:462-465): `or` logic treats `0` as falsy, falls back to `1` on missing/alternate keys
|
||||||
|
3. `GarageDetailsResponse` has no `branches` field — `garage.branches?.length` always 0
|
||||||
|
4. `asset_count` hardcoded to 0 (admin_organizations.py:473)
|
||||||
|
5. `OrganizationSubscription` query (admin_organizations.py:414-425) doesn't check `valid_until >= now()` — expired subs appear active
|
||||||
|
6. Fallback path (admin_organizations.py:476-488) incomplete — missing `valid_from` and `is_active`
|
||||||
|
|
||||||
|
### Fix created
|
||||||
|
Detailed fix spec written to `docs/admin_garage_subscription_tab_bugfix_spec.md`
|
||||||
|
|
||||||
|
## 2026-06-26 — P0 CORE LOGIC & ADD-ON UPGRADE — Execute Bugfix #301 & Extra Allowances
|
||||||
|
|
||||||
|
**Gitea Issue:** #301 (Bugfix) + P0 Add-on Upgrade
|
||||||
|
**Scope:** Backend + Frontend
|
||||||
|
**Type:** Bug + Feature
|
||||||
|
|
||||||
|
### 🔧 Módosított fájlok
|
||||||
|
- [`backend/app/api/v1/endpoints/admin_organizations.py`](backend/app/api/v1/endpoints/admin_organizations.py:47) — Backend API changes
|
||||||
|
- `OrgSubscriptionUpdate`: Added `extra_vehicles`, `extra_branches`, `extra_users` fields (lines 56-67)
|
||||||
|
- `SubscriptionSummary`: Added `branch_limit`, `user_limit`, `extra_allowances` fields (lines 138-142)
|
||||||
|
- `BranchBrief`: New Pydantic model for branch data (lines 145-150)
|
||||||
|
- `GarageDetailsResponse`: Added `branches: List[BranchBrief]` field (line 202)
|
||||||
|
- `get_organization_details` (line 404):
|
||||||
|
- Added `valid_until >= now` check to subscription query (line 449)
|
||||||
|
- Added real `asset_count` query from Vehicle table (lines 458-464)
|
||||||
|
- Added branches query from Branch table (lines 467-482)
|
||||||
|
- **Bugfix**: Replaced `or` operator with explicit `dict.get()` for limit calculations (lines 524-537)
|
||||||
|
- **Add-on math**: Base (from tier rules) + Extra (from extra_allowances JSONB) = Total limit
|
||||||
|
- `update_org_subscription` (line 983):
|
||||||
|
- Constructs `extra_allowances` JSONB from payload fields (lines 1044-1051)
|
||||||
|
- Passes to new `OrganizationSubscription` (line 1060)
|
||||||
|
- Returns `extra_allowances` in response (line 1090)
|
||||||
|
- [`frontend_admin/pages/garages/[id]/index.vue`](frontend_admin/pages/garages/[id]/index.vue:1463) — Frontend UI changes
|
||||||
|
- Added `extraVehicles`, `extraBranches`, `extraUsers` reactive state (lines 1463-1466)
|
||||||
|
- Added `employeeQuotaPercent` computed property (lines 1510-1515)
|
||||||
|
- Updated Employees tab: utilization bar with `user_limit` (line 544-547)
|
||||||
|
- Added add-on input cards: Extra Jármű, Extra Telephely, Extra Dolgozó (template section ~lines 611-685)
|
||||||
|
- Updated `updateSubscription`: sends extra_allowances payload (lines 1858-1861)
|
||||||
|
|
||||||
|
### ✅ Verifikáció
|
||||||
|
- `sync_engine.py`: 1278 elements OK — system perfectly in sync
|
||||||
|
- `test_subscription_feature_flags.py`: All 6 steps passed (login, feature flags, check, public tiers)
|
||||||
|
- Python syntax check: ✅ Syntax OK
|
||||||
|
|||||||
@@ -52,6 +52,19 @@ class OrgSubscriptionUpdate(BaseModel):
|
|||||||
description="Egyedi lejárati dátum (pl. 2-5 éves B2B deal esetén). "
|
description="Egyedi lejárati dátum (pl. 2-5 éves B2B deal esetén). "
|
||||||
"Ha None, a csomag duration.days alapján számolódik."
|
"Ha None, a csomag duration.days alapján számolódik."
|
||||||
)
|
)
|
||||||
|
# ── P0 ADD-ON UPGRADE: Extra allowances (add-ons) ──
|
||||||
|
extra_vehicles: int = Field(
|
||||||
|
default=0, ge=0,
|
||||||
|
description="Extra jármű kvóta a csomag keretein felül (add-on)."
|
||||||
|
)
|
||||||
|
extra_branches: int = Field(
|
||||||
|
default=0, ge=0,
|
||||||
|
description="Extra telephely kvóta a csomag keretein felül (add-on)."
|
||||||
|
)
|
||||||
|
extra_users: int = Field(
|
||||||
|
default=0, ge=0,
|
||||||
|
description="Extra dolgozó kvóta a csomag keretein felül (add-on)."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OrgSubscriptionResponse(BaseModel):
|
class OrgSubscriptionResponse(BaseModel):
|
||||||
@@ -122,6 +135,19 @@ class SubscriptionSummary(BaseModel):
|
|||||||
is_active: bool = True
|
is_active: bool = True
|
||||||
asset_count: int = 0
|
asset_count: int = 0
|
||||||
asset_limit: int = 1
|
asset_limit: int = 1
|
||||||
|
# ── P0 ADD-ON UPGRADE: Branch & User limits ──
|
||||||
|
branch_limit: int = 0
|
||||||
|
user_limit: int = 0
|
||||||
|
# ── P0 ADD-ON UPGRADE: Extra allowances (add-ons) ──
|
||||||
|
extra_allowances: dict = {}
|
||||||
|
|
||||||
|
|
||||||
|
class BranchBrief(BaseModel):
|
||||||
|
"""Rövid telephely adatok a frontend számára."""
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
city: Optional[str] = None
|
||||||
|
is_active: bool = True
|
||||||
|
|
||||||
|
|
||||||
class GarageDetailsResponse(BaseModel):
|
class GarageDetailsResponse(BaseModel):
|
||||||
@@ -166,8 +192,14 @@ class GarageDetailsResponse(BaseModel):
|
|||||||
# Meta
|
# Meta
|
||||||
created_at: Optional[str] = None
|
created_at: Optional[str] = None
|
||||||
member_count: int = 0
|
member_count: int = 0
|
||||||
|
# P0: Owner user ID for frontend display
|
||||||
|
owner_user_id: Optional[int] = None
|
||||||
|
# P0: Owner person ID for frontend display
|
||||||
|
owner_person_id: Optional[int] = None
|
||||||
# P0: Full member list with nested person data
|
# P0: Full member list with nested person data
|
||||||
members: List[OrganizationMemberResponse] = []
|
members: List[OrganizationMemberResponse] = []
|
||||||
|
# ── P0 ADD-ON UPGRADE: Branches list for utilization display ──
|
||||||
|
branches: List[BranchBrief] = []
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -217,6 +249,17 @@ async def list_organizations(
|
|||||||
if status_filter:
|
if status_filter:
|
||||||
base_query = base_query.where(Organization.status == status_filter)
|
base_query = base_query.where(Organization.status == status_filter)
|
||||||
if org_type_filter:
|
if org_type_filter:
|
||||||
|
if org_type_filter == "corporate":
|
||||||
|
# P0 HOTFIX: "corporate" is a UI category, not a DB enum value.
|
||||||
|
# The DB enum (fleet.orgtype) has: individual, business, fleet_owner,
|
||||||
|
# service, service_provider, club. "corporate" means all non-individual types.
|
||||||
|
from app.models.marketplace.organization import OrgType
|
||||||
|
corporate_types = [
|
||||||
|
t.value for t in OrgType
|
||||||
|
if t.value != OrgType.individual.value
|
||||||
|
]
|
||||||
|
base_query = base_query.where(Organization.org_type.in_(corporate_types))
|
||||||
|
else:
|
||||||
base_query = base_query.where(Organization.org_type == org_type_filter)
|
base_query = base_query.where(Organization.org_type == org_type_filter)
|
||||||
if tier_name_filter:
|
if tier_name_filter:
|
||||||
from app.models.core_logic import SubscriptionTier
|
from app.models.core_logic import SubscriptionTier
|
||||||
@@ -395,13 +438,15 @@ async def get_organization_details(
|
|||||||
detail=f"Szervezet nem található ID-vel: {org_id}",
|
detail=f"Szervezet nem található ID-vel: {org_id}",
|
||||||
)
|
)
|
||||||
|
|
||||||
# 2. Aktív előfizetés lekérése
|
# 2. Aktív előfizetés lekérése (P0 ADD-ON: valid_until >= now() check)
|
||||||
|
now = datetime.utcnow()
|
||||||
sub_stmt = (
|
sub_stmt = (
|
||||||
select(OrganizationSubscription)
|
select(OrganizationSubscription)
|
||||||
.options(selectinload(OrganizationSubscription.tier))
|
.options(selectinload(OrganizationSubscription.tier))
|
||||||
.where(
|
.where(
|
||||||
OrganizationSubscription.org_id == org_id,
|
OrganizationSubscription.org_id == org_id,
|
||||||
OrganizationSubscription.is_active == True,
|
OrganizationSubscription.is_active == True,
|
||||||
|
OrganizationSubscription.valid_until >= now,
|
||||||
)
|
)
|
||||||
.order_by(OrganizationSubscription.id.desc())
|
.order_by(OrganizationSubscription.id.desc())
|
||||||
.limit(1)
|
.limit(1)
|
||||||
@@ -409,6 +454,33 @@ async def get_organization_details(
|
|||||||
sub_result = await db.execute(sub_stmt)
|
sub_result = await db.execute(sub_stmt)
|
||||||
active_sub = sub_result.scalar_one_or_none()
|
active_sub = sub_result.scalar_one_or_none()
|
||||||
|
|
||||||
|
# 2b. P0 ADD-ON: Valós járműszám lekérése a fleet táblából
|
||||||
|
from app.models.fleet.vehicle import Vehicle # noqa: E402
|
||||||
|
vehicle_count_stmt = select(func.count(Vehicle.id)).where(
|
||||||
|
Vehicle.organization_id == org_id,
|
||||||
|
Vehicle.is_deleted == False,
|
||||||
|
)
|
||||||
|
vehicle_count_result = await db.execute(vehicle_count_stmt)
|
||||||
|
asset_count = vehicle_count_result.scalar() or 0
|
||||||
|
|
||||||
|
# 2c. P0 ADD-ON: Telephelyek (branches) lekérése
|
||||||
|
from app.models.fleet.organization import Branch # noqa: E402
|
||||||
|
branches_stmt = select(Branch).where(
|
||||||
|
Branch.organization_id == org_id,
|
||||||
|
Branch.is_deleted == False,
|
||||||
|
).order_by(Branch.name)
|
||||||
|
branches_result = await db.execute(branches_stmt)
|
||||||
|
branch_rows = branches_result.scalars().all()
|
||||||
|
branches_list = [
|
||||||
|
BranchBrief(
|
||||||
|
id=b.id,
|
||||||
|
name=b.name,
|
||||||
|
city=b.city,
|
||||||
|
is_active=b.is_active,
|
||||||
|
)
|
||||||
|
for b in branch_rows
|
||||||
|
]
|
||||||
|
|
||||||
# 3. Tagok lekérése eager loading-gal (User + Person)
|
# 3. Tagok lekérése eager loading-gal (User + Person)
|
||||||
members_stmt = (
|
members_stmt = (
|
||||||
select(OrganizationMember)
|
select(OrganizationMember)
|
||||||
@@ -440,36 +512,59 @@ async def get_organization_details(
|
|||||||
contact_result = await db.execute(contact_stmt)
|
contact_result = await db.execute(contact_stmt)
|
||||||
contact = contact_result.scalar_one_or_none()
|
contact = contact_result.scalar_one_or_none()
|
||||||
|
|
||||||
# 5. Subscription összefoglaló
|
# 5. Subscription összefoglaló — P0 ADD-ON UPGRADE
|
||||||
|
# Fix: explicit dict.get() instead of `or` (bugfix: 0 is falsy in Python)
|
||||||
|
# Add: extra_allowances math (Base + Extra)
|
||||||
subscription_summary = None
|
subscription_summary = None
|
||||||
if active_sub and active_sub.tier:
|
if active_sub and active_sub.tier:
|
||||||
rules = active_sub.tier.rules or {}
|
rules = active_sub.tier.rules or {}
|
||||||
asset_limit = (
|
fc = active_sub.tier.feature_capabilities or {}
|
||||||
rules.get("max_vehicles")
|
extra = active_sub.extra_allowances or {}
|
||||||
or active_sub.tier.feature_capabilities.get("max_vehicles")
|
|
||||||
or 1
|
# Base limits from tier rules (with explicit .get() — no `or` bug)
|
||||||
)
|
base_vehicles = rules.get("max_vehicles", fc.get("max_vehicles", 1))
|
||||||
|
base_branches = rules.get("max_branches", fc.get("max_branches", 0))
|
||||||
|
base_users = rules.get("max_users", fc.get("max_users", 0))
|
||||||
|
|
||||||
|
# Extra allowances (add-ons)
|
||||||
|
extra_vehicles = extra.get("extra_vehicles", 0) or 0
|
||||||
|
extra_branches = extra.get("extra_branches", 0) or 0
|
||||||
|
extra_users = extra.get("extra_users", 0) or 0
|
||||||
|
|
||||||
|
# Total = Base + Extra
|
||||||
|
asset_limit = base_vehicles + extra_vehicles
|
||||||
|
branch_limit = base_branches + extra_branches
|
||||||
|
user_limit = base_users + extra_users
|
||||||
|
|
||||||
subscription_summary = SubscriptionSummary(
|
subscription_summary = SubscriptionSummary(
|
||||||
tier_name=active_sub.tier.name,
|
tier_name=active_sub.tier.name,
|
||||||
tier_level=active_sub.tier.tier_level,
|
tier_level=active_sub.tier.tier_level,
|
||||||
valid_from=active_sub.valid_from.isoformat() if active_sub.valid_from else None,
|
valid_from=active_sub.valid_from.isoformat() if active_sub.valid_from else None,
|
||||||
expires_at=active_sub.valid_until.isoformat() if active_sub.valid_until else None,
|
expires_at=active_sub.valid_until.isoformat() if active_sub.valid_until else None,
|
||||||
is_active=active_sub.is_active,
|
is_active=active_sub.is_active,
|
||||||
asset_count=0,
|
asset_count=asset_count,
|
||||||
asset_limit=asset_limit,
|
asset_limit=asset_limit,
|
||||||
|
branch_limit=branch_limit,
|
||||||
|
user_limit=user_limit,
|
||||||
|
extra_allowances=extra,
|
||||||
)
|
)
|
||||||
elif org.subscription_tier:
|
elif org.subscription_tier:
|
||||||
rules = org.subscription_tier.rules or {}
|
rules = org.subscription_tier.rules or {}
|
||||||
asset_limit = (
|
fc = org.subscription_tier.feature_capabilities or {}
|
||||||
rules.get("max_vehicles")
|
extra = {}
|
||||||
or org.subscription_tier.feature_capabilities.get("max_vehicles")
|
|
||||||
or 1
|
base_vehicles = rules.get("max_vehicles", fc.get("max_vehicles", 1))
|
||||||
)
|
base_branches = rules.get("max_branches", fc.get("max_branches", 0))
|
||||||
|
base_users = rules.get("max_users", fc.get("max_users", 0))
|
||||||
|
|
||||||
subscription_summary = SubscriptionSummary(
|
subscription_summary = SubscriptionSummary(
|
||||||
tier_name=org.subscription_tier.name,
|
tier_name=org.subscription_tier.name,
|
||||||
tier_level=org.subscription_tier.tier_level,
|
tier_level=org.subscription_tier.tier_level,
|
||||||
expires_at=org.subscription_expires_at.isoformat() if org.subscription_expires_at else None,
|
expires_at=org.subscription_expires_at.isoformat() if org.subscription_expires_at else None,
|
||||||
asset_limit=asset_limit,
|
asset_count=asset_count,
|
||||||
|
asset_limit=base_vehicles,
|
||||||
|
branch_limit=base_branches,
|
||||||
|
user_limit=base_users,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 6. Kapcsolattartó adatok
|
# 6. Kapcsolattartó adatok
|
||||||
@@ -524,6 +619,7 @@ async def get_organization_details(
|
|||||||
# Get email from the user record
|
# Get email from the user record
|
||||||
email = m.user.email if m.user else None
|
email = m.user.email if m.user else None
|
||||||
person_data = PersonBrief(
|
person_data = PersonBrief(
|
||||||
|
id=person_obj.id,
|
||||||
first_name=person_obj.first_name or "",
|
first_name=person_obj.first_name or "",
|
||||||
last_name=person_obj.last_name or "",
|
last_name=person_obj.last_name or "",
|
||||||
email=email,
|
email=email,
|
||||||
@@ -554,6 +650,7 @@ async def get_organization_details(
|
|||||||
# we still provide an empty PersonBrief so the frontend never crashes
|
# we still provide an empty PersonBrief so the frontend never crashes
|
||||||
# on null person access.
|
# on null person access.
|
||||||
owner_person_data = PersonBrief(
|
owner_person_data = PersonBrief(
|
||||||
|
id=owner_person.id if owner_person else None,
|
||||||
first_name=owner_person.first_name or "" if owner_person else "",
|
first_name=owner_person.first_name or "" if owner_person else "",
|
||||||
last_name=owner_person.last_name or "" if owner_person else "",
|
last_name=owner_person.last_name or "" if owner_person else "",
|
||||||
email=owner_email,
|
email=owner_email,
|
||||||
@@ -629,7 +726,12 @@ async def get_organization_details(
|
|||||||
primary_contact=primary_contact,
|
primary_contact=primary_contact,
|
||||||
created_at=org.created_at.isoformat() if org.created_at else None,
|
created_at=org.created_at.isoformat() if org.created_at else None,
|
||||||
member_count=member_count,
|
member_count=member_count,
|
||||||
|
# P0: Expose owner user ID and person ID for frontend display
|
||||||
|
owner_user_id=owner.id if owner else None,
|
||||||
|
owner_person_id=owner_person.id if owner_person else None,
|
||||||
members=members_list,
|
members=members_list,
|
||||||
|
# ── P0 ADD-ON UPGRADE: Branches list ──
|
||||||
|
branches=branches_list,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -939,17 +1041,27 @@ async def update_org_subscription(
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
valid_until = now + timedelta(days=days)
|
valid_until = now + timedelta(days=days)
|
||||||
|
|
||||||
# 5. Létrehozzuk az új subscription rekordot
|
# 5. P0 ADD-ON: Összeállítjuk az extra_allowances JSONB-t
|
||||||
|
extra_allowances = {}
|
||||||
|
if payload.extra_vehicles > 0:
|
||||||
|
extra_allowances["extra_vehicles"] = payload.extra_vehicles
|
||||||
|
if payload.extra_branches > 0:
|
||||||
|
extra_allowances["extra_branches"] = payload.extra_branches
|
||||||
|
if payload.extra_users > 0:
|
||||||
|
extra_allowances["extra_users"] = payload.extra_users
|
||||||
|
|
||||||
|
# 6. Létrehozzuk az új subscription rekordot
|
||||||
new_sub = OrganizationSubscription(
|
new_sub = OrganizationSubscription(
|
||||||
org_id=org_id,
|
org_id=org_id,
|
||||||
tier_id=payload.tier_id,
|
tier_id=payload.tier_id,
|
||||||
valid_from=now,
|
valid_from=now,
|
||||||
valid_until=valid_until,
|
valid_until=valid_until,
|
||||||
is_active=True,
|
is_active=True,
|
||||||
|
extra_allowances=extra_allowances,
|
||||||
)
|
)
|
||||||
db.add(new_sub)
|
db.add(new_sub)
|
||||||
|
|
||||||
# 6. Frissítjük a Organization denormalizált mezőit is
|
# 7. Frissítjük a Organization denormalizált mezőit is
|
||||||
org.subscription_tier_id = payload.tier_id
|
org.subscription_tier_id = payload.tier_id
|
||||||
org.subscription_expires_at = valid_until
|
org.subscription_expires_at = valid_until
|
||||||
org.subscription_plan = tier.name
|
org.subscription_plan = tier.name
|
||||||
@@ -960,7 +1072,8 @@ async def update_org_subscription(
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"Admin {current_user.id} ({current_user.email}) updated subscription for org {org_id}: "
|
f"Admin {current_user.id} ({current_user.email}) updated subscription for org {org_id}: "
|
||||||
f"tier_id={payload.tier_id}, tier_name={tier.name}, "
|
f"tier_id={payload.tier_id}, tier_name={tier.name}, "
|
||||||
f"valid_until={valid_until.isoformat()}"
|
f"valid_until={valid_until.isoformat()}, "
|
||||||
|
f"extra_allowances={extra_allowances}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -974,6 +1087,7 @@ async def update_org_subscription(
|
|||||||
"valid_from": new_sub.valid_from.isoformat() if new_sub.valid_from else None,
|
"valid_from": new_sub.valid_from.isoformat() if new_sub.valid_from else None,
|
||||||
"valid_until": new_sub.valid_until.isoformat() if new_sub.valid_until else None,
|
"valid_until": new_sub.valid_until.isoformat() if new_sub.valid_until else None,
|
||||||
"is_active": new_sub.is_active,
|
"is_active": new_sub.is_active,
|
||||||
|
"extra_allowances": extra_allowances,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class OrganizationMemberUpdate(BaseModel):
|
|||||||
|
|
||||||
class PersonBrief(BaseModel):
|
class PersonBrief(BaseModel):
|
||||||
"""Nested person data for member responses."""
|
"""Nested person data for member responses."""
|
||||||
|
id: Optional[int] = None
|
||||||
first_name: str = ""
|
first_name: str = ""
|
||||||
last_name: str = ""
|
last_name: str = ""
|
||||||
email: Optional[str] = None
|
email: Optional[str] = None
|
||||||
|
|||||||
315
docs/admin_garage_subscription_tab_bugfix_spec.md
Normal file
315
docs/admin_garage_subscription_tab_bugfix_spec.md
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
# 🔧 Javítási Terv: Admin Garázs Előfizetés Fül — Hibás Csomagadatok
|
||||||
|
|
||||||
|
> **Gitea Issue:** [#301](http://192.168.100.10:3000/kincses/service-finder/issues/301)
|
||||||
|
> **Hatáskör:** Backend (admin_organizations.py) + Frontend (index.vue)
|
||||||
|
> **Típus:** Bug
|
||||||
|
> **Prioritás:** Magas
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Összefoglaló
|
||||||
|
|
||||||
|
A frontend admin `frontend_admin/pages/garages/[id]/index.vue` garázs részletek oldal Előfizetés (Subscription) fülén a kiválasztott csomaghoz tartozó adatok (asset_limit, branch_limit, asset_count) nem a valóságot tükrözik. A backend `SubscriptionSummary` Pydantic modellje hiányos, és a limit-ek kinyerése törékeny.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Feltárt Hibák (Root Causes)
|
||||||
|
|
||||||
|
### 🐛 #1: `branch_limit` mező hiányzik a `SubscriptionSummary`-ból
|
||||||
|
|
||||||
|
**Hely:** `backend/app/api/v1/endpoints/admin_organizations.py:116-124`
|
||||||
|
|
||||||
|
A `SubscriptionSummary` Pydantic modell jelenleg nem tartalmaz `branch_limit` mezőt. A frontend template azonban használja:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// frontend_admin/pages/garages/[id]/index.vue:526
|
||||||
|
{{ garage.branches?.length || 0 }} / {{ garage.subscription?.branch_limit || '∞' }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Mivel `branch_limit` sosem érkezik a backend válaszban, a mező `undefined`, és a frontend mindig `'∞'`-t (végtelen) jelenít meg.
|
||||||
|
|
||||||
|
### 🐛 #2: `asset_limit` kinyerése logikai hibás
|
||||||
|
|
||||||
|
**Hely:** `backend/app/api/v1/endpoints/admin_organizations.py:462-465`
|
||||||
|
|
||||||
|
```python
|
||||||
|
asset_limit = (
|
||||||
|
rules.get("max_vehicles")
|
||||||
|
or active_sub.tier.feature_capabilities.get("max_vehicles")
|
||||||
|
or 1
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problémák:**
|
||||||
|
1. Python `or` operátor falsy-nak tekinti a `0`-t — ha a tier `max_vehicles: 0`, az `or` miatt `feature_capabilities`-re ugrik tovább.
|
||||||
|
2. Ha `feature_capabilities`-ben sincs `max_vehicles`, vagy az is `0`, az `asset_limit = 1` lesz.
|
||||||
|
3. Ha a tier más kulcsnevet használ (pl. `vehicle_limit`, `max_assets`), az érték hibásan `1`-re esik vissza.
|
||||||
|
|
||||||
|
### 🐛 #3: `GarageDetailsResponse` nem tartalmaz `branches` mezőt
|
||||||
|
|
||||||
|
**Hely:** `backend/app/api/v1/endpoints/admin_organizations.py:127-175`
|
||||||
|
|
||||||
|
A `GarageDetailsResponse` modellben nincs `branches` lista. A frontend `garage.branches?.length` használ, de a backend nem ad vissza branch adatokat, így a kihasználtsági mutató mindig `0 / ∞`.
|
||||||
|
|
||||||
|
### 🐛 #4: `asset_count` hardkódolt (mindig 0)
|
||||||
|
|
||||||
|
**Hely:** `backend/app/api/v1/endpoints/admin_organizations.py:473`
|
||||||
|
|
||||||
|
```python
|
||||||
|
asset_count=0,
|
||||||
|
```
|
||||||
|
|
||||||
|
Az `asset_count` mindig `0`, sosem számolja le a szervezet tényleges járműveit.
|
||||||
|
|
||||||
|
### 🐛 #5: Lejárt előfizetés is aktívként jelenhet meg
|
||||||
|
|
||||||
|
**Hely:** `backend/app/api/v1/endpoints/admin_organizations.py:414-425`
|
||||||
|
|
||||||
|
```python
|
||||||
|
.where(
|
||||||
|
OrganizationSubscription.org_id == org_id,
|
||||||
|
OrganizationSubscription.is_active == True,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
A lekérdezés nem ellenőrzi a `valid_until >= now()` feltételt. Ha egy subscription `is_active=True` de `valid_until` már lejárt, a backend továbbra is aktívként kezeli.
|
||||||
|
|
||||||
|
### 🐛 #6: Fallback path hiányos adatokkal
|
||||||
|
|
||||||
|
**Hely:** `backend/app/api/v1/endpoints/admin_organizations.py:476-488`
|
||||||
|
|
||||||
|
Ha nincs aktív `OrganizationSubscription`, a kód a `org.subscription_tier` denormalizált kapcsolatra esik vissza. Ez a path nem adja vissza a `valid_from` és `is_active` mezőket, csak a defaultokat használja.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Javítási Terv
|
||||||
|
|
||||||
|
### 1. Backend: `SubscriptionSummary` bővítése
|
||||||
|
|
||||||
|
**Fájl:** `backend/app/api/v1/endpoints/admin_organizations.py`
|
||||||
|
|
||||||
|
#### 1/a. `branch_limit` mező hozzáadása (sor 116-124 körül)
|
||||||
|
|
||||||
|
A `SubscriptionSummary` osztály bővítése:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class SubscriptionSummary(BaseModel):
|
||||||
|
tier_name: str = "Free/Fallback"
|
||||||
|
tier_level: int = 0
|
||||||
|
valid_from: Optional[str] = None
|
||||||
|
expires_at: Optional[str] = None
|
||||||
|
is_active: bool = True
|
||||||
|
asset_count: int = 0
|
||||||
|
asset_limit: int = 1
|
||||||
|
branch_limit: int = 0 # 🆕 HIÁNYZÓ MEZŐ
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1/b. `asset_limit` kinyerés javítása (sor 462-465)
|
||||||
|
|
||||||
|
Az `or` helyett használj **explicit `max()` logikát**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# JAVÍTVA: explicit max() használata az or helyett
|
||||||
|
rules = active_sub.tier.rules or {}
|
||||||
|
fc = active_sub.tier.feature_capabilities or {}
|
||||||
|
|
||||||
|
# Kompatibilitás: több kulcsnév támogatása
|
||||||
|
vehicle_limit_keys = ["max_vehicles", "vehicle_limit", "max_assets"]
|
||||||
|
asset_limit = max(
|
||||||
|
(rules.get(k, 0) for k in vehicle_limit_keys),
|
||||||
|
default=0
|
||||||
|
)
|
||||||
|
asset_limit = max(
|
||||||
|
asset_limit,
|
||||||
|
max((fc.get(k, 0) for k in vehicle_limit_keys), default=0),
|
||||||
|
)
|
||||||
|
asset_limit = max(asset_limit, 1) # minimum 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ugyanezt a javítást kell elvégezni a fallback path-on is** (sor 477-482).
|
||||||
|
|
||||||
|
#### 1/c. `branch_limit` kitermelése a rules-ből (sor 462-488 között)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 🆕 HIÁNYZÓ: branch_limit kinyerése
|
||||||
|
branch_limit_keys = ["max_branches", "branch_limit", "max_garages"]
|
||||||
|
branch_limit = max(
|
||||||
|
(rules.get(k, 0) for k in branch_limit_keys),
|
||||||
|
default=0
|
||||||
|
)
|
||||||
|
branch_limit = max(
|
||||||
|
branch_limit,
|
||||||
|
max((fc.get(k, 0) for k in branch_limit_keys), default=0),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Ezt add hozzá mindkét path-hoz (aktív sub + fallback):
|
||||||
|
|
||||||
|
```python
|
||||||
|
subscription_summary = SubscriptionSummary(
|
||||||
|
...
|
||||||
|
asset_limit=asset_limit,
|
||||||
|
branch_limit=branch_limit, # 🆕
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1/d. `asset_count` dinamikus számolása
|
||||||
|
|
||||||
|
Az `asset_count`-ot ne hardkódold. Számold meg a szervezet járműveit. Ehhez be kell tölteni az `Organization.assets` relationship-et a SELECT-nél:
|
||||||
|
|
||||||
|
```python
|
||||||
|
org_stmt = (
|
||||||
|
select(Organization)
|
||||||
|
.options(
|
||||||
|
selectinload(Organization.subscription_tier),
|
||||||
|
selectinload(Organization.owner).selectinload(User.person),
|
||||||
|
selectinload(Organization.assets), # 🆕
|
||||||
|
)
|
||||||
|
.where(Organization.id == org_id)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Majd a subscription summary építésénél:
|
||||||
|
|
||||||
|
```python
|
||||||
|
asset_count = len(org.assets) if hasattr(org, 'assets') and org.assets else 0
|
||||||
|
```
|
||||||
|
|
||||||
|
VAGY használj explicit lekérdezést:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from sqlalchemy import func
|
||||||
|
from app.models.asset import AssetAssignment
|
||||||
|
|
||||||
|
asset_count_stmt = select(func.count(AssetAssignment.id)).where(
|
||||||
|
AssetAssignment.organization_id == org_id
|
||||||
|
)
|
||||||
|
asset_count_result = await db.execute(asset_count_stmt)
|
||||||
|
asset_count = asset_count_result.scalar() or 0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1/e. Lejárt előfizetés szűrés (sor 414-425)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from sqlalchemy import or_ as sa_or
|
||||||
|
|
||||||
|
sub_stmt = (
|
||||||
|
select(OrganizationSubscription)
|
||||||
|
.options(selectinload(OrganizationSubscription.tier))
|
||||||
|
.where(
|
||||||
|
OrganizationSubscription.org_id == org_id,
|
||||||
|
OrganizationSubscription.is_active == True,
|
||||||
|
# 🆕 HIÁNYZÓ: lejárati dátum ellenőrzése
|
||||||
|
sa_or_(
|
||||||
|
OrganizationSubscription.valid_until.is_(None),
|
||||||
|
OrganizationSubscription.valid_until >= func.now(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.order_by(OrganizationSubscription.id.desc())
|
||||||
|
.limit(1)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Backend: `GarageDetailsResponse` bővítése `branches` listával
|
||||||
|
|
||||||
|
**Fájl:** `backend/app/api/v1/endpoints/admin_organizations.py`
|
||||||
|
|
||||||
|
#### 2/a. BranchBrief Pydantic modell létrehozása (a SubscriptionSummary után)
|
||||||
|
|
||||||
|
```python
|
||||||
|
class BranchBrief(BaseModel):
|
||||||
|
"""Fióktelep rövid adatai."""
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
city: Optional[str] = None
|
||||||
|
is_active: bool = True
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2/b. `GarageDetailsResponse` bővítése `branches`-szel
|
||||||
|
|
||||||
|
```python
|
||||||
|
class GarageDetailsResponse(BaseModel):
|
||||||
|
...
|
||||||
|
subscription: Optional[SubscriptionSummary] = None
|
||||||
|
branches: List[BranchBrief] = [] # 🆕 HIÁNYZÓ MEZŐ
|
||||||
|
primary_contact: Optional[ContactPersonInfo] = None
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2/c. Branch adatok lekérdezése a végpontban
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 🆕 HIÁNYZÓ: branch adatok lekérése
|
||||||
|
from app.models.location import Branch
|
||||||
|
|
||||||
|
branches_stmt = select(Branch).where(Branch.organization_id == org_id)
|
||||||
|
branches_result = await db.execute(branches_stmt)
|
||||||
|
branches_data = branches_result.scalars().all()
|
||||||
|
|
||||||
|
branch_list = [
|
||||||
|
BranchBrief(
|
||||||
|
id=b.id,
|
||||||
|
name=b.name,
|
||||||
|
city=b.city,
|
||||||
|
is_active=b.is_active,
|
||||||
|
)
|
||||||
|
for b in branches_data
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Frontend: Ellenőrző módosítások
|
||||||
|
|
||||||
|
**Fájl:** `frontend_admin/pages/garages/[id]/index.vue`
|
||||||
|
|
||||||
|
#### 3/a. `branchQuotaPercent` computed property ellenőrzése
|
||||||
|
|
||||||
|
Ellenőrizd, hogy a számított property helyesen működik a nem-`undefined` `branch_limit`-nel:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const branchQuotaPercent = computed(() => {
|
||||||
|
if (!garage.value?.subscription?.branch_limit) return 0
|
||||||
|
const branchCount = garage.value?.branches?.length || 0
|
||||||
|
return (branchCount / garage.value.subscription.branch_limit) * 100
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Elfogadási Kritériák (Acceptance Criteria)
|
||||||
|
|
||||||
|
1. **Branch limit megjelenítése:** A branches utilization sorban a backend által küldött `branch_limit` érték jelenjen meg (ne mindig `∞`).
|
||||||
|
2. **Asset limit helyes értéke:** A kiválasztott csomag `rules` JSONB-jében lévő `max_vehicles` (vagy alternatív kulcs) értéke jelenjen meg.
|
||||||
|
3. **Asset count valós adat:** A járművek száma ne `0` legyen, hanem a tényleges asset-ek száma.
|
||||||
|
4. **Branch count valós adat:** A branch-ek száma ne mindig `0` legyen, hanem a tényleges branch-ek száma a `branches` listából.
|
||||||
|
5. **Lejárt előfizetés:** Ne jelenjen meg aktív előfizetésként, ha a `valid_until` már lejárt.
|
||||||
|
6. **Fallback:** Ha nincs aktív subscription, a `org.subscription_tier` denormalizált mezőből származó adatok legyenek teljesek (valid_from, is_active).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Módosítandó Fájlok
|
||||||
|
|
||||||
|
| # | Fájl | Változtatás |
|
||||||
|
|---|------|-------------|
|
||||||
|
| 1 | `backend/app/api/v1/endpoints/admin_organizations.py` | `SubscriptionSummary` bővítése `branch_limit`-lel, `asset_limit` logika javítása, `asset_count` dinamikus számolása, `GarageDetailsResponse` bővítése `branches`-szel + `BranchBrief`, lejárati dátum szűrés |
|
||||||
|
| 2 | `frontend_admin/pages/garages/[id]/index.vue` | `branchQuotaPercent` számítás ellenőrzése |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Tesztelési Terv
|
||||||
|
|
||||||
|
1. **Létező garázs megnyitása:** Ellenőrizd, hogy az Előfizetés fül a tényleges csomag adatait mutatja.
|
||||||
|
2. **Csomagváltás:** Válts csomagot, és ellenőrizd, hogy a frissítés után a helyes adatok jelennek meg.
|
||||||
|
3. **Lejárt előfizetés:** Állíts be egy lejárt `valid_until` dátumot, és ellenőrizd, hogy a garázs fallback csomag adatait mutatja.
|
||||||
|
4. **Több branch-es garázs:** Ellenőrizd, hogy a branch count és limit helyesen jelenik meg.
|
||||||
|
5. **API teszt:** `GET /api/v1/admin/organizations/{id}/details` - ellenőrizd, hogy a válasz tartalmazza a `subscription.branch_limit` és `branches` mezőket.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ Végrehajtási Sorrend
|
||||||
|
|
||||||
|
1. **Code mód** váltása
|
||||||
|
2. Backend módosítások elvégzése (`admin_organizations.py`)
|
||||||
|
3. Sync engine futtatása: `docker compose exec sf_api python3 /app/backend/app/scripts/sync_engine.py`
|
||||||
|
4. API konténer újraindítása
|
||||||
|
5. Frontend (ha szükséges) módosítása
|
||||||
|
6. Manuális tesztelés a böngészőből
|
||||||
156
docs/admin_garage_system_identifiers_bug_analysis.md
Normal file
156
docs/admin_garage_system_identifiers_bug_analysis.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# 🔍 Admin Garázs Részletek — Rendszer Azonosítók Bug Analysis
|
||||||
|
|
||||||
|
**Dátum:** 2026-06-26
|
||||||
|
**URL:** GET /api/v1/admin/organizations/{org_id}/details
|
||||||
|
**Érintett garázs:** org_id=43 (Accipe Tímea - Privát Garázs)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Probléma Leírás
|
||||||
|
|
||||||
|
Az admin oldalon a Garázs menü → General Tab → Cégadatok → Rendszer Azonosítók blokkban 3 értéknek kellene megjelennie:
|
||||||
|
|
||||||
|
| Mező | Várt érték | Tényleges | Státusz |
|
||||||
|
|------|-----------|-----------|---------|
|
||||||
|
| Garázs ID | 43 | 43 | OK |
|
||||||
|
| User ID (tulajdonos) | 79 | N/A | HIBA |
|
||||||
|
| Person ID (tulajdonos) | (valami szám) | N/A | HIBA |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Root Cause Analysis
|
||||||
|
|
||||||
|
### HIBA #1 — User ID nem töltődik be
|
||||||
|
|
||||||
|
**Hely:** frontend_admin/pages/garages/[id]/index.vue:200
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<span>User ID: <span>{{ garage.owner?.id || 'N/A' }}</span></span>
|
||||||
|
```
|
||||||
|
|
||||||
|
A frontend a `garage.owner?.id` kifejezéssel próbálja elérni a tulajdonos User ID-ját.
|
||||||
|
|
||||||
|
**A probléma:** A `GarageDetailsResponse` Pydantic séma (backend/app/api/v1/endpoints/admin_organizations.py:127-172) **nem tartalmaz** `owner` mezőt! A séma jelenlegi mezői:
|
||||||
|
- `owner_person_id: Optional[int]` (sor 170) — letezik
|
||||||
|
- `owner_user_id` — NEM LETEZIK
|
||||||
|
- `owner` object — NEM LETEZIK
|
||||||
|
|
||||||
|
Mivel a backend válaszban nincs `owner` kulcs, `garage.owner` mindig `undefined`, igy `garage.owner?.id` is `undefined`, ami a `|| 'N/A'` miatt 'N/A'-ra esik vissza.
|
||||||
|
|
||||||
|
**Adat elerhetoseg:** A backend lekeri az `org.owner`-t (`User` modell) a 398. sorban:
|
||||||
|
```python
|
||||||
|
selectinload(Organization.owner).selectinload(User.person)
|
||||||
|
```
|
||||||
|
Es elerheto az 503-514. sorokban:
|
||||||
|
```python
|
||||||
|
owner: Optional[User] = org.owner # User objektum, id=79
|
||||||
|
```
|
||||||
|
|
||||||
|
Tehat az adat **rendelkezesre all** a backendben, csak **nincs kiteve** a valaszban.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### HIBA #2 — Person ID nem toltodik be
|
||||||
|
|
||||||
|
**Hely:** frontend_admin/pages/garages/[id]/index.vue:201
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<span>Person ID: <span>{{ garage.owner_person_id ?? 'N/A' }}</span></span>
|
||||||
|
```
|
||||||
|
|
||||||
|
A frontend a `garage.owner_person_id` mezot olvassa. Ez a mezo **letezik** a `GarageDetailsResponse` semaban (sor 170) es a backend be is tolti a 648. sorban:
|
||||||
|
|
||||||
|
```python
|
||||||
|
owner_person_id=owner_person.id if owner_person else None,
|
||||||
|
```
|
||||||
|
|
||||||
|
**Lehetseges okok:**
|
||||||
|
1. `owner.person` (a User-hez tartozo Person rekord) **None** az adatbazisban
|
||||||
|
2. A `PersonBrief` sema (backend/app/schemas/organization.py:37-43) `id: Optional[int] = None` mezoje None, igy a szemely rekord ID-ja nem elerheto
|
||||||
|
|
||||||
|
**Megfigyeles:** A members[0].person objektumban sincs `id` mezo a valaszban, ami arra utal, hogy a `person.id` None a serializacio soran.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adatfolyam Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
[Adatbazis] [Backend API] [Frontend]
|
||||||
|
|
||||||
|
User (id=79) --------> org.owner (elerheto) -----+
|
||||||
|
| |
|
||||||
|
v v
|
||||||
|
Person (id=?) -------> owner_person -------------+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
GarageDetailsResponse
|
||||||
|
+-- id: 43 OK
|
||||||
|
+-- owner? -> NINCS
|
||||||
|
+-- owner_user_id? -> NINCS
|
||||||
|
+-- owner_person_id -> null
|
||||||
|
|
|
||||||
|
v
|
||||||
|
garage.owner?.id -> N/A
|
||||||
|
garage.owner_person_id -> N/A
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Javítási Terv
|
||||||
|
|
||||||
|
### 1. Backend modositas — `owner_user_id` hozzaadasa
|
||||||
|
|
||||||
|
**Fajl:** backend/app/api/v1/endpoints/admin_organizations.py
|
||||||
|
|
||||||
|
**A) Sema bovites (sor 170 korul):**
|
||||||
|
```python
|
||||||
|
# P0: Owner user ID for frontend display
|
||||||
|
owner_user_id: Optional[int] = None
|
||||||
|
```
|
||||||
|
|
||||||
|
**B) Valasz bovites (sor 648 korul, a return elott):**
|
||||||
|
```python
|
||||||
|
owner_user_id=owner.id if owner else None,
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Frontend modositas — Helyes mezohivatkozas
|
||||||
|
|
||||||
|
**Fajl:** frontend_admin/pages/garages/[id]/index.vue
|
||||||
|
|
||||||
|
**Sor 200 modositasa:**
|
||||||
|
```vue
|
||||||
|
<!-- HIBA: garage.owner?.id -> garage.owner nem letezik -->
|
||||||
|
<span>User ID: <span>{{ garage.owner?.id || 'N/A' }}</span></span>
|
||||||
|
|
||||||
|
<!-- JAVITAS: garage.owner_user_id -> uj mezo -->
|
||||||
|
<span>User ID: <span>{{ garage.owner_user_id ?? 'N/A' }}</span></span>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Sor 201 (maradhat):**
|
||||||
|
```vue
|
||||||
|
<span>Person ID: <span>{{ garage.owner_person_id ?? 'N/A' }}</span></span>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Valasz (Javitas utan varhato)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 43,
|
||||||
|
"owner_user_id": 79,
|
||||||
|
"owner_person_id": 38,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Megjegyzes
|
||||||
|
|
||||||
|
A vizsgalt garazs (org_id=43) a `private_pro_v1` csomaggal rendelkezik:
|
||||||
|
- max jarmu: 3
|
||||||
|
- max garazs: 1
|
||||||
|
- havi kredit: 0
|
||||||
|
|
||||||
|
A `members` tombben a tulajdonos (user_id=79) `OWNER` role-lal szerepel, es a `person` adatai (first_name, last_name, email, phone) rendelkezesre allnak, de a `person.id` nincs kitoltve a valaszban.
|
||||||
@@ -2421,6 +2421,7 @@ var garages$1 = {
|
|||||||
employeesTab: "Dolgozók",
|
employeesTab: "Dolgozók",
|
||||||
fleetTab: "Flotta",
|
fleetTab: "Flotta",
|
||||||
analyticsTab: "Analitika",
|
analyticsTab: "Analitika",
|
||||||
|
subscriptionTab: "Előfizetés",
|
||||||
editBasicTab: "Alapadatok",
|
editBasicTab: "Alapadatok",
|
||||||
editContactTab: "Kapcsolat",
|
editContactTab: "Kapcsolat",
|
||||||
editAddressTab: "Címek",
|
editAddressTab: "Címek",
|
||||||
@@ -2457,7 +2458,41 @@ var garages$1 = {
|
|||||||
tab_addresses: "Címek",
|
tab_addresses: "Címek",
|
||||||
basic_info: "Alapadatok",
|
basic_info: "Alapadatok",
|
||||||
contact_section: "Kapcsolattartó",
|
contact_section: "Kapcsolattartó",
|
||||||
addresses_section: "Címek"
|
addresses_section: "Címek",
|
||||||
|
vehicles_used: "Járművek",
|
||||||
|
branches_used: "Telephelyek",
|
||||||
|
employees_used: "Dolgozók",
|
||||||
|
status: "Státusz",
|
||||||
|
subscription_history: "Előfizetési Előzmények",
|
||||||
|
history_date: "Dátum",
|
||||||
|
history_package: "Csomag",
|
||||||
|
history_action: "Művelet",
|
||||||
|
history_status: "Státusz",
|
||||||
|
no_subscription_history: "Még nincsenek előfizetési előzmények."
|
||||||
|
},
|
||||||
|
analytics: {
|
||||||
|
ltv: "Élettartam Érték (LTV)",
|
||||||
|
mrr: "Havi Bevétel (MRR)",
|
||||||
|
monthly_recurring: "Havi ismétlődő bevétel",
|
||||||
|
outstanding: "Kintlévőség",
|
||||||
|
all_settled: "Minden számla rendezve",
|
||||||
|
earned_credits: "Szerzett Kreditek",
|
||||||
|
contribution_xp: "Platform építésével gyűjtött XP",
|
||||||
|
invited_companies: "Meghívott Cégek",
|
||||||
|
companies_joined: "Cég csatlakozott a meghívásodra",
|
||||||
|
validated_garages: "Validált Garázsok",
|
||||||
|
garages_confirmed: "Garázs sikeresen hitelesítve",
|
||||||
|
utilization: "Kihasználtság",
|
||||||
|
vehicle_quota: "Jármű Kvóta",
|
||||||
|
employee_quota: "Alkalmazotti Kvóta",
|
||||||
|
utilized: "kihasználva",
|
||||||
|
marketplace_engagement: "Piactér & Aktivitás",
|
||||||
|
avg_rating: "Átlagos Értékelés",
|
||||||
|
reviews: "Értékelések",
|
||||||
|
reviews_count: "értékelés",
|
||||||
|
last_activity: "Utolsó Aktivitás",
|
||||||
|
last_login_mock: "2 órája",
|
||||||
|
services_30d: "Elvégzett Szervizek (30 nap)"
|
||||||
},
|
},
|
||||||
employees: {
|
employees: {
|
||||||
title: "Dolgozók",
|
title: "Dolgozók",
|
||||||
@@ -2685,6 +2720,7 @@ var garages = {
|
|||||||
employeesTab: "Employees",
|
employeesTab: "Employees",
|
||||||
fleetTab: "Fleet",
|
fleetTab: "Fleet",
|
||||||
analyticsTab: "Analytics",
|
analyticsTab: "Analytics",
|
||||||
|
subscriptionTab: "Subscription",
|
||||||
editBasicTab: "Basic Info",
|
editBasicTab: "Basic Info",
|
||||||
editContactTab: "Contact",
|
editContactTab: "Contact",
|
||||||
editAddressTab: "Addresses",
|
editAddressTab: "Addresses",
|
||||||
@@ -2721,7 +2757,41 @@ var garages = {
|
|||||||
tab_addresses: "Addresses",
|
tab_addresses: "Addresses",
|
||||||
basic_info: "Basic Info",
|
basic_info: "Basic Info",
|
||||||
contact_section: "Contact Person",
|
contact_section: "Contact Person",
|
||||||
addresses_section: "Addresses"
|
addresses_section: "Addresses",
|
||||||
|
vehicles_used: "Vehicles",
|
||||||
|
branches_used: "Branches",
|
||||||
|
employees_used: "Employees",
|
||||||
|
status: "Status",
|
||||||
|
subscription_history: "Subscription History",
|
||||||
|
history_date: "Date",
|
||||||
|
history_package: "Package",
|
||||||
|
history_action: "Action",
|
||||||
|
history_status: "Status",
|
||||||
|
no_subscription_history: "No subscription history yet."
|
||||||
|
},
|
||||||
|
analytics: {
|
||||||
|
ltv: "Lifetime Value (LTV)",
|
||||||
|
mrr: "Monthly Revenue (MRR)",
|
||||||
|
monthly_recurring: "Monthly recurring revenue",
|
||||||
|
outstanding: "Outstanding",
|
||||||
|
all_settled: "All invoices settled",
|
||||||
|
earned_credits: "Earned Credits",
|
||||||
|
contribution_xp: "XP earned from platform contributions",
|
||||||
|
invited_companies: "Invited Companies",
|
||||||
|
companies_joined: "Companies joined via your invite",
|
||||||
|
validated_garages: "Validated Garages",
|
||||||
|
garages_confirmed: "Garages successfully verified",
|
||||||
|
utilization: "Utilization",
|
||||||
|
vehicle_quota: "Vehicle Quota",
|
||||||
|
employee_quota: "Employee Quota",
|
||||||
|
utilized: "utilized",
|
||||||
|
marketplace_engagement: "Marketplace & Engagement",
|
||||||
|
avg_rating: "Average Rating",
|
||||||
|
reviews: "Reviews",
|
||||||
|
reviews_count: "reviews",
|
||||||
|
last_activity: "Last Activity",
|
||||||
|
last_login_mock: "2 hours ago",
|
||||||
|
services_30d: "Services Completed (30 days)"
|
||||||
},
|
},
|
||||||
employees: {
|
employees: {
|
||||||
title: "Employees",
|
title: "Employees",
|
||||||
@@ -3426,16 +3496,16 @@ _wH6JrtIxmaSoA8lCPWFnE9z4lQeXW6H5z3l5aymEQw
|
|||||||
const assets = {
|
const assets = {
|
||||||
"/index.mjs": {
|
"/index.mjs": {
|
||||||
"type": "text/javascript; charset=utf-8",
|
"type": "text/javascript; charset=utf-8",
|
||||||
"etag": "\"24b7a-X7Gi3Oi5IkHbqD0x6I8saqEhvJo\"",
|
"etag": "\"253ec-9gWita9FIFOcxrWJJImCHqiAiEc\"",
|
||||||
"mtime": "2026-06-26T00:29:32.171Z",
|
"mtime": "2026-06-26T13:42:06.440Z",
|
||||||
"size": 150394,
|
"size": 152556,
|
||||||
"path": "index.mjs"
|
"path": "index.mjs"
|
||||||
},
|
},
|
||||||
"/index.mjs.map": {
|
"/index.mjs.map": {
|
||||||
"type": "application/json",
|
"type": "application/json",
|
||||||
"etag": "\"83219-k/zre5TDT2FcQBXF7JC+SUbYHHs\"",
|
"etag": "\"83251-gdWWzINLTOdOWQypEY8kD82/CME\"",
|
||||||
"mtime": "2026-06-26T00:29:32.171Z",
|
"mtime": "2026-06-26T13:42:06.440Z",
|
||||||
"size": 537113,
|
"size": 537169,
|
||||||
"path": "index.mjs.map"
|
"path": "index.mjs.map"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{_ as s}from"./DlAUqK2U.js";import{o,c as t,J as r}from"./CHWHIiGB.js";const c={},n={class:"bg-slate-900 min-h-screen"};function a(e,l){return o(),t("div",n,[r(e.$slots,"default")])}const d=s(c,[["render",a]]);export{d as default};
|
|
||||||
1
frontend_admin/.nuxt/dist/client/_nuxt/BPZZgRgP.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/BPZZgRgP.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/client/_nuxt/BVodpYs3.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/BVodpYs3.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{_ as h}from"./qc1uPXiA.js";import{p as v,e as y,g as _,c as n,a as t,f as k,h as s,t as c,i as u,j as S,k as p,v as m,l as x,b as V,w as L,m as f,o as i,d as C}from"./CHWHIiGB.js";import{u as N}from"./DKEj_yij.js";const B=v("/sf_logo.png"),E={class:"min-h-screen bg-slate-900 flex items-center justify-center px-4"},R={class:"w-full max-w-md"},j={class:"bg-slate-800 rounded-xl shadow-2xl border border-slate-700 p-8"},A={key:0,class:"mb-6 p-3 rounded-lg bg-red-900/40 border border-red-700 text-red-300 text-sm"},D=["disabled"],F={key:0,class:"animate-spin h-5 w-5 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24"},I={class:"mt-6 text-center"},T=y({__name:"login",setup(M){const a=f(""),l=f(""),b=_(),o=N();async function g(){try{await o.login(a.value,l.value),b.push("/")}catch(d){console.error("Login failed:",d)}}return(d,e)=>{const w=h;return i(),n("div",E,[t("div",R,[e[6]||(e[6]=k('<div class="text-center mb-8"><div class="flex items-center justify-center gap-3 mb-4"><img src="'+B+'" class="h-12 w-auto drop-shadow-md" alt="ServiceFinder Logo"><span class="text-3xl font-extrabold tracking-wider"><span class="text-white">SERVICE</span><span class="text-cyan-400">FINDER</span></span></div><h1 class="text-xl font-semibold text-slate-300">Staff Portal</h1><p class="text-sm text-slate-500 mt-1">Authorised personnel only</p></div>',1)),t("div",j,[s(o).error?(i(),n("div",A,c(s(o).error),1)):u("",!0),t("form",{onSubmit:S(g,["prevent"]),class:"space-y-5"},[t("div",null,[e[2]||(e[2]=t("label",{for:"email",class:"block text-sm font-medium text-slate-300 mb-1.5"}," Email Address ",-1)),p(t("input",{id:"email","onUpdate:modelValue":e[0]||(e[0]=r=>x(a)?a.value=r:null),type:"email",autocomplete:"email",required:"",placeholder:"admin@example.com",class:"w-full px-4 py-2.5 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:border-transparent transition"},null,512),[[m,s(a)]])]),t("div",null,[e[3]||(e[3]=t("label",{for:"password",class:"block text-sm font-medium text-slate-300 mb-1.5"}," Password ",-1)),p(t("input",{id:"password","onUpdate:modelValue":e[1]||(e[1]=r=>x(l)?l.value=r:null),type:"password",autocomplete:"current-password",required:"",placeholder:"••••••••",class:"w-full px-4 py-2.5 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:border-transparent transition"},null,512),[[m,s(l)]])]),t("button",{type:"submit",disabled:s(o).isLoading,class:"w-full py-2.5 px-4 bg-cyan-600 hover:bg-cyan-500 disabled:bg-cyan-800 disabled:cursor-not-allowed text-white font-semibold rounded-lg transition duration-200 flex items-center justify-center gap-2"},[s(o).isLoading?(i(),n("svg",F,[...e[4]||(e[4]=[t("circle",{class:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor","stroke-width":"4"},null,-1),t("path",{class:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"},null,-1)])])):u("",!0),t("span",null,c(s(o).isLoading?"Signing in...":"Sign In"),1)],8,D)],32),t("div",I,[V(w,{to:"/",class:"text-sm text-slate-500 hover:text-cyan-400 transition"},{default:L(()=>[...e[5]||(e[5]=[C(" ← Back to ServiceFinder ",-1)])]),_:1})])])])])}}});export{T as default};
|
|
||||||
6
frontend_admin/.nuxt/dist/client/_nuxt/CGTxeHv7.js
vendored
Normal file
6
frontend_admin/.nuxt/dist/client/_nuxt/CGTxeHv7.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/client/_nuxt/CSkx_E93.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/CSkx_E93.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{K as a,B as i,C as o,h as l,L as c}from"./CGTxeHv7.js";const h=a(async(s,f)=>{let t,r;if(s.path==="/login")return;if(!i("access_token").value)return o("/login");const e=l();if(!e.user)try{[t,r]=c(()=>e.fetchUser()),await t,r()}catch{return e.logout(),o("/login")}if(!e.user)return e.logout(),o("/login");const n=["SUPERADMIN","ADMIN","MODERATOR","SALES_REP","SERVICE_MGR"],u=(e.user.role||"").toUpperCase();if(!n.includes(u))return e.logout(),o("/login")});export{h as default};
|
||||||
@@ -1 +1 @@
|
|||||||
import{_ as s}from"./DlAUqK2U.js";import{u as a,o as i,c as u,a as e,t as o}from"./CHWHIiGB.js";const l={class:"antialiased bg-white dark:bg-black dark:text-white font-sans grid min-h-screen overflow-hidden place-content-center text-black"},c={class:"max-w-520px text-center"},d=["textContent"],p=["textContent"],f={__name:"error-500",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},status:{type:Number,default:500},statusText:{type:String,default:"Server error"},description:{type:String,default:"This page is temporarily unavailable."}},setup(t){const r=t;return a({title:`${r.status} - ${r.statusText} | ${r.appName}`,script:[{innerHTML:`!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver(e=>{for(const o of e)if("childList"===o.type)for(const e of o.addedNodes)"LINK"===e.tagName&&"modulepreload"===e.rel&&r(e)}).observe(document,{childList:!0,subtree:!0})}function r(e){if(e.ep)return;e.ep=!0;const r=function(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),"use-credentials"===e.crossOrigin?r.credentials="include":"anonymous"===e.crossOrigin?r.credentials="omit":r.credentials="same-origin",r}(e);fetch(e.href,r)}}();`}],style:[{innerHTML:'*,:after,:before{border-color:var(--un-default-border-color,#e5e7eb);border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}h1{font-size:inherit;font-weight:inherit}h1,p{margin:0}*,:after,:before{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 transparent;--un-ring-shadow:0 0 transparent;--un-shadow-inset: ;--un-shadow:0 0 transparent;--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }'}]}),(g,n)=>(i(),u("div",l,[n[0]||(n[0]=e("div",{class:"-bottom-1/2 fixed h-1/2 left-0 right-0 spotlight"},null,-1)),e("div",c,[e("h1",{class:"font-medium mb-8 sm:text-10xl text-8xl",textContent:o(t.status)},null,8,d),e("p",{class:"font-light leading-tight mb-16 px-8 sm:px-0 sm:text-4xl text-xl",textContent:o(t.description)},null,8,p)])]))}},h=s(f,[["__scopeId","data-v-a01dd0ba"]]);export{h as default};
|
import{_ as s}from"./DlAUqK2U.js";import{u as a,o as i,c as u,a as e,t as o}from"./CGTxeHv7.js";const l={class:"antialiased bg-white dark:bg-black dark:text-white font-sans grid min-h-screen overflow-hidden place-content-center text-black"},c={class:"max-w-520px text-center"},d=["textContent"],p=["textContent"],f={__name:"error-500",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},status:{type:Number,default:500},statusText:{type:String,default:"Server error"},description:{type:String,default:"This page is temporarily unavailable."}},setup(t){const r=t;return a({title:`${r.status} - ${r.statusText} | ${r.appName}`,script:[{innerHTML:`!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver(e=>{for(const o of e)if("childList"===o.type)for(const e of o.addedNodes)"LINK"===e.tagName&&"modulepreload"===e.rel&&r(e)}).observe(document,{childList:!0,subtree:!0})}function r(e){if(e.ep)return;e.ep=!0;const r=function(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),"use-credentials"===e.crossOrigin?r.credentials="include":"anonymous"===e.crossOrigin?r.credentials="omit":r.credentials="same-origin",r}(e);fetch(e.href,r)}}();`}],style:[{innerHTML:'*,:after,:before{border-color:var(--un-default-border-color,#e5e7eb);border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}h1{font-size:inherit;font-weight:inherit}h1,p{margin:0}*,:after,:before{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 transparent;--un-ring-shadow:0 0 transparent;--un-shadow-inset: ;--un-shadow:0 0 transparent;--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }'}]}),(g,n)=>(i(),u("div",l,[n[0]||(n[0]=e("div",{class:"-bottom-1/2 fixed h-1/2 left-0 right-0 spotlight"},null,-1)),e("div",c,[e("h1",{class:"font-medium mb-8 sm:text-10xl text-8xl",textContent:o(t.status)},null,8,d),e("p",{class:"font-light leading-tight mb-16 px-8 sm:px-0 sm:text-4xl text-xl",textContent:o(t.description)},null,8,p)])]))}},h=s(f,[["__scopeId","data-v-a01dd0ba"]]);export{h as default};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{a3 as C,m as u,x as l,z as r}from"./CHWHIiGB.js";const g=C("auth",()=>{const t=u(null),o=u(null),c=u(!1),s=u(null),v=u(!1),h=l(()=>!!o.value&&!!t.value),k=l(()=>{const e=t.value?.role;return e?["SUPERADMIN","ADMIN","MODERATOR","SALES_REP","SERVICE_MGR"].includes(e.toUpperCase()):!1}),m=l(()=>{if(!t.value)return"";const{first_name:e,last_name:n}=t.value;return e&&n?`${e} ${n}`:e||n||t.value.email}),p=l(()=>t.value?.email??""),w=l(()=>t.value?.role??"guest");async function R(e,n){c.value=!0,s.value=null;try{const a=new URLSearchParams;a.append("username",e),a.append("password",n);const d=await $fetch("/api/v1/auth/login",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:a}),A=r("access_token",{maxAge:3600*24*7,path:"/",sameSite:"lax",secure:!0});A.value=d.access_token,o.value=d.access_token,await i()}catch(a){throw s.value=a?.data?.detail||a?.message||"Login failed",a}finally{c.value=!1}}async function i(){const n=r("access_token").value||o.value;if(n)try{const a=await $fetch("/api/v1/auth/me",{headers:{Authorization:`Bearer ${n}`}});t.value=a}catch(a){throw a?.response?.status===401&&f(),a}}function f(){o.value=null,t.value=null,s.value=null;const e=r("access_token");e.value=null}async function _(){const e=r("access_token");if(e.value){o.value=e.value;try{await i()}catch{f()}}v.value=!0}function y(){s.value=null}return{user:t,token:o,isLoading:c,error:s,isInitialized:v,isAuthenticated:h,isAdmin:k,userName:m,userEmail:p,userRole:w,login:R,fetchUser:i,logout:f,init:_,clearError:y}});export{g as u};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{H as a,z as i,A as o,I as l}from"./CHWHIiGB.js";import{u as c}from"./DKEj_yij.js";const A=a(async(s,f)=>{let t,r;if(s.path==="/login")return;if(!i("access_token").value)return o("/login");const e=c();if(!e.user)try{[t,r]=l(()=>e.fetchUser()),await t,r()}catch{return e.logout(),o("/login")}if(!e.user)return e.logout(),o("/login");const u=["SUPERADMIN","ADMIN","MODERATOR","SALES_REP","SERVICE_MGR"],n=(e.user.role||"").toUpperCase();if(!u.includes(n))return e.logout(),o("/login")});export{A as default};
|
|
||||||
1
frontend_admin/.nuxt/dist/client/_nuxt/DU5nqnNf.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/DU5nqnNf.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{_ as s}from"./DlAUqK2U.js";import{o,c as t,M as r}from"./CGTxeHv7.js";const c={},n={class:"bg-slate-900 min-h-screen"};function a(e,l){return o(),t("div",n,[r(e.$slots,"default")])}const d=s(c,[["render",a]]);export{d as default};
|
||||||
1
frontend_admin/.nuxt/dist/client/_nuxt/D_jf_u12.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/D_jf_u12.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/client/_nuxt/Di7O2dT-.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/Di7O2dT-.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/client/_nuxt/DkxL14wO.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/DkxL14wO.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{_ as h}from"./BPZZgRgP.js";import{p as v,e as y,g as _,h as k,c as r,a as t,f as S,i as s,t as c,j as u,k as V,l as p,v as m,m as x,b as L,w as C,q as f,o as i,d as N}from"./CGTxeHv7.js";const B=v("/sf_logo.png"),E={class:"min-h-screen bg-slate-900 flex items-center justify-center px-4"},R={class:"w-full max-w-md"},j={class:"bg-slate-800 rounded-xl shadow-2xl border border-slate-700 p-8"},A={key:0,class:"mb-6 p-3 rounded-lg bg-red-900/40 border border-red-700 text-red-300 text-sm"},q=["disabled"],D={key:0,class:"animate-spin h-5 w-5 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24"},F={class:"mt-6 text-center"},P=y({__name:"login",setup(I){const a=f(""),l=f(""),b=_(),o=k();async function g(){try{await o.login(a.value,l.value),b.push("/")}catch(d){console.error("Login failed:",d)}}return(d,e)=>{const w=h;return i(),r("div",E,[t("div",R,[e[6]||(e[6]=S('<div class="text-center mb-8"><div class="flex items-center justify-center gap-3 mb-4"><img src="'+B+'" class="h-12 w-auto drop-shadow-md" alt="ServiceFinder Logo"><span class="text-3xl font-extrabold tracking-wider"><span class="text-white">SERVICE</span><span class="text-cyan-400">FINDER</span></span></div><h1 class="text-xl font-semibold text-slate-300">Staff Portal</h1><p class="text-sm text-slate-500 mt-1">Authorised personnel only</p></div>',1)),t("div",j,[s(o).error?(i(),r("div",A,c(s(o).error),1)):u("",!0),t("form",{onSubmit:V(g,["prevent"]),class:"space-y-5"},[t("div",null,[e[2]||(e[2]=t("label",{for:"email",class:"block text-sm font-medium text-slate-300 mb-1.5"}," Email Address ",-1)),p(t("input",{id:"email","onUpdate:modelValue":e[0]||(e[0]=n=>x(a)?a.value=n:null),type:"email",autocomplete:"email",required:"",placeholder:"admin@example.com",class:"w-full px-4 py-2.5 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:border-transparent transition"},null,512),[[m,s(a)]])]),t("div",null,[e[3]||(e[3]=t("label",{for:"password",class:"block text-sm font-medium text-slate-300 mb-1.5"}," Password ",-1)),p(t("input",{id:"password","onUpdate:modelValue":e[1]||(e[1]=n=>x(l)?l.value=n:null),type:"password",autocomplete:"current-password",required:"",placeholder:"••••••••",class:"w-full px-4 py-2.5 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:border-transparent transition"},null,512),[[m,s(l)]])]),t("button",{type:"submit",disabled:s(o).isLoading,class:"w-full py-2.5 px-4 bg-cyan-600 hover:bg-cyan-500 disabled:bg-cyan-800 disabled:cursor-not-allowed text-white font-semibold rounded-lg transition duration-200 flex items-center justify-center gap-2"},[s(o).isLoading?(i(),r("svg",D,[...e[4]||(e[4]=[t("circle",{class:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor","stroke-width":"4"},null,-1),t("path",{class:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"},null,-1)])])):u("",!0),t("span",null,c(s(o).isLoading?"Signing in...":"Sign In"),1)],8,q)],32),t("div",F,[L(w,{to:"/",class:"text-sm text-slate-500 hover:text-cyan-400 transition"},{default:C(()=>[...e[5]||(e[5]=[N(" ← Back to ServiceFinder ",-1)])]),_:1})])])])])}}});export{P as default};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/client/_nuxt/IlbAEw5Q.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/IlbAEw5Q.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
import{_ as a}from"./qc1uPXiA.js";import{_ as i}from"./DlAUqK2U.js";import{u,o as c,c as l,a as e,t as r,b as d,w as p,d as f}from"./CHWHIiGB.js";const m={class:"antialiased bg-white dark:bg-black dark:text-white font-sans grid min-h-screen overflow-hidden place-content-center text-black"},g={class:"max-w-520px text-center z-20"},b=["textContent"],h=["textContent"],x={class:"flex items-center justify-center w-full"},y={__name:"error-404",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},status:{type:Number,default:404},statusText:{type:String,default:"Not Found"},description:{type:String,default:"Sorry, the page you are looking for could not be found."},backHome:{type:String,default:"Go back home"}},setup(t){const n=t;return u({title:`${n.status} - ${n.statusText} | ${n.appName}`,script:[{innerHTML:`!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver(e=>{for(const o of e)if("childList"===o.type)for(const e of o.addedNodes)"LINK"===e.tagName&&"modulepreload"===e.rel&&r(e)}).observe(document,{childList:!0,subtree:!0})}function r(e){if(e.ep)return;e.ep=!0;const r=function(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),"use-credentials"===e.crossOrigin?r.credentials="include":"anonymous"===e.crossOrigin?r.credentials="omit":r.credentials="same-origin",r}(e);fetch(e.href,r)}}();`}],style:[{innerHTML:'*,:after,:before{border-color:var(--un-default-border-color,#e5e7eb);border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}h1{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}h1,p{margin:0}*,:after,:before{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 transparent;--un-ring-shadow:0 0 transparent;--un-shadow-inset: ;--un-shadow:0 0 transparent;--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }'}]}),(k,o)=>{const s=a;return c(),l("div",m,[o[0]||(o[0]=e("div",{class:"fixed left-0 right-0 spotlight z-10"},null,-1)),e("div",g,[e("h1",{class:"font-medium mb-8 sm:text-10xl text-8xl",textContent:r(t.status)},null,8,b),e("p",{class:"font-light leading-tight mb-16 px-8 sm:px-0 sm:text-4xl text-xl",textContent:r(t.description)},null,8,h),e("div",x,[d(s,{to:"/",class:"cursor-pointer gradient-border px-4 py-2 sm:px-6 sm:py-3 sm:text-xl text-md"},{default:p(()=>[f(r(t.backHome),1)]),_:1})])])])}}},z=i(y,[["__scopeId","data-v-1bd9e11a"]]);export{z as default};
|
import{_ as a}from"./BPZZgRgP.js";import{_ as i}from"./DlAUqK2U.js";import{u,o as c,c as l,a as e,t as r,b as d,w as p,d as f}from"./CGTxeHv7.js";const m={class:"antialiased bg-white dark:bg-black dark:text-white font-sans grid min-h-screen overflow-hidden place-content-center text-black"},g={class:"max-w-520px text-center z-20"},b=["textContent"],h=["textContent"],x={class:"flex items-center justify-center w-full"},y={__name:"error-404",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},status:{type:Number,default:404},statusText:{type:String,default:"Not Found"},description:{type:String,default:"Sorry, the page you are looking for could not be found."},backHome:{type:String,default:"Go back home"}},setup(t){const n=t;return u({title:`${n.status} - ${n.statusText} | ${n.appName}`,script:[{innerHTML:`!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver(e=>{for(const o of e)if("childList"===o.type)for(const e of o.addedNodes)"LINK"===e.tagName&&"modulepreload"===e.rel&&r(e)}).observe(document,{childList:!0,subtree:!0})}function r(e){if(e.ep)return;e.ep=!0;const r=function(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),"use-credentials"===e.crossOrigin?r.credentials="include":"anonymous"===e.crossOrigin?r.credentials="omit":r.credentials="same-origin",r}(e);fetch(e.href,r)}}();`}],style:[{innerHTML:'*,:after,:before{border-color:var(--un-default-border-color,#e5e7eb);border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}h1{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}h1,p{margin:0}*,:after,:before{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 transparent;--un-ring-shadow:0 0 transparent;--un-shadow-inset: ;--un-shadow:0 0 transparent;--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }'}]}),(k,o)=>{const s=a;return c(),l("div",m,[o[0]||(o[0]=e("div",{class:"fixed left-0 right-0 spotlight z-10"},null,-1)),e("div",g,[e("h1",{class:"font-medium mb-8 sm:text-10xl text-8xl",textContent:r(t.status)},null,8,b),e("p",{class:"font-light leading-tight mb-16 px-8 sm:px-0 sm:text-4xl text-xl",textContent:r(t.description)},null,8,h),e("div",x,[d(s,{to:"/",class:"cursor-pointer gradient-border px-4 py-2 sm:px-6 sm:py-3 sm:text-xl text-md"},{default:p(()=>[f(r(t.backHome),1)]),_:1})])])])}}},z=i(y,[["__scopeId","data-v-1bd9e11a"]]);export{z as default};
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
import{a3 as _,m as u,x as a}from"./CHWHIiGB.js";const h=_("region",()=>{const t=u([]),n=u(null),c=u(!1),l=u(null),o=a(()=>t.value.find(e=>e.country_code==="DEFAULT")||null),s=a(()=>{const e=new Map;for(const r of t.value)e.set(r.country_code,r);return e}),i=a(()=>n.value?.currency||o.value?.currency||"EUR"),v=a(()=>n.value?.locale_code||o.value?.locale_code||"en-EU"),f=a(()=>n.value?.default_vat_rate??o.value?.default_vat_rate??0),d=a(()=>n.value?.timezone||o.value?.timezone||"Europe/Brussels");async function g(){if(!(t.value.length>0)){c.value=!0,l.value=null;try{const e=await $fetch("/api/v1/system/regions");t.value=e||[]}catch(e){l.value=e?.data?.detail||e?.message||"Failed to load regions",console.error("[RegionStore] Fetch error:",e)}finally{c.value=!1}}}function m(e){const r=t.value.find(R=>R.country_code===e);n.value=r||o.value}function y(e){return s.value.get(e)}return{regions:t,activeRegion:n,isLoading:c,error:l,defaultRegion:o,regionMap:s,activeCurrency:i,activeLocale:v,activeVatRate:f,activeTimezone:d,fetchRegions:g,setActiveRegion:m,getRegion:y}});export{h as u};
|
import{a7 as _,q as u,z as a}from"./CGTxeHv7.js";const h=_("region",()=>{const t=u([]),n=u(null),c=u(!1),l=u(null),o=a(()=>t.value.find(e=>e.country_code==="DEFAULT")||null),s=a(()=>{const e=new Map;for(const r of t.value)e.set(r.country_code,r);return e}),i=a(()=>n.value?.currency||o.value?.currency||"EUR"),v=a(()=>n.value?.locale_code||o.value?.locale_code||"en-EU"),f=a(()=>n.value?.default_vat_rate??o.value?.default_vat_rate??0),d=a(()=>n.value?.timezone||o.value?.timezone||"Europe/Brussels");async function g(){if(!(t.value.length>0)){c.value=!0,l.value=null;try{const e=await $fetch("/api/v1/system/regions");t.value=e||[]}catch(e){l.value=e?.data?.detail||e?.message||"Failed to load regions",console.error("[RegionStore] Fetch error:",e)}finally{c.value=!1}}}function y(e){const r=t.value.find(R=>R.country_code===e);n.value=r||o.value}function m(e){return s.value.get(e)}return{regions:t,activeRegion:n,isLoading:c,error:l,defaultRegion:o,regionMap:s,activeCurrency:i,activeLocale:v,activeVatRate:f,activeTimezone:d,fetchRegions:g,setActiveRegion:y,getRegion:m}});export{h as u};
|
||||||
1
frontend_admin/.nuxt/dist/client/_nuxt/p3BZMbac.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/p3BZMbac.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/client/_nuxt/woz7WbxD.js
vendored
Normal file
1
frontend_admin/.nuxt/dist/client/_nuxt/woz7WbxD.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"file":"auth-9ekP0oPk.js","mappings":";;;;;;;;;;;;;;;;;;;AAEE,MAAA,iCAA0B,OAAA,IAAA,SAAA;AAAA,MAAA,QAAA;AACxB,MAAA,GAAA,SAAA,UAAA;AACF;AAAA,EAGA;AACA,sBAAiB,UAAO,cAAA;AACtB,MAAA,CAAA,mBAAkB;AACpB,WAAA,WAAA,QAAA;AAAA,EAGA;AAGA,oBAAe,aAAM;AACnB,MAAA,CAAA,UAAI,MAAA;AACF,QAAA;AACF;AAAA,MAAA,CAAA,QAAQ,SAAA,IAAAA,aAAA,MAAA,UAAA,UAAA,CAAA,GAAA,MAAA,QAAA,UAAA;AAAA;AAAA,IAEN,QAAA;AACA;AACF,aAAA,WAAA,QAAA;AAAA,IACF;AAAA,EAGA;AACE,MAAA,CAAA,UAAU,MAAO;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EAGA;AACA,QAAM,eAAY,CAAA,cAAe,SAAY,aAAY,aAAA,aAAA;AAEzD,QAAK,YAAa,UAAS,KAAA,QAAW,IAAA,YAAA;AAEpC,MAAA,CAAA,aAAU,SAAO,QAAA,GAAA;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EACF;;","names":["__executeAsync"],"sources":["../../../../middleware/auth.ts"],"sourcesContent":["export default defineNuxtRouteMiddleware(async (to, from) => {\n // Skip auth check on the login page itself\n if (to.path === '/login') {\n return\n }\n\n // Check for the access_token cookie\n const tokenCookie = useCookie('access_token')\n if (!tokenCookie.value) {\n return navigateTo('/login')\n }\n\n // ── RBAC: Verify user role from Pinia authStore ──────────────────────\n const authStore = useAuthStore()\n\n // If the user profile hasn't been loaded yet, try to fetch it\n if (!authStore.user) {\n try {\n await authStore.fetchUser()\n } catch {\n // Token is invalid or expired — clear and redirect to login\n authStore.logout()\n return navigateTo('/login')\n }\n }\n\n // After fetch, check if user is still null (fetch failed silently)\n if (!authStore.user) {\n authStore.logout()\n return navigateTo('/login')\n }\n\n // Allowed staff roles that can access the admin panel\n const allowedRoles = ['SUPERADMIN', 'ADMIN', 'MODERATOR', 'SALES_REP', 'SERVICE_MGR']\n const userRole = (authStore.user.role || '').toUpperCase()\n\n if (!allowedRoles.includes(userRole)) {\n // Standard USER or unknown role — kick them out, clear token, redirect\n authStore.logout()\n return navigateTo('/login')\n }\n})\n"],"version":3}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { executeAsync } from "/app/node_modules/unctx/dist/index.mjs";
|
import { executeAsync } from "/app/node_modules/unctx/dist/index.mjs";
|
||||||
import { d as defineNuxtRouteMiddleware, c as useCookie, n as navigateTo } from "../server.mjs";
|
import { e as defineNuxtRouteMiddleware, c as useCookie, n as navigateTo, b as useAuthStore } from "../server.mjs";
|
||||||
import { u as useAuthStore } from "./auth-RwMj9LdV.js";
|
|
||||||
import "vue";
|
import "vue";
|
||||||
import "/app/node_modules/ofetch/dist/node.mjs";
|
import "/app/node_modules/ofetch/dist/node.mjs";
|
||||||
import "#internal/nuxt/paths";
|
import "#internal/nuxt/paths";
|
||||||
@@ -51,4 +50,4 @@ const auth = defineNuxtRouteMiddleware(async (to, from) => {
|
|||||||
export {
|
export {
|
||||||
auth as default
|
auth as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=auth-9ekP0oPk.js.map
|
//# sourceMappingURL=auth-B3jrOAhu.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"auth-9ekP0oPk.js","sources":["../../../../middleware/auth.ts"],"sourcesContent":["export default defineNuxtRouteMiddleware(async (to, from) => {\n // Skip auth check on the login page itself\n if (to.path === '/login') {\n return\n }\n\n // Check for the access_token cookie\n const tokenCookie = useCookie('access_token')\n if (!tokenCookie.value) {\n return navigateTo('/login')\n }\n\n // ── RBAC: Verify user role from Pinia authStore ──────────────────────\n const authStore = useAuthStore()\n\n // If the user profile hasn't been loaded yet, try to fetch it\n if (!authStore.user) {\n try {\n await authStore.fetchUser()\n } catch {\n // Token is invalid or expired — clear and redirect to login\n authStore.logout()\n return navigateTo('/login')\n }\n }\n\n // After fetch, check if user is still null (fetch failed silently)\n if (!authStore.user) {\n authStore.logout()\n return navigateTo('/login')\n }\n\n // Allowed staff roles that can access the admin panel\n const allowedRoles = ['SUPERADMIN', 'ADMIN', 'MODERATOR', 'SALES_REP', 'SERVICE_MGR']\n const userRole = (authStore.user.role || '').toUpperCase()\n\n if (!allowedRoles.includes(userRole)) {\n // Standard USER or unknown role — kick them out, clear token, redirect\n authStore.logout()\n return navigateTo('/login')\n }\n})\n"],"names":["__executeAsync"],"mappings":";;;;;;;;;;;;;;;;;;;AAEE,MAAA,iCAA0B,OAAA,IAAA,SAAA;AAAA,MAAA,QAAA;AACxB,MAAA,GAAA,SAAA,UAAA;AACF;AAAA,EAGA;AACA,sBAAiB,UAAO,cAAA;AACtB,MAAA,CAAA,mBAAkB;AACpB,WAAA,WAAA,QAAA;AAAA,EAGA;AAGA,oBAAe,aAAM;AACnB,MAAA,CAAA,UAAI,MAAA;AACF,QAAA;AACF;AAAA,MAAA,CAAA,QAAQ,SAAA,IAAAA,aAAA,MAAA,UAAA,UAAA,CAAA,GAAA,MAAA,QAAA,UAAA;AAAA;AAAA,IAEN,QAAA;AACA;AACF,aAAA,WAAA,QAAA;AAAA,IACF;AAAA,EAGA;AACE,MAAA,CAAA,UAAU,MAAO;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EAGA;AACA,QAAM,eAAY,CAAA,cAAe,SAAY,aAAY,aAAA,aAAA;AAEzD,QAAK,YAAa,UAAS,KAAA,QAAW,IAAA,YAAA;AAEpC,MAAA,CAAA,aAAU,SAAO,QAAA,GAAA;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EACF;;"}
|
{"version":3,"file":"auth-B3jrOAhu.js","sources":["../../../../middleware/auth.ts"],"sourcesContent":["export default defineNuxtRouteMiddleware(async (to, from) => {\n // Skip auth check on the login page itself\n if (to.path === '/login') {\n return\n }\n\n // Check for the access_token cookie\n const tokenCookie = useCookie('access_token')\n if (!tokenCookie.value) {\n return navigateTo('/login')\n }\n\n // ── RBAC: Verify user role from Pinia authStore ──────────────────────\n const authStore = useAuthStore()\n\n // If the user profile hasn't been loaded yet, try to fetch it\n if (!authStore.user) {\n try {\n await authStore.fetchUser()\n } catch {\n // Token is invalid or expired — clear and redirect to login\n authStore.logout()\n return navigateTo('/login')\n }\n }\n\n // After fetch, check if user is still null (fetch failed silently)\n if (!authStore.user) {\n authStore.logout()\n return navigateTo('/login')\n }\n\n // Allowed staff roles that can access the admin panel\n const allowedRoles = ['SUPERADMIN', 'ADMIN', 'MODERATOR', 'SALES_REP', 'SERVICE_MGR']\n const userRole = (authStore.user.role || '').toUpperCase()\n\n if (!allowedRoles.includes(userRole)) {\n // Standard USER or unknown role — kick them out, clear token, redirect\n authStore.logout()\n return navigateTo('/login')\n }\n})\n"],"names":["__executeAsync"],"mappings":";;;;;;;;;;;;;;;;;;AAEE,MAAA,iCAA0B,OAAA,IAAA,SAAA;AAAA,MAAA,QAAA;AACxB,MAAA,GAAA,SAAA,UAAA;AACF;AAAA,EAGA;AACA,sBAAiB,UAAO,cAAA;AACtB,MAAA,CAAA,mBAAkB;AACpB,WAAA,WAAA,QAAA;AAAA,EAGA;AAGA,oBAAe,aAAM;AACnB,MAAA,CAAA,UAAI,MAAA;AACF,QAAA;AACF;AAAA,MAAA,CAAA,QAAQ,SAAA,IAAAA,aAAA,MAAA,UAAA,UAAA,CAAA,GAAA,MAAA,QAAA,UAAA;AAAA;AAAA,IAEN,QAAA;AACA;AACF,aAAA,WAAA,QAAA;AAAA,IACF;AAAA,EAGA;AACE,MAAA,CAAA,UAAU,MAAO;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EAGA;AACA,QAAM,eAAY,CAAA,cAAe,SAAY,aAAY,aAAA,aAAA;AAEzD,QAAK,YAAa,UAAS,KAAA,QAAW,IAAA,YAAA;AAEpC,MAAA,CAAA,aAAU,SAAO,QAAA,GAAA;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EACF;;"}
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/auth-B3jrOAhu.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/auth-B3jrOAhu.js.map.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"file":"auth-B3jrOAhu.js","mappings":";;;;;;;;;;;;;;;;;;AAEE,MAAA,iCAA0B,OAAA,IAAA,SAAA;AAAA,MAAA,QAAA;AACxB,MAAA,GAAA,SAAA,UAAA;AACF;AAAA,EAGA;AACA,sBAAiB,UAAO,cAAA;AACtB,MAAA,CAAA,mBAAkB;AACpB,WAAA,WAAA,QAAA;AAAA,EAGA;AAGA,oBAAe,aAAM;AACnB,MAAA,CAAA,UAAI,MAAA;AACF,QAAA;AACF;AAAA,MAAA,CAAA,QAAQ,SAAA,IAAAA,aAAA,MAAA,UAAA,UAAA,CAAA,GAAA,MAAA,QAAA,UAAA;AAAA;AAAA,IAEN,QAAA;AACA;AACF,aAAA,WAAA,QAAA;AAAA,IACF;AAAA,EAGA;AACE,MAAA,CAAA,UAAU,MAAO;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EAGA;AACA,QAAM,eAAY,CAAA,cAAe,SAAY,aAAY,aAAA,aAAA;AAEzD,QAAK,YAAa,UAAS,KAAA,QAAW,IAAA,YAAA;AAEpC,MAAA,CAAA,aAAU,SAAO,QAAA,GAAA;AACjB;AACF,WAAA,WAAA,QAAA;AAAA,EACF;;","names":["__executeAsync"],"sources":["../../../../middleware/auth.ts"],"sourcesContent":["export default defineNuxtRouteMiddleware(async (to, from) => {\n // Skip auth check on the login page itself\n if (to.path === '/login') {\n return\n }\n\n // Check for the access_token cookie\n const tokenCookie = useCookie('access_token')\n if (!tokenCookie.value) {\n return navigateTo('/login')\n }\n\n // ── RBAC: Verify user role from Pinia authStore ──────────────────────\n const authStore = useAuthStore()\n\n // If the user profile hasn't been loaded yet, try to fetch it\n if (!authStore.user) {\n try {\n await authStore.fetchUser()\n } catch {\n // Token is invalid or expired — clear and redirect to login\n authStore.logout()\n return navigateTo('/login')\n }\n }\n\n // After fetch, check if user is still null (fetch failed silently)\n if (!authStore.user) {\n authStore.logout()\n return navigateTo('/login')\n }\n\n // Allowed staff roles that can access the admin panel\n const allowedRoles = ['SUPERADMIN', 'ADMIN', 'MODERATOR', 'SALES_REP', 'SERVICE_MGR']\n const userRole = (authStore.user.role || '').toUpperCase()\n\n if (!allowedRoles.includes(userRole)) {\n // Standard USER or unknown role — kick them out, clear token, redirect\n authStore.logout()\n return navigateTo('/login')\n }\n})\n"],"version":3}
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
import { defineStore } from "pinia";
|
|
||||||
import { ref, computed } from "vue";
|
|
||||||
import { c as useCookie } from "../server.mjs";
|
|
||||||
const useAuthStore = defineStore("auth", () => {
|
|
||||||
const user = ref(null);
|
|
||||||
const token = ref(null);
|
|
||||||
const isLoading = ref(false);
|
|
||||||
const error = ref(null);
|
|
||||||
const isInitialized = ref(false);
|
|
||||||
const isAuthenticated = computed(() => !!token.value && !!user.value);
|
|
||||||
const isAdmin = computed(() => {
|
|
||||||
const role = user.value?.role;
|
|
||||||
if (!role) return false;
|
|
||||||
const staffRoles = ["SUPERADMIN", "ADMIN", "MODERATOR", "SALES_REP", "SERVICE_MGR"];
|
|
||||||
return staffRoles.includes(role.toUpperCase());
|
|
||||||
});
|
|
||||||
const userName = computed(() => {
|
|
||||||
if (!user.value) return "";
|
|
||||||
const { first_name, last_name } = user.value;
|
|
||||||
if (first_name && last_name) return `${first_name} ${last_name}`;
|
|
||||||
return first_name || last_name || user.value.email;
|
|
||||||
});
|
|
||||||
const userEmail = computed(() => user.value?.email ?? "");
|
|
||||||
const userRole = computed(() => user.value?.role ?? "guest");
|
|
||||||
async function login(email, password) {
|
|
||||||
isLoading.value = true;
|
|
||||||
error.value = null;
|
|
||||||
try {
|
|
||||||
const body = new URLSearchParams();
|
|
||||||
body.append("username", email);
|
|
||||||
body.append("password", password);
|
|
||||||
const res = await $fetch("/api/v1/auth/login", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
||||||
body
|
|
||||||
});
|
|
||||||
const tokenCookie = useCookie("access_token", {
|
|
||||||
maxAge: 60 * 60 * 24 * 7,
|
|
||||||
// 7 days
|
|
||||||
path: "/",
|
|
||||||
sameSite: "lax",
|
|
||||||
secure: true
|
|
||||||
});
|
|
||||||
tokenCookie.value = res.access_token;
|
|
||||||
token.value = res.access_token;
|
|
||||||
await fetchUser();
|
|
||||||
} catch (err) {
|
|
||||||
error.value = err?.data?.detail || err?.message || "Login failed";
|
|
||||||
throw err;
|
|
||||||
} finally {
|
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function fetchUser() {
|
|
||||||
const tokenCookie = useCookie("access_token");
|
|
||||||
const currentToken = tokenCookie.value || token.value;
|
|
||||||
if (!currentToken) return;
|
|
||||||
try {
|
|
||||||
const res = await $fetch("/api/v1/auth/me", {
|
|
||||||
headers: { Authorization: `Bearer ${currentToken}` }
|
|
||||||
});
|
|
||||||
user.value = res;
|
|
||||||
} catch (err) {
|
|
||||||
if (err?.response?.status === 401) {
|
|
||||||
logout();
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function logout() {
|
|
||||||
token.value = null;
|
|
||||||
user.value = null;
|
|
||||||
error.value = null;
|
|
||||||
const tokenCookie = useCookie("access_token");
|
|
||||||
tokenCookie.value = null;
|
|
||||||
}
|
|
||||||
async function init() {
|
|
||||||
const tokenCookie = useCookie("access_token");
|
|
||||||
if (tokenCookie.value) {
|
|
||||||
token.value = tokenCookie.value;
|
|
||||||
try {
|
|
||||||
await fetchUser();
|
|
||||||
} catch {
|
|
||||||
logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isInitialized.value = true;
|
|
||||||
}
|
|
||||||
function clearError() {
|
|
||||||
error.value = null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
// State
|
|
||||||
user,
|
|
||||||
token,
|
|
||||||
isLoading,
|
|
||||||
error,
|
|
||||||
isInitialized,
|
|
||||||
// Getters
|
|
||||||
isAuthenticated,
|
|
||||||
isAdmin,
|
|
||||||
userName,
|
|
||||||
userEmail,
|
|
||||||
userRole,
|
|
||||||
// Actions
|
|
||||||
login,
|
|
||||||
fetchUser,
|
|
||||||
logout,
|
|
||||||
init,
|
|
||||||
clearError
|
|
||||||
};
|
|
||||||
});
|
|
||||||
export {
|
|
||||||
useAuthStore as u
|
|
||||||
};
|
|
||||||
//# sourceMappingURL=auth-RwMj9LdV.js.map
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,11 +1,10 @@
|
|||||||
import { _ as __nuxt_component_0 } from "./nuxt-link-Cp-CAJwR.js";
|
import { _ as __nuxt_component_0 } from "./nuxt-link-C5PnX__I.js";
|
||||||
import { defineComponent, computed, ref, mergeProps, withCtx, createVNode, toDisplayString, unref, openBlock, createBlock, createTextVNode, useSSRContext } from "vue";
|
import { defineComponent, computed, ref, mergeProps, withCtx, createVNode, toDisplayString, unref, openBlock, createBlock, createTextVNode, useSSRContext } from "vue";
|
||||||
import { ssrRenderAttrs, ssrRenderClass, ssrRenderComponent, ssrRenderAttr, ssrRenderList, ssrRenderStyle, ssrInterpolate, ssrRenderSlot } from "vue/server-renderer";
|
import { ssrRenderAttrs, ssrRenderClass, ssrRenderComponent, ssrRenderAttr, ssrRenderList, ssrRenderStyle, ssrInterpolate, ssrRenderSlot } from "vue/server-renderer";
|
||||||
import { publicAssetsURL } from "#internal/nuxt/paths";
|
import { publicAssetsURL } from "#internal/nuxt/paths";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { u as useRegionStore } from "./region-0mvXqaMM.js";
|
import { u as useRegionStore } from "./region-0mvXqaMM.js";
|
||||||
import { a as useRouter, b as useI18n } from "../server.mjs";
|
import { a as useRouter, b as useAuthStore, d as useI18n } from "../server.mjs";
|
||||||
import { u as useAuthStore } from "./auth-RwMj9LdV.js";
|
|
||||||
import "/app/node_modules/klona/dist/index.mjs";
|
import "/app/node_modules/klona/dist/index.mjs";
|
||||||
import "/app/node_modules/hookable/dist/index.mjs";
|
import "/app/node_modules/hookable/dist/index.mjs";
|
||||||
import "/app/node_modules/ufo/dist/index.mjs";
|
import "/app/node_modules/ufo/dist/index.mjs";
|
||||||
@@ -72,7 +71,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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" /></svg>',
|
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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" /></svg>',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/users",
|
path: "/",
|
||||||
|
/* P0 HOTFIX: placeholder until /users page is built */
|
||||||
label: "Felhasználók listája",
|
label: "Felhasználók listája",
|
||||||
icon: '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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" /></svg>'
|
icon: '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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" /></svg>'
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>',
|
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/logs",
|
path: "/",
|
||||||
|
/* P0 HOTFIX: placeholder until /logs page is built */
|
||||||
label: "Rendszernaplók",
|
label: "Rendszernaplók",
|
||||||
icon: '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>'
|
icon: '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>'
|
||||||
}
|
}
|
||||||
@@ -286,4 +287,4 @@ _sfc_main.setup = (props, ctx) => {
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=default-DOjdWE8b.js.map
|
//# sourceMappingURL=default-C9mWt9Pc.js.map
|
||||||
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/default-C9mWt9Pc.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/default-C9mWt9Pc.js.map.json
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -98,11 +98,13 @@ const resource = {
|
|||||||
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garages CRM" } },
|
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garages CRM" } },
|
||||||
"subtitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garage list, package management and status changes" } },
|
"subtitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garage list, package management and status changes" } },
|
||||||
"total_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Total Garages" } },
|
"total_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Total Garages" } },
|
||||||
"active_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Active Garages" } },
|
"private_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Private Garages" } },
|
||||||
"premium_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Premium Garages" } },
|
"corporate_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Corporate Garages" } },
|
||||||
"enterprise_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Enterprise Garages" } },
|
|
||||||
"search_placeholder": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Search by name, contact or email..." } },
|
"search_placeholder": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Search by name, contact or email..." } },
|
||||||
"all_tiers": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "All packages" } },
|
"all_tiers": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "All packages" } },
|
||||||
|
"all_types": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "All types" } },
|
||||||
|
"type_individual": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Private (Individual)" } },
|
||||||
|
"type_corporate": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Corporate" } },
|
||||||
"company_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Company Name" } },
|
"company_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Company Name" } },
|
||||||
"email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Email" } },
|
"email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Email" } },
|
||||||
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Status" } },
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Status" } },
|
||||||
@@ -160,11 +162,139 @@ const resource = {
|
|||||||
"contact_department": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Department" } },
|
"contact_department": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Department" } },
|
||||||
"contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Phone" } },
|
"contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Phone" } },
|
||||||
"no_contact": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "No primary contact person" } },
|
"no_contact": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "No primary contact person" } },
|
||||||
"coming_soon": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "This feature will be available soon..." } }
|
"edit_details": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Edit Details" } },
|
||||||
|
"save": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Save" } },
|
||||||
|
"generalTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "General" } },
|
||||||
|
"employeesTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Employees" } },
|
||||||
|
"fleetTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Fleet" } },
|
||||||
|
"analyticsTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Analytics" } },
|
||||||
|
"subscriptionTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Subscription" } },
|
||||||
|
"editBasicTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Basic Info" } },
|
||||||
|
"editContactTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact" } },
|
||||||
|
"editAddressTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Addresses" } },
|
||||||
|
"zip": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "ZIP Code" } },
|
||||||
|
"city": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "City" } },
|
||||||
|
"street_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Street" } },
|
||||||
|
"street_type": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Street Type" } },
|
||||||
|
"house_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "House Number" } },
|
||||||
|
"coming_soon": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "This feature will be available soon..." } },
|
||||||
|
"missing_data_title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Missing Data" } },
|
||||||
|
"missing_data_desc": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "The garage profile is incomplete. Please fill in the missing fields." } },
|
||||||
|
"missing_data_activation_required": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "To activate the garage, the following data must be provided:" } },
|
||||||
|
"missing_tax_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Tax Number" } },
|
||||||
|
"missing_billing": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Billing Address" } },
|
||||||
|
"missing_contact_email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact Email" } },
|
||||||
|
"missing_contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact Phone" } },
|
||||||
|
"missing_data_count": { "t": 0, "b": { "t": 2, "i": [{ "t": 4, "k": "count" }, { "t": 3, "v": " fields missing" }] } },
|
||||||
|
"contact_person_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact Person Name" } },
|
||||||
|
"contact_email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact Email" } },
|
||||||
|
"contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact Phone" } },
|
||||||
|
"billing_address": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Billing Address" } },
|
||||||
|
"billing_zip": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "ZIP Code" } },
|
||||||
|
"billing_city": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "City" } },
|
||||||
|
"billing_street_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Street" } },
|
||||||
|
"billing_street_type": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Street Type" } },
|
||||||
|
"billing_house_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "House Number" } },
|
||||||
|
"notification_address": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Notification Address" } },
|
||||||
|
"notification_zip": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "ZIP Code" } },
|
||||||
|
"notification_city": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "City" } },
|
||||||
|
"notification_street_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Street" } },
|
||||||
|
"notification_street_type": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Street Type" } },
|
||||||
|
"notification_house_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "House Number" } },
|
||||||
|
"tab_basic": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Basic Info" } },
|
||||||
|
"tab_contact": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact" } },
|
||||||
|
"tab_addresses": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Addresses" } },
|
||||||
|
"basic_info": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Basic Info" } },
|
||||||
|
"contact_section": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Contact Person" } },
|
||||||
|
"addresses_section": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Addresses" } },
|
||||||
|
"vehicles_used": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Vehicles" } },
|
||||||
|
"branches_used": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Branches" } },
|
||||||
|
"employees_used": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Employees" } },
|
||||||
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Status" } },
|
||||||
|
"subscription_history": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Subscription History" } },
|
||||||
|
"history_date": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Date" } },
|
||||||
|
"history_package": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Package" } },
|
||||||
|
"history_action": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Action" } },
|
||||||
|
"history_status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Status" } },
|
||||||
|
"no_subscription_history": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "No subscription history yet." } }
|
||||||
|
},
|
||||||
|
"analytics": {
|
||||||
|
"ltv": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Lifetime Value (LTV)" } },
|
||||||
|
"mrr": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Monthly Revenue (MRR)" } },
|
||||||
|
"monthly_recurring": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Monthly recurring revenue" } },
|
||||||
|
"outstanding": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Outstanding" } },
|
||||||
|
"all_settled": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "All invoices settled" } },
|
||||||
|
"earned_credits": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Earned Credits" } },
|
||||||
|
"contribution_xp": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "XP earned from platform contributions" } },
|
||||||
|
"invited_companies": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Invited Companies" } },
|
||||||
|
"companies_joined": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Companies joined via your invite" } },
|
||||||
|
"validated_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Validated Garages" } },
|
||||||
|
"garages_confirmed": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garages successfully verified" } },
|
||||||
|
"utilization": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utilization" } },
|
||||||
|
"vehicle_quota": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Vehicle Quota" } },
|
||||||
|
"employee_quota": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Employee Quota" } },
|
||||||
|
"utilized": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "utilized" } },
|
||||||
|
"marketplace_engagement": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Marketplace & Engagement" } },
|
||||||
|
"avg_rating": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Average Rating" } },
|
||||||
|
"reviews": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Reviews" } },
|
||||||
|
"reviews_count": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "reviews" } },
|
||||||
|
"last_activity": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Last Activity" } },
|
||||||
|
"last_login_mock": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "2 hours ago" } },
|
||||||
|
"services_30d": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Services Completed (30 days)" } }
|
||||||
|
},
|
||||||
|
"employees": {
|
||||||
|
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Employees" } },
|
||||||
|
"total_count": { "t": 0, "b": { "t": 2, "i": [{ "t": 4, "k": "count" }, { "t": 3, "v": " employees" }] } },
|
||||||
|
"name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Name" } },
|
||||||
|
"email_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Email / Phone" } },
|
||||||
|
"role": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Role" } },
|
||||||
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Status" } },
|
||||||
|
"actions": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Actions" } },
|
||||||
|
"edit_role": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Edit" } },
|
||||||
|
"remove": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Remove" } },
|
||||||
|
"no_employees": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "No employees assigned to this garage." } },
|
||||||
|
"edit_role_title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Edit Employee Role" } },
|
||||||
|
"editRoleTitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Edit Employee Role" } },
|
||||||
|
"editRoleFor": { "t": 0, "b": { "t": 2, "i": [{ "t": 3, "v": "Change role for " }, { "t": 4, "k": "name" }] } },
|
||||||
|
"cancel": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Cancel" } },
|
||||||
|
"save": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Save Changes" } },
|
||||||
|
"saveRole": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Save Role" } },
|
||||||
|
"saving": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Saving..." } },
|
||||||
|
"status_active": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Active" } },
|
||||||
|
"status_inactive": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Inactive" } },
|
||||||
|
"remove_title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Remove Employee" } },
|
||||||
|
"removeTitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Remove Employee" } },
|
||||||
|
"remove_confirm": { "t": 0, "b": { "t": 2, "i": [{ "t": 3, "v": 'Are you sure you want to remove "' }, { "t": 4, "k": "name" }, { "t": 3, "v": '" from this garage?' }] } },
|
||||||
|
"removeConfirm": { "t": 0, "b": { "t": 2, "i": [{ "t": 3, "v": 'Are you sure you want to remove "' }, { "t": 4, "k": "name" }, { "t": 3, "v": '" from this garage?' }] } },
|
||||||
|
"remove_btn": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Remove" } },
|
||||||
|
"removing": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Removing..." } },
|
||||||
|
"add_employee": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Add Employee" } },
|
||||||
|
"addTitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Add New Employee" } },
|
||||||
|
"email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Email Address" } },
|
||||||
|
"emailPlaceholder": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Enter email address..." } },
|
||||||
|
"roleMember": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Member" } },
|
||||||
|
"roleManager": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Manager" } },
|
||||||
|
"roleAdmin": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Admin" } },
|
||||||
|
"roleOwner": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Owner" } },
|
||||||
|
"add": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Add Employee" } },
|
||||||
|
"adding": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Adding..." } }
|
||||||
|
},
|
||||||
|
"fleet": {
|
||||||
|
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Fleet" } },
|
||||||
|
"total_vehicles": { "t": 0, "b": { "t": 2, "i": [{ "t": 4, "k": "count" }, { "t": 3, "v": " vehicles total" }] } },
|
||||||
|
"plate": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Plate" } },
|
||||||
|
"brand": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Brand" } },
|
||||||
|
"model": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Model" } },
|
||||||
|
"brand_model": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Brand & Model" } },
|
||||||
|
"year": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Year" } },
|
||||||
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Status" } },
|
||||||
|
"vin": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "VIN" } },
|
||||||
|
"no_vehicles": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "No vehicles assigned to this garage yet." } },
|
||||||
|
"no_fleet_access": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "You don't have permission to view fleet data." } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export {
|
export {
|
||||||
resource as default
|
resource as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=en-WIj2pBfh.js.map
|
//# sourceMappingURL=en-BI6r-iRW.js.map
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/en-BI6r-iRW.js.map
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/en-BI6r-iRW.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"en-BI6r-iRW.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/en-BI6r-iRW.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/en-BI6r-iRW.js.map.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"file":"en-BI6r-iRW.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","names":[],"sources":[],"sourcesContent":[],"version":3}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"en-WIj2pBfh.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"file":"en-WIj2pBfh.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","names":[],"sources":[],"sourcesContent":[],"version":3}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"entry-styles-1.mjs-B2hfTmd6.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"file":"entry-styles-1.mjs-B2hfTmd6.js","mappings":";","names":[],"sources":[],"sourcesContent":[],"version":3}
|
|
||||||
5
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-1.mjs-Be0Mk_0H.js
vendored
Normal file
5
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-1.mjs-Be0Mk_0H.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-1.mjs-Be0Mk_0H.js.map
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-1.mjs-Be0Mk_0H.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"entry-styles-1.mjs-Be0Mk_0H.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-1.mjs-Be0Mk_0H.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-1.mjs-Be0Mk_0H.js.map.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"file":"entry-styles-1.mjs-Be0Mk_0H.js","mappings":";","names":[],"sources":[],"sourcesContent":[],"version":3}
|
||||||
5
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-2.mjs-CiZbT56B.js
vendored
Normal file
5
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-2.mjs-CiZbT56B.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-2.mjs-CiZbT56B.js.map
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-2.mjs-CiZbT56B.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"entry-styles-2.mjs-CiZbT56B.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-2.mjs-CiZbT56B.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles-2.mjs-CiZbT56B.js.map.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"file":"entry-styles-2.mjs-CiZbT56B.js","mappings":";","names":[],"sources":[],"sourcesContent":[],"version":3}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"entry-styles-2.mjs-rU9a7bNs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"file":"entry-styles-2.mjs-rU9a7bNs.js","mappings":";","names":[],"sources":[],"sourcesContent":[],"version":3}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import style_0 from "./entry-styles-1.mjs-B2hfTmd6.js";
|
|
||||||
import style_1 from "./entry-styles-2.mjs-rU9a7bNs.js";
|
|
||||||
import style_2 from "./entry-styles-3.mjs-C1rWf53M.js";
|
|
||||||
export default [
|
|
||||||
style_0,
|
|
||||||
style_1,
|
|
||||||
style_2
|
|
||||||
]
|
|
||||||
8
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles.DW_zlACo.mjs
vendored
Normal file
8
frontend_admin/.nuxt/dist/server/_nuxt/entry-styles.DW_zlACo.mjs
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import style_0 from "./entry-styles-1.mjs-Be0Mk_0H.js";
|
||||||
|
import style_1 from "./entry-styles-2.mjs-CiZbT56B.js";
|
||||||
|
import style_2 from "./entry-styles-3.mjs-C1rWf53M.js";
|
||||||
|
export default [
|
||||||
|
style_0,
|
||||||
|
style_1,
|
||||||
|
style_2
|
||||||
|
]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { _ as __nuxt_component_0 } from "./nuxt-link-Cp-CAJwR.js";
|
import { _ as __nuxt_component_0 } from "./nuxt-link-C5PnX__I.js";
|
||||||
import { mergeProps, withCtx, createTextVNode, toDisplayString, useSSRContext } from "vue";
|
import { mergeProps, withCtx, createTextVNode, toDisplayString, useSSRContext } from "vue";
|
||||||
import { ssrRenderAttrs, ssrInterpolate, ssrRenderComponent } from "vue/server-renderer";
|
import { ssrRenderAttrs, ssrInterpolate, ssrRenderComponent } from "vue/server-renderer";
|
||||||
import { _ as _export_sfc } from "./_plugin-vue_export-helper-1tPrXgE0.js";
|
import { _ as _export_sfc } from "./_plugin-vue_export-helper-1tPrXgE0.js";
|
||||||
@@ -94,4 +94,4 @@ const error404 = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-1
|
|||||||
export {
|
export {
|
||||||
error404 as default
|
error404 as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=error-404-Bkg5lg69.js.map
|
//# sourceMappingURL=error-404-DPt4byml.js.map
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"hu-B3JxlqZo.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"file":"hu-B3JxlqZo.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","names":[],"sources":[],"sourcesContent":[],"version":3}
|
|
||||||
@@ -98,11 +98,13 @@ const resource = {
|
|||||||
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garázsok CRM" } },
|
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garázsok CRM" } },
|
||||||
"subtitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garázsok listája, csomagkezelés és státuszmódosítás" } },
|
"subtitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garázsok listája, csomagkezelés és státuszmódosítás" } },
|
||||||
"total_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Összes Garázs" } },
|
"total_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Összes Garázs" } },
|
||||||
"active_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Aktív Garázsok" } },
|
"private_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Privát Garázsok" } },
|
||||||
"premium_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Premium Garázsok" } },
|
"corporate_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Céges Garázsok" } },
|
||||||
"enterprise_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Enterprise Garázsok" } },
|
|
||||||
"search_placeholder": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Keresés név, kapcsolattartó vagy e-mail alapján..." } },
|
"search_placeholder": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Keresés név, kapcsolattartó vagy e-mail alapján..." } },
|
||||||
"all_tiers": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Összes csomag" } },
|
"all_tiers": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Összes csomag" } },
|
||||||
|
"all_types": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Összes típus" } },
|
||||||
|
"type_individual": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Privát (Egyéni)" } },
|
||||||
|
"type_corporate": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Céges (Vállalati)" } },
|
||||||
"company_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Cégnév" } },
|
"company_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Cégnév" } },
|
||||||
"email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "E-mail" } },
|
"email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "E-mail" } },
|
||||||
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Státusz" } },
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Státusz" } },
|
||||||
@@ -160,11 +162,139 @@ const resource = {
|
|||||||
"contact_department": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Osztály" } },
|
"contact_department": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Osztály" } },
|
||||||
"contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Telefonszám" } },
|
"contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Telefonszám" } },
|
||||||
"no_contact": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Nincs elsődleges kapcsolattartó" } },
|
"no_contact": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Nincs elsődleges kapcsolattartó" } },
|
||||||
"coming_soon": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Ez a funkció hamarosan elérhető lesz..." } }
|
"edit_details": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Adatok Szerkesztése" } },
|
||||||
|
"save": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Mentés" } },
|
||||||
|
"generalTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Általános" } },
|
||||||
|
"employeesTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Dolgozók" } },
|
||||||
|
"fleetTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Flotta" } },
|
||||||
|
"analyticsTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Analitika" } },
|
||||||
|
"subscriptionTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Előfizetés" } },
|
||||||
|
"editBasicTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Alapadatok" } },
|
||||||
|
"editContactTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolat" } },
|
||||||
|
"editAddressTab": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Címek" } },
|
||||||
|
"zip": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Irányítószám" } },
|
||||||
|
"city": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Város" } },
|
||||||
|
"street_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utca" } },
|
||||||
|
"street_type": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utca típusa" } },
|
||||||
|
"house_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Házszám" } },
|
||||||
|
"coming_soon": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Ez a funkció hamarosan elérhető lesz..." } },
|
||||||
|
"missing_data_title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Hiányzó adatok" } },
|
||||||
|
"missing_data_desc": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "A garázs profilja hiányos. Kérjük, egészítse ki a hiányzó adatokat." } },
|
||||||
|
"missing_data_activation_required": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "A garázs aktiválásához az alábbi adatok pótlása kötelező:" } },
|
||||||
|
"missing_tax_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Adószám" } },
|
||||||
|
"missing_billing": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Számlázási cím" } },
|
||||||
|
"missing_contact_email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolattartó e-mail" } },
|
||||||
|
"missing_contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolattartó telefon" } },
|
||||||
|
"missing_data_count": { "t": 0, "b": { "t": 2, "i": [{ "t": 4, "k": "count" }, { "t": 3, "v": " mező hiányzik" }] } },
|
||||||
|
"contact_person_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolattartó neve" } },
|
||||||
|
"contact_email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolattartó e-mail" } },
|
||||||
|
"contact_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolattartó telefon" } },
|
||||||
|
"billing_address": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Számlázási cím" } },
|
||||||
|
"billing_zip": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Irányítószám" } },
|
||||||
|
"billing_city": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Város" } },
|
||||||
|
"billing_street_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utca" } },
|
||||||
|
"billing_street_type": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utca típusa" } },
|
||||||
|
"billing_house_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Házszám" } },
|
||||||
|
"notification_address": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Értesítési cím" } },
|
||||||
|
"notification_zip": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Irányítószám" } },
|
||||||
|
"notification_city": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Város" } },
|
||||||
|
"notification_street_name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utca" } },
|
||||||
|
"notification_street_type": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utca típusa" } },
|
||||||
|
"notification_house_number": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Házszám" } },
|
||||||
|
"tab_basic": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Alapadatok" } },
|
||||||
|
"tab_contact": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolat" } },
|
||||||
|
"tab_addresses": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Címek" } },
|
||||||
|
"basic_info": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Alapadatok" } },
|
||||||
|
"contact_section": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kapcsolattartó" } },
|
||||||
|
"addresses_section": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Címek" } },
|
||||||
|
"vehicles_used": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Járművek" } },
|
||||||
|
"branches_used": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Telephelyek" } },
|
||||||
|
"employees_used": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Dolgozók" } },
|
||||||
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Státusz" } },
|
||||||
|
"subscription_history": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Előfizetési Előzmények" } },
|
||||||
|
"history_date": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Dátum" } },
|
||||||
|
"history_package": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Csomag" } },
|
||||||
|
"history_action": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Művelet" } },
|
||||||
|
"history_status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Státusz" } },
|
||||||
|
"no_subscription_history": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Még nincsenek előfizetési előzmények." } }
|
||||||
|
},
|
||||||
|
"analytics": {
|
||||||
|
"ltv": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Élettartam Érték (LTV)" } },
|
||||||
|
"mrr": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Havi Bevétel (MRR)" } },
|
||||||
|
"monthly_recurring": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Havi ismétlődő bevétel" } },
|
||||||
|
"outstanding": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kintlévőség" } },
|
||||||
|
"all_settled": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Minden számla rendezve" } },
|
||||||
|
"earned_credits": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Szerzett Kreditek" } },
|
||||||
|
"contribution_xp": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Platform építésével gyűjtött XP" } },
|
||||||
|
"invited_companies": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Meghívott Cégek" } },
|
||||||
|
"companies_joined": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Cég csatlakozott a meghívásodra" } },
|
||||||
|
"validated_garages": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Validált Garázsok" } },
|
||||||
|
"garages_confirmed": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Garázs sikeresen hitelesítve" } },
|
||||||
|
"utilization": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Kihasználtság" } },
|
||||||
|
"vehicle_quota": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Jármű Kvóta" } },
|
||||||
|
"employee_quota": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Alkalmazotti Kvóta" } },
|
||||||
|
"utilized": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "kihasználva" } },
|
||||||
|
"marketplace_engagement": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Piactér & Aktivitás" } },
|
||||||
|
"avg_rating": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Átlagos Értékelés" } },
|
||||||
|
"reviews": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Értékelések" } },
|
||||||
|
"reviews_count": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "értékelés" } },
|
||||||
|
"last_activity": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Utolsó Aktivitás" } },
|
||||||
|
"last_login_mock": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "2 órája" } },
|
||||||
|
"services_30d": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Elvégzett Szervizek (30 nap)" } }
|
||||||
|
},
|
||||||
|
"employees": {
|
||||||
|
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Dolgozók" } },
|
||||||
|
"total_count": { "t": 0, "b": { "t": 2, "i": [{ "t": 3, "v": "Összesen " }, { "t": 4, "k": "count" }, { "t": 3, "v": " fő" }] } },
|
||||||
|
"name": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Név" } },
|
||||||
|
"email_phone": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "E-mail / Telefon" } },
|
||||||
|
"role": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Szerepkör" } },
|
||||||
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Státusz" } },
|
||||||
|
"actions": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Műveletek" } },
|
||||||
|
"edit_role": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Szerepkör szerkesztése" } },
|
||||||
|
"remove": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Eltávolítás" } },
|
||||||
|
"no_employees": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Még nincsenek tagok ehhez a garázshoz." } },
|
||||||
|
"edit_role_title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Tag szerepkörének szerkesztése" } },
|
||||||
|
"editRoleTitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Tag szerepkörének szerkesztése" } },
|
||||||
|
"editRoleFor": { "t": 0, "b": { "t": 2, "i": [{ "t": 4, "k": "name" }, { "t": 3, "v": " szerepkörének módosítása" }] } },
|
||||||
|
"cancel": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Mégse" } },
|
||||||
|
"save": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Mentés" } },
|
||||||
|
"saveRole": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Szerepkör mentése" } },
|
||||||
|
"saving": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Mentés..." } },
|
||||||
|
"status_active": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Aktív" } },
|
||||||
|
"status_inactive": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Inaktív" } },
|
||||||
|
"remove_title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Tag eltávolítása" } },
|
||||||
|
"removeTitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Tag eltávolítása" } },
|
||||||
|
"remove_confirm": { "t": 0, "b": { "t": 2, "i": [{ "t": 3, "v": "Biztosan eltávolítod " }, { "t": 4, "k": "name" }, { "t": 3, "v": " tagot a garázsból?" }] } },
|
||||||
|
"removeConfirm": { "t": 0, "b": { "t": 2, "i": [{ "t": 3, "v": "Biztosan eltávolítod " }, { "t": 4, "k": "name" }, { "t": 3, "v": " tagot a garázsból?" }] } },
|
||||||
|
"remove_btn": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Eltávolítás" } },
|
||||||
|
"removing": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Eltávolítás..." } },
|
||||||
|
"add_employee": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Új dolgozó hozzáadása" } },
|
||||||
|
"addTitle": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Új dolgozó hozzáadása" } },
|
||||||
|
"email": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "E-mail cím" } },
|
||||||
|
"emailPlaceholder": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Add meg az e-mail címet..." } },
|
||||||
|
"roleMember": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Tag" } },
|
||||||
|
"roleManager": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Menedzser" } },
|
||||||
|
"roleAdmin": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Admin" } },
|
||||||
|
"roleOwner": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Tulajdonos" } },
|
||||||
|
"add": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Hozzáadás" } },
|
||||||
|
"adding": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Hozzáadás..." } }
|
||||||
|
},
|
||||||
|
"fleet": {
|
||||||
|
"title": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Flotta" } },
|
||||||
|
"total_vehicles": { "t": 0, "b": { "t": 2, "i": [{ "t": 3, "v": "Összesen " }, { "t": 4, "k": "count" }, { "t": 3, "v": " jármű" }] } },
|
||||||
|
"plate": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Rendszám" } },
|
||||||
|
"brand": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Márka" } },
|
||||||
|
"model": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Modell" } },
|
||||||
|
"brand_model": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Márka & Modell" } },
|
||||||
|
"year": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Évjárat" } },
|
||||||
|
"status": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Státusz" } },
|
||||||
|
"vin": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Alvázszám" } },
|
||||||
|
"no_vehicles": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Ehhez a garázshoz még nincsenek járművek rendelve." } },
|
||||||
|
"no_fleet_access": { "t": 0, "b": { "t": 2, "i": [{ "t": 3 }], "s": "Nincs jogosultságod a flotta adatok megtekintéséhez." } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export {
|
export {
|
||||||
resource as default
|
resource as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=hu-B3JxlqZo.js.map
|
//# sourceMappingURL=hu-Ck1VzT5S.js.map
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/hu-Ck1VzT5S.js.map
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/hu-Ck1VzT5S.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"hu-Ck1VzT5S.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/hu-Ck1VzT5S.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/hu-Ck1VzT5S.js.map.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"file":"hu-Ck1VzT5S.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","names":[],"sources":[],"sourcesContent":[],"version":3}
|
||||||
695
frontend_admin/.nuxt/dist/server/_nuxt/index-1I7UC9HP.js
vendored
Normal file
695
frontend_admin/.nuxt/dist/server/_nuxt/index-1I7UC9HP.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/index-1I7UC9HP.js.map
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/index-1I7UC9HP.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/index-1I7UC9HP.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/index-1I7UC9HP.js.map.json
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/index-CzKBE-M2.js.map
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/index-CzKBE-M2.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/index-CzKBE-M2.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/index-CzKBE-M2.js.map.json
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@ import { defineComponent, ref, computed, unref, useSSRContext } from "vue";
|
|||||||
import { ssrRenderAttrs, ssrInterpolate, ssrRenderClass, ssrRenderList, ssrIncludeBooleanAttr, ssrRenderAttr } from "vue/server-renderer";
|
import { ssrRenderAttrs, ssrInterpolate, ssrRenderClass, ssrRenderList, ssrIncludeBooleanAttr, ssrRenderAttr } from "vue/server-renderer";
|
||||||
import "/app/node_modules/hookable/dist/index.mjs";
|
import "/app/node_modules/hookable/dist/index.mjs";
|
||||||
import "/app/node_modules/klona/dist/index.mjs";
|
import "/app/node_modules/klona/dist/index.mjs";
|
||||||
import { b as useI18n } from "../server.mjs";
|
import { d as useI18n } from "../server.mjs";
|
||||||
import "/app/node_modules/ofetch/dist/node.mjs";
|
import "/app/node_modules/ofetch/dist/node.mjs";
|
||||||
import "#internal/nuxt/paths";
|
import "#internal/nuxt/paths";
|
||||||
import "/app/node_modules/unctx/dist/index.mjs";
|
import "/app/node_modules/unctx/dist/index.mjs";
|
||||||
@@ -79,13 +79,30 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
return colorMap[domain] || "text-slate-400";
|
return colorMap[domain] || "text-slate-400";
|
||||||
}
|
}
|
||||||
function getCellClass(role, perm) {
|
function getCellClass(role, perm) {
|
||||||
if (isRoleLocked(role)) return "bg-purple-900/5";
|
if (isRoleLocked(role)) {
|
||||||
|
return isPermEnabled(role.id, perm.id) ? "bg-purple-900/10" : "bg-purple-900/5";
|
||||||
|
}
|
||||||
if (isPermEnabled(role.id, perm.id)) return "bg-emerald-900/10";
|
if (isPermEnabled(role.id, perm.id)) return "bg-emerald-900/10";
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
function formatPermissionLabel(perm) {
|
function formatPermissionLabel(perm) {
|
||||||
return perm.code.replace(/:/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
return perm.code.replace(/:/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
||||||
}
|
}
|
||||||
|
function getToggleClass(role, perm) {
|
||||||
|
const enabled = isPermEnabled(role.id, perm.id);
|
||||||
|
const locked = isRoleLocked(role);
|
||||||
|
const baseClasses = "peer-focus:outline-none peer-focus:ring-2";
|
||||||
|
if (locked) {
|
||||||
|
if (enabled) {
|
||||||
|
return `${baseClasses} bg-emerald-600 peer-focus:ring-emerald-500/50 after:translate-x-full after:border-white`;
|
||||||
|
}
|
||||||
|
return `${baseClasses} bg-slate-600`;
|
||||||
|
}
|
||||||
|
if (enabled) {
|
||||||
|
return `${baseClasses} bg-emerald-600 peer-focus:ring-emerald-500/50 peer-checked:after:translate-x-full peer-checked:after:border-white`;
|
||||||
|
}
|
||||||
|
return `${baseClasses} bg-slate-600 peer-focus:ring-indigo-500/50 peer-checked:after:translate-x-full peer-checked:after:border-white peer-checked:bg-indigo-600`;
|
||||||
|
}
|
||||||
function getDomainPermissions(domain) {
|
function getDomainPermissions(domain) {
|
||||||
return filteredPermissions.value.filter((p) => p.domain === domain);
|
return filteredPermissions.value.filter((p) => p.domain === domain);
|
||||||
}
|
}
|
||||||
@@ -159,7 +176,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
}
|
}
|
||||||
_push(`</div></td><!--[-->`);
|
_push(`</div></td><!--[-->`);
|
||||||
ssrRenderList(filteredRoles.value, (role) => {
|
ssrRenderList(filteredRoles.value, (role) => {
|
||||||
_push(`<td class="${ssrRenderClass([getCellClass(role, perm), "p-3 text-center border-l border-slate-700/30"])}"><label class="${ssrRenderClass([{ "cursor-not-allowed opacity-40": isRoleLocked(role) }, "relative inline-flex items-center justify-center cursor-pointer"])}"><input type="checkbox"${ssrIncludeBooleanAttr(isPermEnabled(role.id, perm.id)) ? " checked" : ""} class="sr-only peer"${ssrIncludeBooleanAttr(isRoleLocked(role)) ? " disabled" : ""}><div class="${ssrRenderClass([isRoleLocked(role) ? "bg-slate-600" : isPermEnabled(role.id, perm.id) ? "bg-emerald-600 peer-focus:ring-emerald-500/50 peer-checked:after:translate-x-full peer-checked:after:border-white" : "bg-slate-600 peer-focus:ring-indigo-500/50 peer-checked:after:translate-x-full peer-checked:after:border-white peer-checked:bg-indigo-600", "w-9 h-5 rounded-full peer peer-focus:outline-none peer-focus:ring-2 transition-all after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all"])}"></div></label></td>`);
|
_push(`<td class="${ssrRenderClass([getCellClass(role, perm), "p-3 text-center border-l border-slate-700/30"])}"><label class="${ssrRenderClass([isRoleLocked(role) ? "cursor-not-allowed" : "cursor-pointer", "relative inline-flex items-center justify-center"])}"><input type="checkbox"${ssrIncludeBooleanAttr(isPermEnabled(role.id, perm.id)) ? " checked" : ""} class="sr-only peer"${ssrIncludeBooleanAttr(isRoleLocked(role)) ? " disabled" : ""}><div class="${ssrRenderClass([getToggleClass(role, perm), "w-9 h-5 rounded-full transition-all duration-200 after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all after:duration-200"])}"></div></label></td>`);
|
||||||
});
|
});
|
||||||
_push(`<!--]--></tr>`);
|
_push(`<!--]--></tr>`);
|
||||||
});
|
});
|
||||||
@@ -192,4 +209,4 @@ _sfc_main.setup = (props, ctx) => {
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=index-D2n0yf-2.js.map
|
//# sourceMappingURL=index-DgwDY6Ie.js.map
|
||||||
1
frontend_admin/.nuxt/dist/server/_nuxt/index-DgwDY6Ie.js.map
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/index-DgwDY6Ie.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/index-DgwDY6Ie.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/index-DgwDY6Ie.js.map.json
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,182 +0,0 @@
|
|||||||
import { defineComponent, ref, computed, useSSRContext } from "vue";
|
|
||||||
import { ssrRenderAttrs, ssrInterpolate, ssrRenderClass, ssrRenderList } from "vue/server-renderer";
|
|
||||||
import { useRoute, useRouter } from "vue-router";
|
|
||||||
import "/app/node_modules/hookable/dist/index.mjs";
|
|
||||||
import "/app/node_modules/klona/dist/index.mjs";
|
|
||||||
import "../server.mjs";
|
|
||||||
import "/app/node_modules/ofetch/dist/node.mjs";
|
|
||||||
import "#internal/nuxt/paths";
|
|
||||||
import "/app/node_modules/unctx/dist/index.mjs";
|
|
||||||
import "/app/node_modules/h3/dist/index.mjs";
|
|
||||||
import "pinia";
|
|
||||||
import "/app/node_modules/defu/dist/defu.mjs";
|
|
||||||
import "/app/node_modules/ufo/dist/index.mjs";
|
|
||||||
import "/app/node_modules/cookie-es/dist/index.mjs";
|
|
||||||
import "/app/node_modules/destr/dist/index.mjs";
|
|
||||||
import "/app/node_modules/ohash/dist/index.mjs";
|
|
||||||
import "/app/node_modules/@unhead/vue/dist/index.mjs";
|
|
||||||
import "@vue/devtools-api";
|
|
||||||
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
||||||
__name: "index",
|
|
||||||
__ssrInlineRender: true,
|
|
||||||
setup(__props) {
|
|
||||||
useRoute();
|
|
||||||
useRouter();
|
|
||||||
const loading = ref(true);
|
|
||||||
const error = ref(null);
|
|
||||||
const garage = ref(null);
|
|
||||||
const activeTab = ref("general");
|
|
||||||
const tabs = [
|
|
||||||
{ key: "general", label: "Általános" },
|
|
||||||
{ key: "employees", label: "Dolgozók" },
|
|
||||||
{ key: "fleet", label: "Flotta" },
|
|
||||||
{ key: "analytics", label: "Analitika" }
|
|
||||||
];
|
|
||||||
const formattedAddress = computed(() => {
|
|
||||||
if (!garage.value) return "—";
|
|
||||||
const parts = [];
|
|
||||||
if (garage.value.address_zip) parts.push(garage.value.address_zip);
|
|
||||||
if (garage.value.address_city) parts.push(garage.value.address_city);
|
|
||||||
const streetParts = [];
|
|
||||||
if (garage.value.address_street_name) streetParts.push(garage.value.address_street_name);
|
|
||||||
if (garage.value.address_street_type) streetParts.push(garage.value.address_street_type);
|
|
||||||
if (garage.value.address_house_number) streetParts.push(garage.value.address_house_number);
|
|
||||||
if (streetParts.length > 0) parts.push(streetParts.join(" "));
|
|
||||||
return parts.length > 0 ? parts.join(", ") : "—";
|
|
||||||
});
|
|
||||||
function garageDisplayName(g) {
|
|
||||||
return g.display_name || g.name || g.full_name;
|
|
||||||
}
|
|
||||||
function getInitials(name) {
|
|
||||||
return name.split(" ").map((w) => w.charAt(0)).join("").toUpperCase().slice(0, 2);
|
|
||||||
}
|
|
||||||
function getInitialsColor(name) {
|
|
||||||
const colors = [
|
|
||||||
"bg-amber-600",
|
|
||||||
"bg-purple-600",
|
|
||||||
"bg-slate-600",
|
|
||||||
"bg-indigo-600",
|
|
||||||
"bg-emerald-600",
|
|
||||||
"bg-rose-600",
|
|
||||||
"bg-cyan-600",
|
|
||||||
"bg-orange-600",
|
|
||||||
"bg-teal-600"
|
|
||||||
];
|
|
||||||
let hash = 0;
|
|
||||||
for (let i = 0; i < name.length; i++) {
|
|
||||||
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
|
||||||
}
|
|
||||||
return colors[Math.abs(hash) % colors.length];
|
|
||||||
}
|
|
||||||
function statusBadgeClass(status) {
|
|
||||||
if (status === "active") return "bg-emerald-500/10 text-emerald-400";
|
|
||||||
if (status === "suspended") return "bg-red-500/10 text-red-400";
|
|
||||||
if (status === "pending_verification") return "bg-amber-500/10 text-amber-400";
|
|
||||||
return "bg-slate-500/10 text-slate-400";
|
|
||||||
}
|
|
||||||
function statusDotClass(status) {
|
|
||||||
if (status === "active") return "bg-emerald-400";
|
|
||||||
if (status === "suspended") return "bg-red-400";
|
|
||||||
if (status === "pending_verification") return "bg-amber-400";
|
|
||||||
return "bg-slate-400";
|
|
||||||
}
|
|
||||||
function statusLabel(status) {
|
|
||||||
if (status === "active") return "Aktív";
|
|
||||||
if (status === "suspended") return "Felfüggesztve";
|
|
||||||
if (status === "pending_verification") return "Függőben";
|
|
||||||
return "Inaktív";
|
|
||||||
}
|
|
||||||
function tierBadgeClass(tierName) {
|
|
||||||
const name = tierName.toLowerCase();
|
|
||||||
if (name.includes("enterprise") || name.includes("vip") || name.includes("corp")) return "bg-purple-500/20 text-purple-300";
|
|
||||||
if (name.includes("premium") || name.includes("pro")) return "bg-amber-500/20 text-amber-300";
|
|
||||||
return "bg-slate-500/20 text-slate-300";
|
|
||||||
}
|
|
||||||
function orgTypeLabel(type) {
|
|
||||||
const labels = {
|
|
||||||
individual: "Magánszemély",
|
|
||||||
service: "Szerviz",
|
|
||||||
service_provider: "Szolgáltató",
|
|
||||||
fleet_owner: "Flottatulajdonos",
|
|
||||||
club: "Klub",
|
|
||||||
business: "Vállalkozás"
|
|
||||||
};
|
|
||||||
return labels[type] || type;
|
|
||||||
}
|
|
||||||
function formatDate(dateStr) {
|
|
||||||
if (!dateStr) return "—";
|
|
||||||
try {
|
|
||||||
const d = new Date(dateStr);
|
|
||||||
return d.toLocaleDateString("hu-HU", {
|
|
||||||
year: "numeric",
|
|
||||||
month: "short",
|
|
||||||
day: "numeric"
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
return dateStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (_ctx, _push, _parent, _attrs) => {
|
|
||||||
_push(`<div${ssrRenderAttrs(_attrs)}>`);
|
|
||||||
if (loading.value) {
|
|
||||||
_push(`<div class="flex items-center justify-center py-20"><div class="flex flex-col items-center gap-3"><svg class="w-8 h-8 text-indigo-400 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg><p class="text-slate-400 text-sm">${ssrInterpolate(_ctx.$t("garages.details.loading"))}</p></div></div>`);
|
|
||||||
} else if (error.value) {
|
|
||||||
_push(`<div class="flex flex-col items-center justify-center py-20 text-center"><svg class="w-12 h-12 text-red-500 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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"></path></svg><p class="text-red-400 text-sm mb-2">${ssrInterpolate(error.value)}</p><button class="px-4 py-2 text-sm bg-indigo-600/20 text-indigo-300 hover:bg-indigo-600/30 rounded-lg transition">${ssrInterpolate(_ctx.$t("garages.details.retry"))}</button></div>`);
|
|
||||||
} else if (garage.value) {
|
|
||||||
_push(`<!--[--><div class="mb-8"><button class="inline-flex items-center gap-1.5 text-sm text-slate-400 hover:text-white transition mb-4"><svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg> ${ssrInterpolate(_ctx.$t("garages.details.back"))}</button><div class="flex items-center justify-between"><div class="flex items-center gap-4"><div class="${ssrRenderClass([getInitialsColor(garageDisplayName(garage.value)), "w-12 h-12 rounded-xl flex items-center justify-center text-lg font-bold text-white"])}">${ssrInterpolate(getInitials(garageDisplayName(garage.value)))}</div><div><h1 class="text-2xl font-bold text-white">${ssrInterpolate(garageDisplayName(garage.value))}</h1><p class="text-sm text-slate-400 mt-0.5">${ssrInterpolate(garage.value.full_name)} `);
|
|
||||||
if (garage.value.tax_number) {
|
|
||||||
_push(`<span class="ml-2 text-slate-500">· ${ssrInterpolate(_ctx.$t("garages.details.tax_number"))}: ${ssrInterpolate(garage.value.tax_number)}</span>`);
|
|
||||||
} else {
|
|
||||||
_push(`<!---->`);
|
|
||||||
}
|
|
||||||
_push(`</p></div></div><span class="${ssrRenderClass([statusBadgeClass(garage.value.status), "inline-flex items-center px-3 py-1 rounded-full text-xs font-medium"])}"><span class="${ssrRenderClass([statusDotClass(garage.value.status), "w-1.5 h-1.5 rounded-full mr-1.5"])}"></span> ${ssrInterpolate(statusLabel(garage.value.status))}</span></div></div><div class="border-b border-slate-700 mb-6"><nav class="flex gap-6"><!--[-->`);
|
|
||||||
ssrRenderList(tabs, (tab) => {
|
|
||||||
_push(`<button class="${ssrRenderClass([activeTab.value === tab.key ? "text-indigo-400 border-indigo-400" : "text-slate-400 border-transparent hover:text-slate-300", "pb-3 text-sm font-medium transition border-b-2 -mb-px"])}">${ssrInterpolate(tab.label)}</button>`);
|
|
||||||
});
|
|
||||||
_push(`<!--]--></nav></div>`);
|
|
||||||
if (activeTab.value === "general") {
|
|
||||||
_push(`<div class="space-y-6"><div class="bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden"><div class="px-6 py-4 border-b border-slate-700 flex items-center gap-3"><div class="p-2 rounded-lg bg-indigo-500/10 text-indigo-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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"></path></svg></div><h3 class="text-base font-semibold text-white">${ssrInterpolate(_ctx.$t("garages.details.company_info"))}</h3></div><div class="px-6 py-5"><div class="grid grid-cols-1 md:grid-cols-2 gap-6"><div class="space-y-4"><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.company_name"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.full_name)}</p></div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.display_name"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.display_name || "—")}</p></div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.org_type"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(orgTypeLabel(garage.value.org_type))}</p></div></div><div class="space-y-4"><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.tax_number"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.tax_number || "—")}</p></div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.reg_number"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.reg_number || "—")}</p></div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.created_at"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(formatDate(garage.value.created_at))}</p></div></div></div><div class="mt-6 pt-6 border-t border-slate-700/50"><p class="text-xs text-slate-500 uppercase tracking-wider mb-3">${ssrInterpolate(_ctx.$t("garages.details.address"))}</p><p class="text-sm text-white">${ssrInterpolate(formattedAddress.value)}</p></div></div></div><div class="bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden"><div class="px-6 py-4 border-b border-slate-700 flex items-center gap-3"><div class="p-2 rounded-lg bg-amber-500/10 text-amber-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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"></path></svg></div><h3 class="text-base font-semibold text-white">${ssrInterpolate(_ctx.$t("garages.details.subscription_info"))}</h3></div><div class="px-6 py-5">`);
|
|
||||||
if (garage.value.subscription) {
|
|
||||||
_push(`<div class="grid grid-cols-1 md:grid-cols-2 gap-6"><div class="space-y-4"><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.tier_name"))}</p><span class="${ssrRenderClass([tierBadgeClass(garage.value.subscription.tier_name), "inline-flex mt-1 px-2.5 py-0.5 rounded-full text-xs font-medium"])}">${ssrInterpolate(garage.value.subscription.tier_name)}</span></div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.tier_level"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(_ctx.$t("garages.details.level_n", { n: garage.value.subscription.tier_level }))}</p></div></div><div class="space-y-4"><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.expires_at"))}</p>`);
|
|
||||||
if (garage.value.subscription.expires_at) {
|
|
||||||
_push(`<p class="text-sm text-white mt-1">${ssrInterpolate(formatDate(garage.value.subscription.expires_at))}</p>`);
|
|
||||||
} else {
|
|
||||||
_push(`<p class="text-sm text-slate-400 mt-1 italic">${ssrInterpolate(_ctx.$t("garages.indefinite"))}</p>`);
|
|
||||||
}
|
|
||||||
_push(`</div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.asset_limit"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.subscription.asset_limit)} ${ssrInterpolate(_ctx.$t("garages.details.vehicles"))}</p></div></div></div>`);
|
|
||||||
} else {
|
|
||||||
_push(`<div class="text-center py-4"><p class="text-sm text-slate-400">${ssrInterpolate(_ctx.$t("garages.details.no_subscription"))}</p></div>`);
|
|
||||||
}
|
|
||||||
_push(`</div></div><div class="bg-slate-800/50 border border-slate-700 rounded-xl overflow-hidden"><div class="px-6 py-4 border-b border-slate-700 flex items-center gap-3"><div class="p-2 rounded-lg bg-emerald-500/10 text-emerald-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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"></path></svg></div><h3 class="text-base font-semibold text-white">${ssrInterpolate(_ctx.$t("garages.details.contact_info"))}</h3></div><div class="px-6 py-5">`);
|
|
||||||
if (garage.value.primary_contact) {
|
|
||||||
_push(`<div class="grid grid-cols-1 md:grid-cols-2 gap-6"><div class="space-y-4"><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.contact_name"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.primary_contact.full_name)}</p></div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.contact_role"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.primary_contact.role)}</p></div></div><div class="space-y-4"><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.contact_department"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.primary_contact.department || "—")}</p></div><div><p class="text-xs text-slate-500 uppercase tracking-wider">${ssrInterpolate(_ctx.$t("garages.details.contact_phone"))}</p><p class="text-sm text-white mt-1">${ssrInterpolate(garage.value.primary_contact.phone || "—")}</p></div></div></div>`);
|
|
||||||
} else {
|
|
||||||
_push(`<div class="text-center py-4"><p class="text-sm text-slate-400">${ssrInterpolate(_ctx.$t("garages.details.no_contact"))}</p></div>`);
|
|
||||||
}
|
|
||||||
_push(`</div></div></div>`);
|
|
||||||
} else {
|
|
||||||
_push(`<!---->`);
|
|
||||||
}
|
|
||||||
if (activeTab.value !== "general") {
|
|
||||||
_push(`<div class="flex items-center justify-center py-20"><p class="text-slate-500 text-sm">${ssrInterpolate(_ctx.$t("garages.details.coming_soon"))}</p></div>`);
|
|
||||||
} else {
|
|
||||||
_push(`<!---->`);
|
|
||||||
}
|
|
||||||
_push(`<!--]-->`);
|
|
||||||
} else {
|
|
||||||
_push(`<!---->`);
|
|
||||||
}
|
|
||||||
_push(`</div>`);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const _sfc_setup = _sfc_main.setup;
|
|
||||||
_sfc_main.setup = (props, ctx) => {
|
|
||||||
const ssrContext = useSSRContext();
|
|
||||||
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/garages/[id]/index.vue");
|
|
||||||
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
|
|
||||||
};
|
|
||||||
export {
|
|
||||||
_sfc_main as default
|
|
||||||
};
|
|
||||||
//# sourceMappingURL=index-JpXwtL-Z.js.map
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,10 +1,9 @@
|
|||||||
import { _ as __nuxt_component_0 } from "./nuxt-link-Cp-CAJwR.js";
|
import { _ as __nuxt_component_0 } from "./nuxt-link-C5PnX__I.js";
|
||||||
import { defineComponent, ref, mergeProps, unref, withCtx, createTextVNode, useSSRContext } from "vue";
|
import { defineComponent, ref, mergeProps, unref, withCtx, createTextVNode, useSSRContext } from "vue";
|
||||||
import { ssrRenderAttrs, ssrRenderAttr, ssrInterpolate, ssrIncludeBooleanAttr, ssrRenderComponent } from "vue/server-renderer";
|
import { ssrRenderAttrs, ssrRenderAttr, ssrInterpolate, ssrIncludeBooleanAttr, ssrRenderComponent } from "vue/server-renderer";
|
||||||
import { publicAssetsURL } from "#internal/nuxt/paths";
|
import { publicAssetsURL } from "#internal/nuxt/paths";
|
||||||
import "/app/node_modules/hookable/dist/index.mjs";
|
import "/app/node_modules/hookable/dist/index.mjs";
|
||||||
import { a as useRouter } from "../server.mjs";
|
import { a as useRouter, b as useAuthStore } from "../server.mjs";
|
||||||
import { u as useAuthStore } from "./auth-RwMj9LdV.js";
|
|
||||||
import "/app/node_modules/ufo/dist/index.mjs";
|
import "/app/node_modules/ufo/dist/index.mjs";
|
||||||
import "/app/node_modules/defu/dist/defu.mjs";
|
import "/app/node_modules/defu/dist/defu.mjs";
|
||||||
import "/app/node_modules/ofetch/dist/node.mjs";
|
import "/app/node_modules/ofetch/dist/node.mjs";
|
||||||
@@ -70,4 +69,4 @@ _sfc_main.setup = (props, ctx) => {
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=login-Dx4mHuUH.js.map
|
//# sourceMappingURL=login-DOiXgKDi.js.map
|
||||||
File diff suppressed because one or more lines are too long
1
frontend_admin/.nuxt/dist/server/_nuxt/login-DOiXgKDi.js.map.json
vendored
Normal file
1
frontend_admin/.nuxt/dist/server/_nuxt/login-DOiXgKDi.js.map.json
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
|||||||
import { defineComponent, shallowRef, h, resolveComponent, computed, unref } from "vue";
|
import { defineComponent, shallowRef, h, resolveComponent, computed, unref } from "vue";
|
||||||
import { parseQuery, hasProtocol, joinURL, isScriptProtocol, withTrailingSlash, withoutTrailingSlash } from "/app/node_modules/ufo/dist/index.mjs";
|
import { parseQuery, hasProtocol, joinURL, isScriptProtocol, withTrailingSlash, withoutTrailingSlash } from "/app/node_modules/ufo/dist/index.mjs";
|
||||||
import { a as useRouter, e as encodeRoutePath, r as resolveRouteObject, n as navigateTo, f as useNuxtApp, g as useRuntimeConfig, h as nuxtLinkDefaults } from "../server.mjs";
|
import { a as useRouter, f as encodeRoutePath, r as resolveRouteObject, n as navigateTo, g as useNuxtApp, h as useRuntimeConfig, i as nuxtLinkDefaults } from "../server.mjs";
|
||||||
import "/app/node_modules/defu/dist/defu.mjs";
|
import "/app/node_modules/defu/dist/defu.mjs";
|
||||||
const firstNonUndefined = (...args) => args.find((arg) => arg !== void 0);
|
const firstNonUndefined = (...args) => args.find((arg) => arg !== void 0);
|
||||||
function sanitizeExternalHref(value) {
|
function sanitizeExternalHref(value) {
|
||||||
@@ -304,4 +304,4 @@ function applyTrailingSlashBehavior(to, trailingSlash) {
|
|||||||
export {
|
export {
|
||||||
__nuxt_component_0 as _
|
__nuxt_component_0 as _
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=nuxt-link-Cp-CAJwR.js.map
|
//# sourceMappingURL=nuxt-link-C5PnX__I.js.map
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
export default ({"_DKEj_yij.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"DKEj_yij.js",name:"auth",imports:["node_modules/nuxt/dist/app/entry.js"]},"_DlAUqK2U.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"DlAUqK2U.js",name:"_plugin-vue_export-helper"},"_j8avB3IT.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"j8avB3IT.js",name:"region",imports:["node_modules/nuxt/dist/app/entry.js"]},"_qc1uPXiA.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"qc1uPXiA.js",name:"nuxt-link",imports:["node_modules/nuxt/dist/app/entry.js"]},"i18n/locales/en.json":{resourceType:"script",module:!0,prefetch:!1,preload:!1,file:"HwQw-d2b.js",name:"en",src:"i18n/locales/en.json",isDynamicEntry:!0},"i18n/locales/hu.json":{resourceType:"script",module:!0,prefetch:!1,preload:!1,file:"DiHJCuau.js",name:"hu",src:"i18n/locales/hu.json",isDynamicEntry:!0},"layouts/blank.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"B2nIQl38.js",name:"blank",src:"layouts/blank.vue",isDynamicEntry:!0,imports:["_DlAUqK2U.js","node_modules/nuxt/dist/app/entry.js"]},"layouts/default.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"BezjjCqI.js",name:"default",src:"layouts/default.vue",isDynamicEntry:!0,imports:["_qc1uPXiA.js","node_modules/nuxt/dist/app/entry.js","_j8avB3IT.js","_DKEj_yij.js"]},"middleware/auth.ts":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"DSOY2KzZ.js",name:"auth",src:"middleware/auth.ts",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js","_DKEj_yij.js"]},"node_modules/nuxt/dist/app/components/error-404.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"JOVMCDE9.js",name:"error-404",src:"node_modules/nuxt/dist/app/components/error-404.vue",isDynamicEntry:!0,imports:["_qc1uPXiA.js","_DlAUqK2U.js","node_modules/nuxt/dist/app/entry.js"],css:[]},"error-404.DL_4WIao.css":{file:"error-404.DL_4WIao.css",resourceType:"style",prefetch:!0,preload:!0},"node_modules/nuxt/dist/app/components/error-500.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"CLBsD5qj.js",name:"error-500",src:"node_modules/nuxt/dist/app/components/error-500.vue",isDynamicEntry:!0,imports:["_DlAUqK2U.js","node_modules/nuxt/dist/app/entry.js"],css:[]},"error-500.I1Dtv2V5.css":{file:"error-500.I1Dtv2V5.css",resourceType:"style",prefetch:!0,preload:!0},"node_modules/nuxt/dist/app/entry.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"CHWHIiGB.js",name:"entry",src:"node_modules/nuxt/dist/app/entry.js",isEntry:!0,dynamicImports:["middleware/auth.ts","layouts/blank.vue","layouts/default.vue","i18n/locales/hu.json","i18n/locales/en.json","node_modules/nuxt/dist/app/components/error-404.vue","node_modules/nuxt/dist/app/components/error-500.vue"],css:[]},"entry.KrfumMBl.css":{file:"entry.KrfumMBl.css",resourceType:"style",prefetch:!0,preload:!0},"pages/garages/[id]/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"KwNF0Piy.js",name:"index",src:"pages/garages/[id]/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]},"pages/garages/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"C3lSWcZz.js",name:"index",src:"pages/garages/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]},"pages/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"D5l8f-my.js",name:"index",src:"pages/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]},"pages/login.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"C8W4Ef6u.js",name:"login",src:"pages/login.vue",isDynamicEntry:!0,imports:["_qc1uPXiA.js","node_modules/nuxt/dist/app/entry.js","_DKEj_yij.js"]},"pages/packages/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"d4dk63Pu.js",name:"index",src:"pages/packages/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js","_j8avB3IT.js"]},"pages/permissions/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"DyJFDhDL.js",name:"index",src:"pages/permissions/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]}})
|
export default ({"_BPZZgRgP.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"BPZZgRgP.js",name:"nuxt-link",imports:["node_modules/nuxt/dist/app/entry.js"]},"_DlAUqK2U.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"DlAUqK2U.js",name:"_plugin-vue_export-helper"},"_nwypRWOF.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"nwypRWOF.js",name:"region",imports:["node_modules/nuxt/dist/app/entry.js"]},"i18n/locales/en.json":{resourceType:"script",module:!0,prefetch:!1,preload:!1,file:"woz7WbxD.js",name:"en",src:"i18n/locales/en.json",isDynamicEntry:!0},"i18n/locales/hu.json":{resourceType:"script",module:!0,prefetch:!1,preload:!1,file:"D_jf_u12.js",name:"hu",src:"i18n/locales/hu.json",isDynamicEntry:!0},"layouts/blank.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"DU5nqnNf.js",name:"blank",src:"layouts/blank.vue",isDynamicEntry:!0,imports:["_DlAUqK2U.js","node_modules/nuxt/dist/app/entry.js"]},"layouts/default.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"IlbAEw5Q.js",name:"default",src:"layouts/default.vue",isDynamicEntry:!0,imports:["_BPZZgRgP.js","node_modules/nuxt/dist/app/entry.js","_nwypRWOF.js"]},"middleware/auth.ts":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"CSkx_E93.js",name:"auth",src:"middleware/auth.ts",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]},"node_modules/nuxt/dist/app/components/error-404.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"fLPEiaqv.js",name:"error-404",src:"node_modules/nuxt/dist/app/components/error-404.vue",isDynamicEntry:!0,imports:["_BPZZgRgP.js","_DlAUqK2U.js","node_modules/nuxt/dist/app/entry.js"],css:[]},"error-404.DL_4WIao.css":{file:"error-404.DL_4WIao.css",resourceType:"style",prefetch:!0,preload:!0},"node_modules/nuxt/dist/app/components/error-500.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"CfRvSqVD.js",name:"error-500",src:"node_modules/nuxt/dist/app/components/error-500.vue",isDynamicEntry:!0,imports:["_DlAUqK2U.js","node_modules/nuxt/dist/app/entry.js"],css:[]},"error-500.I1Dtv2V5.css":{file:"error-500.I1Dtv2V5.css",resourceType:"style",prefetch:!0,preload:!0},"node_modules/nuxt/dist/app/entry.js":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"CGTxeHv7.js",name:"entry",src:"node_modules/nuxt/dist/app/entry.js",isEntry:!0,dynamicImports:["middleware/auth.ts","layouts/blank.vue","layouts/default.vue","i18n/locales/hu.json","i18n/locales/en.json","node_modules/nuxt/dist/app/components/error-404.vue","node_modules/nuxt/dist/app/components/error-500.vue"],css:[]},"entry.KrfumMBl.css":{file:"entry.KrfumMBl.css",resourceType:"style",prefetch:!0,preload:!0},"pages/garages/[id]/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"Di7O2dT-.js",name:"index",src:"pages/garages/[id]/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]},"pages/garages/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"p3BZMbac.js",name:"index",src:"pages/garages/index.vue",isDynamicEntry:!0,imports:["_BPZZgRgP.js","node_modules/nuxt/dist/app/entry.js"]},"pages/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"Dsqi8-Rp.js",name:"index",src:"pages/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]},"pages/login.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"DkxL14wO.js",name:"login",src:"pages/login.vue",isDynamicEntry:!0,imports:["_BPZZgRgP.js","node_modules/nuxt/dist/app/entry.js"]},"pages/packages/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"iGXES_tj.js",name:"index",src:"pages/packages/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js","_nwypRWOF.js"]},"pages/permissions/index.vue":{resourceType:"script",module:!0,prefetch:!0,preload:!0,file:"BVodpYs3.js",name:"index",src:"pages/permissions/index.vue",isDynamicEntry:!0,imports:["node_modules/nuxt/dist/app/entry.js"]}})
|
||||||
File diff suppressed because one or more lines are too long
173
frontend_admin/.nuxt/dist/server/server.mjs
vendored
173
frontend_admin/.nuxt/dist/server/server.mjs
vendored
@@ -1,11 +1,11 @@
|
|||||||
import * as Vue from "vue";
|
import * as Vue from "vue";
|
||||||
import { shallowReactive, reactive, effectScope, getCurrentScope, hasInjectionContext, getCurrentInstance as getCurrentInstance$1, inject, toRef, shallowRef, isReadonly, isRef, isShallow, isReactive, toRaw, defineComponent, createElementBlock, provide, cloneVNode, h, ref, unref, onScopeDispose, computed, Fragment, createVNode, Text, defineAsyncComponent, Suspense, nextTick, mergeProps, withCtx, useSSRContext, onErrorCaptured, onServerPrefetch, resolveDynamicComponent, createApp } from "vue";
|
import { hasInjectionContext, getCurrentInstance as getCurrentInstance$1, shallowReactive, reactive, effectScope, getCurrentScope, inject, toRef, shallowRef, isReadonly, isRef, isShallow, isReactive, toRaw, defineComponent, createElementBlock, provide, cloneVNode, h, ref, unref, onScopeDispose, computed, Fragment, createVNode, Text, defineAsyncComponent, Suspense, nextTick, mergeProps, withCtx, useSSRContext, onErrorCaptured, onServerPrefetch, resolveDynamicComponent, createApp } from "vue";
|
||||||
import { $fetch as $fetch$1 } from "/app/node_modules/ofetch/dist/node.mjs";
|
import { $fetch as $fetch$1 } from "/app/node_modules/ofetch/dist/node.mjs";
|
||||||
import { baseURL } from "#internal/nuxt/paths";
|
import { baseURL } from "#internal/nuxt/paths";
|
||||||
import { createHooks } from "/app/node_modules/hookable/dist/index.mjs";
|
import { createHooks } from "/app/node_modules/hookable/dist/index.mjs";
|
||||||
import { getContext, executeAsync } from "/app/node_modules/unctx/dist/index.mjs";
|
import { getContext, executeAsync } from "/app/node_modules/unctx/dist/index.mjs";
|
||||||
import { sanitizeStatusCode, createError as createError$1, appendHeader, getRequestHeader, setCookie, getCookie, deleteCookie, getRequestURL } from "/app/node_modules/h3/dist/index.mjs";
|
import { sanitizeStatusCode, createError as createError$1, appendHeader, getRequestHeader, setCookie, getCookie, deleteCookie, getRequestURL } from "/app/node_modules/h3/dist/index.mjs";
|
||||||
import { shouldHydrate, setActivePinia, createPinia } from "pinia";
|
import { shouldHydrate, setActivePinia, createPinia, defineStore } from "pinia";
|
||||||
import { defu, createDefu } from "/app/node_modules/defu/dist/defu.mjs";
|
import { defu, createDefu } from "/app/node_modules/defu/dist/defu.mjs";
|
||||||
import { START_LOCATION, createMemoryHistory, createRouter, useRoute as useRoute$1, RouterView } from "vue-router";
|
import { START_LOCATION, createMemoryHistory, createRouter, useRoute as useRoute$1, RouterView } from "vue-router";
|
||||||
import { hasProtocol, joinURL, parseURL, encodePath, decodePath, withQuery, isScriptProtocol, parsePath, parseQuery, withoutTrailingSlash } from "/app/node_modules/ufo/dist/index.mjs";
|
import { hasProtocol, joinURL, parseURL, encodePath, decodePath, withQuery, isScriptProtocol, parsePath, parseQuery, withoutTrailingSlash } from "/app/node_modules/ufo/dist/index.mjs";
|
||||||
@@ -473,13 +473,13 @@ const _routes = [
|
|||||||
name: "login",
|
name: "login",
|
||||||
path: "/login",
|
path: "/login",
|
||||||
meta: __nuxt_page_meta || {},
|
meta: __nuxt_page_meta || {},
|
||||||
component: () => import("./_nuxt/login-Dx4mHuUH.js")
|
component: () => import("./_nuxt/login-DOiXgKDi.js")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "garages",
|
name: "garages",
|
||||||
path: "/garages",
|
path: "/garages",
|
||||||
meta: { "middleware": "auth" },
|
meta: { "middleware": "auth" },
|
||||||
component: () => import("./_nuxt/index-o-V5Lz0_.js")
|
component: () => import("./_nuxt/index-CzKBE-M2.js")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "packages",
|
name: "packages",
|
||||||
@@ -491,13 +491,12 @@ const _routes = [
|
|||||||
name: "permissions",
|
name: "permissions",
|
||||||
path: "/permissions",
|
path: "/permissions",
|
||||||
meta: { "middleware": "auth" },
|
meta: { "middleware": "auth" },
|
||||||
component: () => import("./_nuxt/index-D2n0yf-2.js")
|
component: () => import("./_nuxt/index-DgwDY6Ie.js")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "garages-id",
|
name: "garages-id",
|
||||||
path: "/garages/:id()",
|
path: "/garages/:id()",
|
||||||
meta: { "middleware": "auth" },
|
component: () => import("./_nuxt/index-1I7UC9HP.js")
|
||||||
component: () => import("./_nuxt/index-JpXwtL-Z.js")
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const _wrapInTransition = (props, children) => {
|
const _wrapInTransition = (props, children) => {
|
||||||
@@ -642,7 +641,7 @@ const globalMiddleware = [
|
|||||||
manifest_45route_45rule
|
manifest_45route_45rule
|
||||||
];
|
];
|
||||||
const namedMiddleware = {
|
const namedMiddleware = {
|
||||||
auth: () => import("./_nuxt/auth-9ekP0oPk.js")
|
auth: () => import("./_nuxt/auth-B3jrOAhu.js")
|
||||||
};
|
};
|
||||||
Object.assign(/* @__PURE__ */ Object.create(null), {});
|
Object.assign(/* @__PURE__ */ Object.create(null), {});
|
||||||
const pageIslandRoutes = Object.assign(/* @__PURE__ */ Object.create(null), {});
|
const pageIslandRoutes = Object.assign(/* @__PURE__ */ Object.create(null), {});
|
||||||
@@ -1512,7 +1511,7 @@ const localeLoaders = {
|
|||||||
{
|
{
|
||||||
key: "locale_hu_46json_ee06c965",
|
key: "locale_hu_46json_ee06c965",
|
||||||
load: () => import(
|
load: () => import(
|
||||||
"./_nuxt/hu-B3JxlqZo.js"
|
"./_nuxt/hu-Ck1VzT5S.js"
|
||||||
/* webpackChunkName: "locale_hu_46json_ee06c965" */
|
/* webpackChunkName: "locale_hu_46json_ee06c965" */
|
||||||
),
|
),
|
||||||
cache: true
|
cache: true
|
||||||
@@ -1522,7 +1521,7 @@ const localeLoaders = {
|
|||||||
{
|
{
|
||||||
key: "locale_en_46json_0b63539c",
|
key: "locale_en_46json_0b63539c",
|
||||||
load: () => import(
|
load: () => import(
|
||||||
"./_nuxt/en-WIj2pBfh.js"
|
"./_nuxt/en-BI6r-iRW.js"
|
||||||
/* webpackChunkName: "locale_en_46json_0b63539c" */
|
/* webpackChunkName: "locale_en_46json_0b63539c" */
|
||||||
),
|
),
|
||||||
cache: true
|
cache: true
|
||||||
@@ -1662,7 +1661,7 @@ function getDefaultLocaleForDomain(host) {
|
|||||||
}
|
}
|
||||||
const isSupportedLocale = (locale) => localeCodes.includes(locale || "");
|
const isSupportedLocale = (locale) => localeCodes.includes(locale || "");
|
||||||
const resolveSupportedLocale = (locale) => isSupportedLocale(locale) ? locale : void 0;
|
const resolveSupportedLocale = (locale) => isSupportedLocale(locale) ? locale : void 0;
|
||||||
var define_I18N_LOCALE_HASHES_default$1 = { hu: "bb1d6803", en: "bb1d6803" };
|
var define_I18N_LOCALE_HASHES_default$1 = { hu: "4ec99847", en: "4ec99847" };
|
||||||
const useLocaleConfigs = () => useState(
|
const useLocaleConfigs = () => useState(
|
||||||
"i18n:cached-locale-configs",
|
"i18n:cached-locale-configs",
|
||||||
() => void 0
|
() => void 0
|
||||||
@@ -6736,7 +6735,7 @@ const setupVueI18nOptions = async (defaultLocale) => {
|
|||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
var define_I18N_LOCALE_HASHES_default = { hu: "bb1d6803", en: "bb1d6803" };
|
var define_I18N_LOCALE_HASHES_default = { hu: "4ec99847", en: "4ec99847" };
|
||||||
const i18n_EI7LsD1KYQADczz5hrChviGQCdVM8yUkvFEZLJpmnvM = /* @__PURE__ */ defineNuxtPlugin({
|
const i18n_EI7LsD1KYQADczz5hrChviGQCdVM8yUkvFEZLJpmnvM = /* @__PURE__ */ defineNuxtPlugin({
|
||||||
name: "i18n:plugin",
|
name: "i18n:plugin",
|
||||||
parallel: false,
|
parallel: false,
|
||||||
@@ -6819,6 +6818,138 @@ const i18n_EI7LsD1KYQADczz5hrChviGQCdVM8yUkvFEZLJpmnvM = /* @__PURE__ */ defineN
|
|||||||
nuxt.provide("switchLocalePath", useSwitchLocalePath(nuxt));
|
nuxt.provide("switchLocalePath", useSwitchLocalePath(nuxt));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const useAuthStore = defineStore("auth", () => {
|
||||||
|
const user = ref(null);
|
||||||
|
const token = ref(null);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const error = ref(null);
|
||||||
|
const isInitialized = ref(false);
|
||||||
|
const isAuthenticated = computed(() => !!token.value && !!user.value);
|
||||||
|
const isAdmin = computed(() => {
|
||||||
|
const role = user.value?.role;
|
||||||
|
if (!role) return false;
|
||||||
|
const staffRoles = ["SUPERADMIN", "ADMIN", "MODERATOR", "SALES_REP", "SERVICE_MGR"];
|
||||||
|
return staffRoles.includes(role.toUpperCase());
|
||||||
|
});
|
||||||
|
const userName = computed(() => {
|
||||||
|
if (!user.value) return "";
|
||||||
|
const { first_name, last_name } = user.value;
|
||||||
|
if (first_name && last_name) return `${first_name} ${last_name}`;
|
||||||
|
return first_name || last_name || user.value.email;
|
||||||
|
});
|
||||||
|
const userEmail = computed(() => user.value?.email ?? "");
|
||||||
|
const userRole = computed(() => user.value?.role ?? "guest");
|
||||||
|
async function login(email, password) {
|
||||||
|
isLoading.value = true;
|
||||||
|
error.value = null;
|
||||||
|
try {
|
||||||
|
const body = new URLSearchParams();
|
||||||
|
body.append("username", email);
|
||||||
|
body.append("password", password);
|
||||||
|
const res = await $fetch("/api/v1/auth/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||||
|
body
|
||||||
|
});
|
||||||
|
const tokenCookie = useCookie("access_token", {
|
||||||
|
maxAge: 60 * 60 * 24 * 7,
|
||||||
|
// 7 days
|
||||||
|
path: "/",
|
||||||
|
sameSite: "lax",
|
||||||
|
secure: true
|
||||||
|
});
|
||||||
|
tokenCookie.value = res.access_token;
|
||||||
|
token.value = res.access_token;
|
||||||
|
await fetchUser();
|
||||||
|
} catch (err) {
|
||||||
|
error.value = err?.data?.detail || err?.message || "Login failed";
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function fetchUser() {
|
||||||
|
const tokenCookie = useCookie("access_token");
|
||||||
|
const currentToken = tokenCookie.value || token.value;
|
||||||
|
if (!currentToken) return;
|
||||||
|
try {
|
||||||
|
const res = await $fetch("/api/v1/auth/me", {
|
||||||
|
headers: { Authorization: `Bearer ${currentToken}` }
|
||||||
|
});
|
||||||
|
user.value = res;
|
||||||
|
} catch (err) {
|
||||||
|
if (err?.response?.status === 401) {
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function logout() {
|
||||||
|
token.value = null;
|
||||||
|
user.value = null;
|
||||||
|
error.value = null;
|
||||||
|
const tokenCookie = useCookie("access_token");
|
||||||
|
tokenCookie.value = null;
|
||||||
|
}
|
||||||
|
async function init() {
|
||||||
|
const tokenCookie = useCookie("access_token");
|
||||||
|
if (tokenCookie.value) {
|
||||||
|
token.value = tokenCookie.value;
|
||||||
|
try {
|
||||||
|
await fetchUser();
|
||||||
|
} catch {
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isInitialized.value = true;
|
||||||
|
}
|
||||||
|
function clearError() {
|
||||||
|
error.value = null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
// State
|
||||||
|
user,
|
||||||
|
token,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
isInitialized,
|
||||||
|
// Getters
|
||||||
|
isAuthenticated,
|
||||||
|
isAdmin,
|
||||||
|
userName,
|
||||||
|
userEmail,
|
||||||
|
userRole,
|
||||||
|
// Actions
|
||||||
|
login,
|
||||||
|
fetchUser,
|
||||||
|
logout,
|
||||||
|
init,
|
||||||
|
clearError
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const api_jy9dy79pM_nYQuRKPrcfNg56p_gKkzw9SekUTZgAenc = /* @__PURE__ */ defineNuxtPlugin(() => {
|
||||||
|
const originalFetch = globalThis.fetch;
|
||||||
|
globalThis.fetch = async (input, init) => {
|
||||||
|
const response = await originalFetch(input, init);
|
||||||
|
if (response.status === 401) {
|
||||||
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
||||||
|
if (url.includes("/auth/login") || url.includes("/auth/refresh")) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
authStore.logout();
|
||||||
|
} catch {
|
||||||
|
const tokenCookie = useCookie("access_token");
|
||||||
|
tokenCookie.value = null;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
await navigateTo("/login");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
});
|
||||||
const ssg_detect_IpHCGcQQ_IR5Rl99qyukWoMA9fJGfuTYyoksTzy81cs = /* @__PURE__ */ defineNuxtPlugin({
|
const ssg_detect_IpHCGcQQ_IR5Rl99qyukWoMA9fJGfuTYyoksTzy81cs = /* @__PURE__ */ defineNuxtPlugin({
|
||||||
name: "i18n:plugin:ssg-detect",
|
name: "i18n:plugin:ssg-detect",
|
||||||
dependsOn: ["i18n:plugin", "i18n:plugin:route-locale-detect"],
|
dependsOn: ["i18n:plugin", "i18n:plugin:route-locale-detect"],
|
||||||
@@ -6840,11 +6971,12 @@ const plugins = [
|
|||||||
route_locale_detect__HPHJq3Jg7gwhwgKEI8tQavopSAjmrCSPXl9HgL2h9U,
|
route_locale_detect__HPHJq3Jg7gwhwgKEI8tQavopSAjmrCSPXl9HgL2h9U,
|
||||||
preload_30FByJAs5vQa4mNNQLX15KPGCCVjIGrzdTjh6ve5W24,
|
preload_30FByJAs5vQa4mNNQLX15KPGCCVjIGrzdTjh6ve5W24,
|
||||||
i18n_EI7LsD1KYQADczz5hrChviGQCdVM8yUkvFEZLJpmnvM,
|
i18n_EI7LsD1KYQADczz5hrChviGQCdVM8yUkvFEZLJpmnvM,
|
||||||
|
api_jy9dy79pM_nYQuRKPrcfNg56p_gKkzw9SekUTZgAenc,
|
||||||
ssg_detect_IpHCGcQQ_IR5Rl99qyukWoMA9fJGfuTYyoksTzy81cs
|
ssg_detect_IpHCGcQQ_IR5Rl99qyukWoMA9fJGfuTYyoksTzy81cs
|
||||||
];
|
];
|
||||||
const layouts = {
|
const layouts = {
|
||||||
blank: defineAsyncComponent(() => import("./_nuxt/blank-DWT4RB69.js").then((m) => m.default || m)),
|
blank: defineAsyncComponent(() => import("./_nuxt/blank-DWT4RB69.js").then((m) => m.default || m)),
|
||||||
default: defineAsyncComponent(() => import("./_nuxt/default-DOjdWE8b.js").then((m) => m.default || m))
|
default: defineAsyncComponent(() => import("./_nuxt/default-C9mWt9Pc.js").then((m) => m.default || m))
|
||||||
};
|
};
|
||||||
const routeRulesMatcher = _routeRulesMatcher;
|
const routeRulesMatcher = _routeRulesMatcher;
|
||||||
const LayoutLoader = defineComponent({
|
const LayoutLoader = defineComponent({
|
||||||
@@ -7128,7 +7260,7 @@ const _sfc_main$1 = {
|
|||||||
const statusText = _error.statusMessage ?? (is404 ? "Page Not Found" : "Internal Server Error");
|
const statusText = _error.statusMessage ?? (is404 ? "Page Not Found" : "Internal Server Error");
|
||||||
const description = _error.message || _error.toString();
|
const description = _error.message || _error.toString();
|
||||||
const stack = void 0;
|
const stack = void 0;
|
||||||
const _Error404 = defineAsyncComponent(() => import("./_nuxt/error-404-Bkg5lg69.js"));
|
const _Error404 = defineAsyncComponent(() => import("./_nuxt/error-404-DPt4byml.js"));
|
||||||
const _Error = defineAsyncComponent(() => import("./_nuxt/error-500-DfEH3Z64.js"));
|
const _Error = defineAsyncComponent(() => import("./_nuxt/error-500-DfEH3Z64.js"));
|
||||||
const ErrorTemplate = is404 ? _Error404 : _Error;
|
const ErrorTemplate = is404 ? _Error404 : _Error;
|
||||||
return (_ctx, _push, _parent, _attrs) => {
|
return (_ctx, _push, _parent, _attrs) => {
|
||||||
@@ -7222,14 +7354,15 @@ let entry;
|
|||||||
const entry_default = ((ssrContext) => entry(ssrContext));
|
const entry_default = ((ssrContext) => entry(ssrContext));
|
||||||
export {
|
export {
|
||||||
useRouter as a,
|
useRouter as a,
|
||||||
useI18n as b,
|
useAuthStore as b,
|
||||||
useCookie as c,
|
useCookie as c,
|
||||||
defineNuxtRouteMiddleware as d,
|
useI18n as d,
|
||||||
entry_default as default,
|
entry_default as default,
|
||||||
encodeRoutePath as e,
|
defineNuxtRouteMiddleware as e,
|
||||||
useNuxtApp as f,
|
encodeRoutePath as f,
|
||||||
useRuntimeConfig as g,
|
useNuxtApp as g,
|
||||||
nuxtLinkDefaults as h,
|
useRuntimeConfig as h,
|
||||||
|
nuxtLinkDefaults as i,
|
||||||
navigateTo as n,
|
navigateTo as n,
|
||||||
resolveRouteObject as r,
|
resolveRouteObject as r,
|
||||||
useHead as u
|
useHead as u
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user