feat(categories): tree browser, CRUD dialog, pending approval queue with merge
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import { api } from '@/api/client'
|
||||
import type {
|
||||
ApiResponse,
|
||||
Category,
|
||||
CategoryTranslation,
|
||||
ListParams,
|
||||
PaginatedResponse,
|
||||
} from '@/api/types'
|
||||
|
||||
const BASE = '/api/admin/v1/categories'
|
||||
|
||||
export interface CategoryPayload {
|
||||
parent_id?: string | null
|
||||
slug?: string
|
||||
sort_order?: number
|
||||
is_active?: boolean
|
||||
translations?: Array<{ locale: string; name: string; description?: string | null }>
|
||||
}
|
||||
|
||||
export function fetchCategoryTree(includeInactive = true) {
|
||||
return api.get<ApiResponse<Category[]>>(`${BASE}/tree`, {
|
||||
include_inactive: includeInactive,
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchPendingCategories(params: ListParams) {
|
||||
return api.get<PaginatedResponse<Category>>(`${BASE}/pending`, params)
|
||||
}
|
||||
|
||||
export function fetchCategory(id: string) {
|
||||
return api.get<ApiResponse<Category>>(`${BASE}/${id}`)
|
||||
}
|
||||
|
||||
export function createCategory(payload: CategoryPayload) {
|
||||
return api.post<ApiResponse<Category>>(BASE, payload)
|
||||
}
|
||||
|
||||
export function updateCategory(id: string, payload: CategoryPayload) {
|
||||
return api.put<ApiResponse<Category>>(`${BASE}/${id}`, payload)
|
||||
}
|
||||
|
||||
export function deleteCategory(id: string) {
|
||||
return api.delete<ApiResponse<null>>(`${BASE}/${id}`)
|
||||
}
|
||||
|
||||
export function approveCategory(id: string) {
|
||||
return api.post<ApiResponse<Category>>(`${BASE}/${id}/approve`)
|
||||
}
|
||||
|
||||
export function rejectCategory(id: string) {
|
||||
return api.post<ApiResponse<Category>>(`${BASE}/${id}/reject`)
|
||||
}
|
||||
|
||||
export function mergeCategory(id: string, targetId: string) {
|
||||
return api.post<ApiResponse<Category>>(`${BASE}/${id}/merge`, { target_id: targetId })
|
||||
}
|
||||
|
||||
export function fetchCategoryTranslations(id: string) {
|
||||
return api.get<ApiResponse<CategoryTranslation[]>>(`${BASE}/${id}/translations`)
|
||||
}
|
||||
|
||||
export function upsertCategoryTranslation(
|
||||
id: string,
|
||||
locale: string,
|
||||
payload: { name: string; description?: string | null },
|
||||
) {
|
||||
return api.post<ApiResponse<CategoryTranslation>>(`${BASE}/${id}/translations/${locale}`, payload)
|
||||
}
|
||||
|
||||
export function deleteCategoryTranslation(id: string, locale: string) {
|
||||
return api.delete<ApiResponse<null>>(`${BASE}/${id}/translations/${locale}`)
|
||||
}
|
||||
|
||||
/** Flatten the tree for parent/merge-target pickers. */
|
||||
export function flattenTree(nodes: Category[], depth = 0): Array<Category & { depth: number }> {
|
||||
return nodes.flatMap((node) => [
|
||||
{ ...node, depth },
|
||||
...flattenTree(node.children ?? [], depth + 1),
|
||||
])
|
||||
}
|
||||
+15
-9
@@ -72,29 +72,35 @@ export interface MeResponse extends ApiResponse<AdminUser> {
|
||||
|
||||
// ---------- category ----------
|
||||
|
||||
export interface CategoryTranslation {
|
||||
locale: string
|
||||
name: string
|
||||
description: string | null
|
||||
}
|
||||
|
||||
export interface Category {
|
||||
kind: 'category'
|
||||
id: string
|
||||
parent_id: string | null
|
||||
level: number
|
||||
slug: string
|
||||
name: string
|
||||
name: string | null
|
||||
description: string | null
|
||||
status: string
|
||||
sort_order: number
|
||||
is_leaf?: boolean
|
||||
is_active: boolean
|
||||
visibility?: string
|
||||
approval_status?: 'pending' | 'approved' | 'rejected' | string
|
||||
source?: string
|
||||
created_by_uid?: string | null
|
||||
approved_by_uid?: string | null
|
||||
approved_at?: string | null
|
||||
merged_into_category_id?: string | null
|
||||
translations?: CategoryTranslation[]
|
||||
children?: Category[]
|
||||
created_at?: string
|
||||
updated_at?: string
|
||||
}
|
||||
|
||||
export interface CategoryTranslation {
|
||||
locale: string
|
||||
name: string
|
||||
description: string | null
|
||||
}
|
||||
|
||||
// ---------- studio ----------
|
||||
|
||||
export type ArticleStatus =
|
||||
|
||||
Reference in New Issue
Block a user