mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 19:44:12 +00:00
- Add Where type imports and proper type assertions in API routes - Add Locale type definitions for locale validation - Fix email-logs/stats route with proper EmailLog typing - Fix newsletter-service interests type and null checks - Remove invalid contact field from OpenAPI metadata - Fix formSubmissionOverrides type casting in payload.config - Fix vcard route Team type casting All 24 TypeScript errors in src/ are now resolved. Test files have separate type issues that don't affect production. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
218 lines
6.2 KiB
TypeScript
218 lines
6.2 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { getPayload } from 'payload'
|
|
import type { Where } from 'payload'
|
|
import config from '@payload-config'
|
|
|
|
type Locale = 'de' | 'en' | 'all'
|
|
|
|
/**
|
|
* Team API
|
|
*
|
|
* GET /api/team - Liste aller Team-Mitglieder mit Filter und Suche
|
|
*
|
|
* Query-Parameter:
|
|
* - tenant (required): Tenant ID
|
|
* - slug: Einzelnes Mitglied nach Slug
|
|
* - search: Volltextsuche in Name, Rolle, Abteilung, Bio
|
|
* - department: Nach Abteilung filtern
|
|
* - level: Nach Hierarchie-Ebene filtern
|
|
* - specialization: Nach Fachgebiet filtern
|
|
* - language: Nach Sprache filtern
|
|
* - featured: Nur hervorgehobene (true/false)
|
|
* - limit: Maximale Anzahl (default: 50)
|
|
* - page: Seite für Pagination
|
|
* - sort: Sortierung (order, name, department, startDate)
|
|
* - locale: Sprache (de/en)
|
|
*/
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
const { searchParams } = new URL(request.url)
|
|
|
|
// Required: Tenant
|
|
const tenantId = searchParams.get('tenant')
|
|
if (!tenantId) {
|
|
return NextResponse.json({ error: 'tenant parameter is required' }, { status: 400 })
|
|
}
|
|
|
|
const payload = await getPayload({ config })
|
|
|
|
// Optional parameters
|
|
const slug = searchParams.get('slug')
|
|
const search = searchParams.get('search')
|
|
const department = searchParams.get('department')
|
|
const level = searchParams.get('level')
|
|
const specialization = searchParams.get('specialization')
|
|
const language = searchParams.get('language')
|
|
const featured = searchParams.get('featured')
|
|
const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 100)
|
|
const page = parseInt(searchParams.get('page') || '1')
|
|
const sort = searchParams.get('sort') || 'order'
|
|
const localeParam = searchParams.get('locale')
|
|
const locale: Locale = (localeParam === 'de' || localeParam === 'en') ? localeParam : 'de'
|
|
|
|
// Build where clause
|
|
const where: Where = {
|
|
tenant: { equals: parseInt(tenantId) },
|
|
isActive: { equals: true },
|
|
}
|
|
|
|
// Single member by slug
|
|
if (slug) {
|
|
where.slug = { equals: slug }
|
|
}
|
|
|
|
// Department filter
|
|
if (department) {
|
|
where.department = { contains: department }
|
|
}
|
|
|
|
// Hierarchy level filter
|
|
if (level) {
|
|
where.hierarchyLevel = { equals: level }
|
|
}
|
|
|
|
// Featured filter
|
|
if (featured === 'true') {
|
|
where.isFeatured = { equals: true }
|
|
}
|
|
|
|
// Build sort string
|
|
let sortField = 'order'
|
|
switch (sort) {
|
|
case 'name':
|
|
sortField = 'name'
|
|
break
|
|
case 'department':
|
|
sortField = 'department'
|
|
break
|
|
case 'startDate':
|
|
sortField = '-startDate'
|
|
break
|
|
case '-order':
|
|
sortField = '-order'
|
|
break
|
|
default:
|
|
sortField = 'order'
|
|
}
|
|
|
|
// Query team members
|
|
const result = await payload.find({
|
|
collection: 'team',
|
|
where: where as Where,
|
|
sort: sortField,
|
|
limit,
|
|
page,
|
|
locale,
|
|
depth: 2, // Include image and reportsTo
|
|
})
|
|
|
|
let members = result.docs
|
|
|
|
// Post-query filters (for array fields)
|
|
|
|
// Search filter (case-insensitive)
|
|
if (search) {
|
|
const searchLower = search.toLowerCase()
|
|
members = members.filter((member) => {
|
|
const nameMatch = member.name?.toLowerCase().includes(searchLower)
|
|
const roleMatch =
|
|
typeof member.role === 'string' && member.role.toLowerCase().includes(searchLower)
|
|
const deptMatch =
|
|
typeof member.department === 'string' &&
|
|
member.department.toLowerCase().includes(searchLower)
|
|
const bioMatch =
|
|
typeof member.bioShort === 'string' &&
|
|
member.bioShort.toLowerCase().includes(searchLower)
|
|
|
|
// Search in specializations
|
|
const specMatch =
|
|
Array.isArray(member.specializations) &&
|
|
member.specializations.some(
|
|
(s) => typeof s.title === 'string' && s.title.toLowerCase().includes(searchLower)
|
|
)
|
|
|
|
return nameMatch || roleMatch || deptMatch || bioMatch || specMatch
|
|
})
|
|
}
|
|
|
|
// Specialization filter
|
|
if (specialization) {
|
|
const specLower = specialization.toLowerCase()
|
|
members = members.filter(
|
|
(member) =>
|
|
Array.isArray(member.specializations) &&
|
|
member.specializations.some(
|
|
(s) => typeof s.title === 'string' && s.title.toLowerCase().includes(specLower)
|
|
)
|
|
)
|
|
}
|
|
|
|
// Language filter
|
|
if (language) {
|
|
const langLower = language.toLowerCase()
|
|
members = members.filter(
|
|
(member) =>
|
|
Array.isArray(member.languages) &&
|
|
member.languages.some(
|
|
(l) => typeof l.language === 'string' && l.language.toLowerCase().includes(langLower)
|
|
)
|
|
)
|
|
}
|
|
|
|
// Get unique departments for filter dropdown
|
|
const allMembers = await payload.find({
|
|
collection: 'team',
|
|
where: {
|
|
tenant: { equals: parseInt(tenantId) },
|
|
isActive: { equals: true },
|
|
},
|
|
limit: 1000,
|
|
locale,
|
|
})
|
|
|
|
const departments = [
|
|
...new Set(allMembers.docs.map((m) => m.department).filter(Boolean)),
|
|
].sort() as string[]
|
|
|
|
const specializations = [
|
|
...new Set(
|
|
allMembers.docs.flatMap((m) =>
|
|
Array.isArray(m.specializations) ? m.specializations.map((s) => s.title) : []
|
|
)
|
|
),
|
|
]
|
|
.filter(Boolean)
|
|
.sort() as string[]
|
|
|
|
const languages = [
|
|
...new Set(
|
|
allMembers.docs.flatMap((m) =>
|
|
Array.isArray(m.languages) ? m.languages.map((l) => l.language) : []
|
|
)
|
|
),
|
|
]
|
|
.filter(Boolean)
|
|
.sort() as string[]
|
|
|
|
// Single member response
|
|
if (slug && members.length === 1) {
|
|
return NextResponse.json({
|
|
member: members[0],
|
|
filters: { departments, specializations, languages },
|
|
})
|
|
}
|
|
|
|
return NextResponse.json({
|
|
members,
|
|
totalDocs: result.totalDocs,
|
|
totalPages: result.totalPages,
|
|
page: result.page,
|
|
hasNextPage: result.hasNextPage,
|
|
hasPrevPage: result.hasPrevPage,
|
|
filters: { departments, specializations, languages },
|
|
})
|
|
} catch (error) {
|
|
console.error('Team API error:', error)
|
|
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
|
}
|
|
}
|