v1.2.0: Symbol-Verwaltung, SOMA-Admin, Light Mode Farbsystem, Onboarding-Tour, Credit-Link

This commit is contained in:
Pepe Ziberi
2026-02-24 21:13:27 +01:00
parent d893373bd9
commit 1583ef2a17
12 changed files with 700 additions and 128 deletions

View File

@@ -0,0 +1,108 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/db'
import { getSession } from '@/lib/auth'
// GET: List SOMA templates for the current tenant
export async function GET() {
try {
const user = await getSession()
if (!user) return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 401 })
if (user.role !== 'TENANT_ADMIN' && user.role !== 'SERVER_ADMIN') {
return NextResponse.json({ error: 'Keine Berechtigung' }, { status: 403 })
}
const templates = await (prisma as any).journalCheckTemplate.findMany({
where: { tenantId: user.tenantId || null },
orderBy: { sortOrder: 'asc' },
})
return NextResponse.json({ templates })
} catch (error) {
console.error('Error fetching SOMA templates:', error)
return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
}
}
// POST: Create a new SOMA template for the current tenant
export async function POST(req: NextRequest) {
try {
const user = await getSession()
if (!user) return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 401 })
if (user.role !== 'TENANT_ADMIN' && user.role !== 'SERVER_ADMIN') {
return NextResponse.json({ error: 'Keine Berechtigung' }, { status: 403 })
}
const { label, sortOrder } = await req.json()
if (!label?.trim()) {
return NextResponse.json({ error: 'Label ist erforderlich' }, { status: 400 })
}
const template = await (prisma as any).journalCheckTemplate.create({
data: {
label: label.trim(),
sortOrder: sortOrder ?? 0,
tenantId: user.tenantId || null,
isActive: true,
},
})
return NextResponse.json({ template }, { status: 201 })
} catch (error) {
console.error('Error creating SOMA template:', error)
return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
}
}
// PATCH: Update multiple templates (bulk reorder/toggle)
export async function PATCH(req: NextRequest) {
try {
const user = await getSession()
if (!user) return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 401 })
if (user.role !== 'TENANT_ADMIN' && user.role !== 'SERVER_ADMIN') {
return NextResponse.json({ error: 'Keine Berechtigung' }, { status: 403 })
}
const { updates } = await req.json()
if (!Array.isArray(updates)) {
return NextResponse.json({ error: 'updates Array erforderlich' }, { status: 400 })
}
await Promise.all(
updates.map((u: { id: string; label?: string; sortOrder?: number; isActive?: boolean }) =>
(prisma as any).journalCheckTemplate.update({
where: { id: u.id },
data: {
...(u.label !== undefined && { label: u.label }),
...(u.sortOrder !== undefined && { sortOrder: u.sortOrder }),
...(u.isActive !== undefined && { isActive: u.isActive }),
},
})
)
)
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error updating SOMA templates:', error)
return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
}
}
// DELETE: Delete a SOMA template
export async function DELETE(req: NextRequest) {
try {
const user = await getSession()
if (!user) return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 401 })
if (user.role !== 'TENANT_ADMIN' && user.role !== 'SERVER_ADMIN') {
return NextResponse.json({ error: 'Keine Berechtigung' }, { status: 403 })
}
const { id } = await req.json()
if (!id) return NextResponse.json({ error: 'ID erforderlich' }, { status: 400 })
await (prisma as any).journalCheckTemplate.delete({ where: { id } })
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error deleting SOMA template:', error)
return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
}
}

View File

@@ -0,0 +1,83 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/db'
import { getSession } from '@/lib/auth'
// GET: List all icons with their tenant-specific active status
export async function GET() {
try {
const user = await getSession()
if (!user) return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 401 })
if (user.role !== 'TENANT_ADMIN' && user.role !== 'SERVER_ADMIN') {
return NextResponse.json({ error: 'Keine Berechtigung' }, { status: 403 })
}
const tenantId = user.tenantId
if (!tenantId) return NextResponse.json({ error: 'Kein Mandant zugeordnet' }, { status: 400 })
// Get all system icons (active ones)
const icons = await (prisma as any).iconAsset.findMany({
where: { isActive: true },
include: { category: { select: { id: true, name: true } } },
orderBy: [{ category: { sortOrder: 'asc' } }, { name: 'asc' }],
})
// Get tenant-specific overrides
const overrides = await (prisma as any).tenantSymbol.findMany({
where: { tenantId },
})
const overrideMap = new Map(overrides.map((o: any) => [o.iconId, o.isActive]))
// Merge: default is active (true) unless override says otherwise
const symbols = icons.map((icon: any) => ({
id: icon.id,
name: icon.name,
fileKey: icon.fileKey,
mimeType: icon.mimeType,
iconType: icon.iconType,
categoryId: icon.categoryId,
categoryName: icon.category?.name || 'Ohne Kategorie',
isActive: overrideMap.has(icon.id) ? overrideMap.get(icon.id) : true,
}))
return NextResponse.json({ symbols })
} catch (error) {
console.error('Error fetching tenant symbols:', error)
return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
}
}
// PATCH: Update symbol visibility for the tenant (bulk)
export async function PATCH(req: NextRequest) {
try {
const user = await getSession()
if (!user) return NextResponse.json({ error: 'Nicht autorisiert' }, { status: 401 })
if (user.role !== 'TENANT_ADMIN' && user.role !== 'SERVER_ADMIN') {
return NextResponse.json({ error: 'Keine Berechtigung' }, { status: 403 })
}
const tenantId = user.tenantId
if (!tenantId) return NextResponse.json({ error: 'Kein Mandant zugeordnet' }, { status: 400 })
const { updates } = await req.json()
if (!Array.isArray(updates)) {
return NextResponse.json({ error: 'updates Array erforderlich' }, { status: 400 })
}
// Upsert each symbol override
await Promise.all(
updates.map((u: { iconId: string; isActive: boolean }) =>
(prisma as any).tenantSymbol.upsert({
where: { tenantId_iconId: { tenantId, iconId: u.iconId } },
update: { isActive: u.isActive },
create: { tenantId, iconId: u.iconId, isActive: u.isActive },
})
)
)
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error updating tenant symbols:', error)
return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
}
}