Phase 1 Sprint C+D: Admin UI + Frontend Sidebar

This commit is contained in:
Pepe Ziberi
2026-05-20 21:29:45 +02:00
parent ca26f1e733
commit 4602de7a38
4 changed files with 963 additions and 332 deletions

View File

@@ -5,10 +5,11 @@ import { getSession } from '@/lib/auth'
export async function GET() {
try {
const user = await getSession()
const tenantId = user?.tenantId
// Filter categories: global (tenantId=null) + tenant-specific
const categoryWhere: any = user?.tenantId
? { OR: [{ tenantId: null }, { tenantId: user.tenantId }] }
/* ─── 1. Global library (legacy IconAsset) ─── */
const categoryWhere: any = tenantId
? { OR: [{ tenantId: null }, { tenantId }] }
: {}
const categories = await (prisma as any).iconCategory.findMany({
@@ -16,19 +17,18 @@ export async function GET() {
orderBy: { sortOrder: 'asc' },
include: {
icons: {
where: user?.tenantId
? { isActive: true, OR: [{ tenantId: null }, { tenantId: user.tenantId }] }
where: tenantId
? { isActive: true, OR: [{ tenantId: null }, { tenantId }] }
: { isActive: true, tenantId: null },
orderBy: { name: 'asc' },
},
},
})
// Get tenant's hidden icon IDs (legacy)
let hiddenIconIds: string[] = []
if (user?.tenantId) {
if (tenantId) {
const tenant = await (prisma as any).tenant.findUnique({
where: { id: user.tenantId },
where: { id: tenantId },
select: { hiddenIconIds: true },
})
hiddenIconIds = tenant?.hiddenIconIds || []
@@ -44,15 +44,72 @@ export async function GET() {
})),
}))
// Get tenant's custom symbol collection (with custom names)
let mySymbols: any[] = []
if (user?.tenantId) {
/* ─── 2. Tenant symbols (Phase 1 architecture) ─── */
let tenantSymbolGroups: any[] = []
let flatTenantSymbols: any[] = []
if (tenantId) {
const tenantSymbols = await (prisma as any).tenantSymbol.findMany({
where: { tenantId: user.tenantId },
where: { tenantId },
include: { category: true },
orderBy: [{ category: { sortOrder: 'asc' } }, { sortOrder: 'asc' }],
})
flatTenantSymbols = tenantSymbols.map((ts: any) => ({
id: ts.id,
name: ts.customName || ts.name,
customName: ts.customName,
categoryId: ts.categoryId,
categoryName: ts.category?.name || null,
isUploaded: ts.isUploaded,
migratedFromIconId: ts.migratedFromIconId,
imageUrl: ts.isUploaded
? `/api/tenant/symbols/${ts.id}/image`
: ts.migratedFromIconId
? `/api/icons/${ts.migratedFromIconId}/image`
: `/api/icons/${ts.id}/image`,
}))
// Group by category for sidebar display
const groups = new Map<string | null, any[]>()
for (const sym of flatTenantSymbols) {
const key = sym.categoryId || null
if (!groups.has(key)) groups.set(key, [])
groups.get(key)!.push(sym)
}
// Fetch categories that have symbols but may not be in the symbol list (empty ones are omitted)
const catIds = Array.from(groups.keys()).filter(Boolean) as string[]
const tenantCategories = catIds.length
? await (prisma as any).tenantCategory.findMany({
where: { id: { in: catIds }, tenantId },
orderBy: { sortOrder: 'asc' },
})
: []
const catMap = new Map(tenantCategories.map((c: any) => [c.id, c]))
tenantSymbolGroups = Array.from(groups.entries()).map(([catId, symbols]) => {
const cat = catId ? catMap.get(catId) : null
return {
categoryId: catId,
categoryName: cat ? (cat as any).name || 'Kategorie' : 'Ohne Kategorie',
sortOrder: cat ? (cat as any).sortOrder ?? 999 : 999,
symbols,
}
})
tenantSymbolGroups.sort((a, b) => a.sortOrder - b.sortOrder)
}
/* ─── 3. Legacy mySymbols (keep for old clients during transition) ─── */
let mySymbolsLegacy: any[] = []
if (tenantId) {
const legacy = await (prisma as any).tenantSymbol.findMany({
where: { tenantId, iconId: { not: null } },
include: { icon: { select: { id: true, name: true, mimeType: true, iconType: true } } },
orderBy: { sortOrder: 'asc' },
})
mySymbols = tenantSymbols.map((ts: any) => ({
mySymbolsLegacy = legacy.map((ts: any) => ({
id: ts.icon.id,
tenantSymbolId: ts.id,
name: ts.customName || ts.icon.name,
@@ -63,7 +120,12 @@ export async function GET() {
}))
}
return NextResponse.json({ categories: categoriesWithUrls, mySymbols })
return NextResponse.json({
categories: categoriesWithUrls,
mySymbols: mySymbolsLegacy, // legacy shape for old clients
tenantSymbols: flatTenantSymbols, // new flat list
tenantSymbolGroups, // grouped by TenantCategory
})
} catch (error) {
console.error('Error fetching icons:', error)
return NextResponse.json({ error: 'Serverfehler' }, { status: 500 })