Add product detail and listing pages with API integration

- Created a new product detail page to display individual product information, including images, descriptions, and pricing.
- Implemented a product listing page to showcase all available products using the ProductCard and ProductGrid components.
- Added API endpoints for fetching product data, ensuring only active products are returned.
- Introduced a database seed script to populate the database with initial mock product data for development and testing.
- Updated settings to include new database seeding command and adjusted routing for product links.
This commit is contained in:
Bastian Masanek
2025-11-01 19:07:59 +01:00
parent 9150af3ac2
commit 7ab80a6635
9 changed files with 600 additions and 60 deletions

View File

@@ -0,0 +1,50 @@
/**
* GET /api/products/[id]
*
* Returns a single product by UUID.
* Returns 404 if product is not found or is inactive.
*/
import { z } from 'zod'
import { and, eq } from 'drizzle-orm'
import { products } from '../../database/schema'
// UUID validation schema
const paramsSchema = z.object({
id: z.string().uuid('Invalid product ID format'),
})
export default defineEventHandler(async (event) => {
const db = useDatabase()
// Validate and extract product ID from route params
const params = await getValidatedRouterParams(event, paramsSchema.parse)
try {
// Fetch product by ID (must be active)
const product = await db.query.products.findFirst({
where: and(eq(products.id, params.id), eq(products.active, true)),
})
// Return 404 if product not found or inactive
if (!product) {
throw createError({
statusCode: 404,
statusMessage: 'Product not found',
})
}
return product
} catch (error) {
// Re-throw createError errors as-is
if (error && typeof error === 'object' && 'statusCode' in error) {
throw error
}
console.error('Error fetching product:', error)
throw createError({
statusCode: 500,
statusMessage: 'Failed to fetch product',
})
}
})

View File

@@ -0,0 +1,29 @@
/**
* GET /api/products
*
* Returns a list of all active products available for purchase.
* Products are sorted by category and name.
*/
import { eq } from 'drizzle-orm'
import { products } from '../../database/schema'
export default defineEventHandler(async (event) => {
const db = useDatabase()
try {
// Fetch all active products
const allProducts = await db.query.products.findMany({
where: eq(products.active, true),
orderBy: (products, { asc }) => [asc(products.category), asc(products.name)],
})
return allProducts
} catch (error) {
console.error('Error fetching products:', error)
throw createError({
statusCode: 500,
statusMessage: 'Failed to fetch products',
})
}
})