--- import { AttributeCategory, AttributeType, type Prisma } from '@prisma/client' import { Icon } from 'astro-icon/components' import { actions, isInputError } from 'astro:actions' import { z } from 'astro:content' import { orderBy as lodashOrderBy } from 'lodash-es' import Button from '../../components/Button.astro' import SortArrowIcon from '../../components/SortArrowIcon.astro' import Tooltip from '../../components/Tooltip.astro' import { getAttributeCategoryInfo } from '../../constants/attributeCategories' import { getAttributeTypeInfo } from '../../constants/attributeTypes' import BaseLayout from '../../layouts/BaseLayout.astro' import { cn } from '../../lib/cn' import { formatNumber } from '../../lib/numbers' import { zodParseQueryParamsStoringErrors } from '../../lib/parseUrlFilters' import { prisma } from '../../lib/prisma' const search = Astro.url.searchParams.get('search') ?? '' const categoryFilter = z .nativeEnum(AttributeCategory) .nullable() // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing .parse(Astro.url.searchParams.get('category') || null) const typeFilter = z .nativeEnum(AttributeType) .nullable() // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing .parse(Astro.url.searchParams.get('type') || null) const { data: filters } = zodParseQueryParamsStoringErrors( { 'sort-by': z .enum(['title', 'category', 'type', 'privacyPoints', 'trustPoints', 'serviceCount']) .default('title'), 'sort-order': z.enum(['asc', 'desc']).default('asc'), }, Astro ) const createResult = Astro.getActionResult(actions.admin.attribute.create) Astro.locals.banners.addIfSuccess(createResult, 'Attribute created successfully') const createInputErrors = isInputError(createResult?.error) ? createResult.error.fields : {} const updateResult = Astro.getActionResult(actions.admin.attribute.update) Astro.locals.banners.addIfSuccess(updateResult, 'Attribute updated successfully') const sortBy = filters['sort-by'] const sortOrder = filters['sort-order'] const whereClause: Prisma.AttributeWhereInput = { ...(search ? { OR: [ { title: { contains: search, mode: 'insensitive' } }, { description: { contains: search, mode: 'insensitive' } }, { slug: { contains: search, mode: 'insensitive' } }, ], } : {}), category: categoryFilter ?? undefined, type: typeFilter ?? undefined, } let prismaOrderBy: Record = { title: 'asc' } // Default sort // Ensure sortBy is a valid key for Attribute model for Prisma ordering const validPrismaSortKeys = ['title', 'slug', 'privacyPoints', 'trustPoints', 'createdAt', 'updatedAt'] // Add other valid direct fields if needed if (validPrismaSortKeys.includes(sortBy)) { prismaOrderBy = { [sortBy]: sortOrder } } else { // If sortBy is not a direct DB field (like category, type, serviceCount), // Prisma will use its default (title: asc) or the last valid key set. // The actual sorting for these custom cases will happen in JS after fetch. if (sortBy === 'category' || sortBy === 'type' || sortBy === 'serviceCount') { // Keep default prisma sort, JS will handle it } else { // Fallback if an unexpected sort key is provided, perhaps log this or handle error console.warn(`Unsupported Prisma sort key: ${sortBy}. Defaulting to title sort.`) prismaOrderBy = { title: 'asc' } } } let attributes = await Astro.locals.banners.try( 'Error fetching attributes', async () => prisma.attribute.findMany({ where: whereClause, orderBy: prismaOrderBy, include: { services: { select: { serviceId: true, }, }, }, }), [] ) let attributesWithDetails = attributes.map((attribute) => ({ ...attribute, categoryInfo: getAttributeCategoryInfo(attribute.category), typeInfo: getAttributeTypeInfo(attribute.type), serviceCount: attribute.services.length, })) if (sortBy === 'category') { attributesWithDetails = lodashOrderBy( attributesWithDetails, [(item) => item.categoryInfo.order], [sortOrder] ) } else if (sortBy === 'type') { attributesWithDetails = lodashOrderBy(attributesWithDetails, [(item) => item.typeInfo.order], [sortOrder]) } else if (sortBy === 'serviceCount') { attributesWithDetails = lodashOrderBy(attributesWithDetails, ['serviceCount'], [sortOrder]) } const attributeCount = attributesWithDetails.length const makeSortUrl = (slug: NonNullable<(typeof filters)['sort-by']>) => { const currentSortBy = filters['sort-by'] const currentSortOrder = filters['sort-order'] const newSortOrder = currentSortBy === slug && currentSortOrder === 'asc' ? 'desc' : 'asc' const searchParams = new URLSearchParams(Astro.url.search) searchParams.set('sort-by', slug) searchParams.set('sort-order', newSortOrder) return `/admin/attributes?${searchParams.toString()}` } ---

Attribute Management

{attributeCount} attributes