refactor: replace hardcoded categories with Directus-powered category tree and translations

This commit is contained in:
2026-02-07 11:23:39 +01:00
parent 4f00b303e8
commit bb50615e0a
12 changed files with 391 additions and 196 deletions

View File

@@ -10,6 +10,7 @@ class CategoriesService {
this.cache = null
this.cacheTimestamp = 0
this.cacheTimeout = 10 * 60 * 1000 // 10 minutes
this._pending = null
}
async getAll() {
@@ -17,10 +18,19 @@ class CategoriesService {
return this.cache
}
const categories = await directus.getCategories()
this.cache = categories
this.cacheTimestamp = Date.now()
return categories
if (this._pending) return this._pending
this._pending = directus.getCategories().then(categories => {
this.cache = categories
this.cacheTimestamp = Date.now()
this._pending = null
return categories
}).catch(err => {
this._pending = null
throw err
})
return this._pending
}
async getById(id) {
@@ -32,7 +42,17 @@ class CategoriesService {
}
async getTree() {
return directus.getCategoryTree()
const all = await this.getAll()
return this.buildTree(all)
}
buildTree(categories, parentId = null) {
return categories
.filter(cat => (cat.parent?.id || cat.parent) === parentId)
.map(cat => ({
...cat,
children: this.buildTree(categories, cat.id)
}))
}
async getSubcategories(parentId) {

View File

@@ -134,7 +134,7 @@ class DirectusService {
* @returns {Promise<Object|null>} Response data or null for 204
* @throws {DirectusError} On request failure
*/
async request(endpoint, options = {}) {
async request(endpoint, options = {}, _retryCount = 0) {
const url = `${this.baseUrl}${endpoint}`
const headers = {
@@ -163,6 +163,12 @@ class DirectusService {
this.clearTokens()
}
}
if (response.status === 429 && _retryCount < 3) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '3', 10)
await new Promise(r => setTimeout(r, retryAfter * 1000))
return this.request(endpoint, options, _retryCount + 1)
}
if (!response.ok) {
const error = await response.json().catch(() => ({}))
@@ -405,6 +411,7 @@ class DirectusService {
'category.id',
'category.name',
'category.slug',
'category.translations.*',
'location.id',
'location.name',
'location.postal_code',

View File

@@ -4,13 +4,27 @@
*/
import { directus } from './directus.js'
import { categoriesService } from './categories.js'
class ListingsService {
async getListingsWithFilters(filters = {}) {
const directusFilter = { status: { _eq: 'published' } }
if (filters.category) {
directusFilter.category = { slug: { _eq: filters.category } }
if (filters.subcategory) {
directusFilter.category = { slug: { _eq: filters.subcategory } }
} else {
const all = await categoriesService.getAll()
const parent = all.find(c => c.slug === filters.category && !c.parent)
if (parent) {
const childSlugs = all
.filter(c => (c.parent?.id || c.parent) === parent.id)
.map(c => c.slug)
directusFilter.category = { slug: { _in: [filters.category, ...childSlugs] } }
} else {
directusFilter.category = { slug: { _eq: filters.category } }
}
}
}
if (filters.location) {