| import { Request, Response } from 'express';
|
| import prisma from '../models/prisma';
|
| import slugify from 'slugify';
|
| import { z } from 'zod';
|
|
|
| const portfolioSchema = z.object({
|
| title: z.string().min(1, 'Title is required'),
|
| slug: z.string().min(1, 'Slug is required').regex(/^[a-z0-9-]+$/, 'Slug must be lowercase letters, numbers, and hyphens only'),
|
| description: z.string().min(1, 'Description is required'),
|
| technologies: z.string().nullable().optional(),
|
| imageUrl: z.string().nullable().optional(),
|
| clientName: z.string().nullable().optional(),
|
| industry: z.string().nullable().optional(),
|
| testimonials: z.string().nullable().optional(),
|
| });
|
|
|
|
|
|
|
| export const getAllPortfolioItems = async (_req: Request, res: Response) => {
|
| try {
|
| const items = await prisma.portfolioItem.findMany({
|
| orderBy: { createdAt: 'desc' },
|
| include: { author: { select: { name: true, email: true } } },
|
| });
|
| return res.json(items);
|
| } catch (error) {
|
| console.error('Get portfolio items error:', error);
|
| return res.status(500).json({ error: 'Internal server error' });
|
| }
|
| };
|
|
|
|
|
| export const getPortfolioItem = async (req: Request, res: Response) => {
|
| try {
|
| const item = await prisma.portfolioItem.findUnique({
|
| where: { id: req.params.id },
|
| include: { author: { select: { name: true, email: true } } },
|
| });
|
| if (!item) return res.status(404).json({ error: 'Not found' });
|
| return res.json(item);
|
| } catch (error) {
|
| console.error('Get portfolio item error:', error);
|
| return res.status(500).json({ error: 'Internal server error' });
|
| }
|
| };
|
|
|
|
|
| export const createPortfolioItem = async (req: Request, res: Response) => {
|
| try {
|
| const validatedData = portfolioSchema.parse(req.body);
|
| const { title, slug, description, technologies, imageUrl, clientName, industry, testimonials } = validatedData;
|
|
|
|
|
| const existing = await prisma.portfolioItem.findUnique({ where: { slug } });
|
| if (existing) {
|
| return res.status(409).json({ error: 'Slug already exists' });
|
| }
|
|
|
| const item = await prisma.portfolioItem.create({
|
| data: {
|
| title,
|
| slug,
|
| description,
|
| technologies: technologies || null,
|
| imageUrl: imageUrl || null,
|
| clientName: clientName || null,
|
| industry: industry || null,
|
| testimonials: testimonials || null,
|
| },
|
| });
|
|
|
| return res.status(201).json(item);
|
| } catch (error: any) {
|
| if (error instanceof z.ZodError) {
|
| return res.status(400).json({ error: error.errors[0].message });
|
| }
|
| console.error('Create portfolio item error:', error);
|
| return res.status(500).json({ error: 'Internal server error' });
|
| }
|
| };
|
|
|
|
|
| export const updatePortfolioItem = async (req: Request, res: Response) => {
|
| try {
|
| const { id } = req.params;
|
| const validatedData = portfolioSchema.partial().parse(req.body);
|
| const { title, slug, description, technologies, imageUrl, clientName, industry, testimonials } = validatedData;
|
|
|
|
|
| const existing = await prisma.portfolioItem.findUnique({ where: { id } });
|
| if (!existing) return res.status(404).json({ error: 'Not found' });
|
|
|
|
|
| if (slug && slug !== existing.slug) {
|
| const slugExists = await prisma.portfolioItem.findUnique({ where: { slug } });
|
| if (slugExists) return res.status(409).json({ error: 'Slug already exists' });
|
| }
|
|
|
| const item = await prisma.portfolioItem.update({
|
| where: { id },
|
| data: {
|
| ...(title !== undefined && { title }),
|
| ...(slug !== undefined && { slug }),
|
| ...(description !== undefined && { description }),
|
| ...(technologies !== undefined && { technologies }),
|
| ...(imageUrl !== undefined && { imageUrl }),
|
| ...(clientName !== undefined && { clientName }),
|
| ...(industry !== undefined && { industry }),
|
| ...(testimonials !== undefined && { testimonials }),
|
| },
|
| });
|
|
|
| return res.json(item);
|
| } catch (error: any) {
|
| if (error instanceof z.ZodError) {
|
| return res.status(400).json({ error: error.errors[0].message });
|
| }
|
| console.error('Update portfolio item error:', error);
|
| return res.status(500).json({ error: 'Internal server error' });
|
| }
|
| };
|
|
|
|
|
| export const deletePortfolioItem = async (req: Request, res: Response) => {
|
| try {
|
| const { id } = req.params;
|
|
|
| const existing = await prisma.portfolioItem.findUnique({ where: { id } });
|
| if (!existing) return res.status(404).json({ error: 'Not found' });
|
|
|
| await prisma.portfolioItem.delete({ where: { id } });
|
|
|
| return res.json({ message: 'Deleted successfully' });
|
| } catch (error) {
|
| console.error('Delete portfolio item error:', error);
|
| return res.status(500).json({ error: 'Internal server error' });
|
| }
|
| };
|
|
|