From 330247b3b7536bccef890f4e0b229003de98adf4 Mon Sep 17 00:00:00 2001 From: Riccardo Date: Sun, 7 Jul 2024 22:52:00 +0200 Subject: [PATCH] feat: add index and create customer form --- README.md | 2 +- app/api/protected/customer-form/[id]/route.ts | 81 ++++++++++++++++--- app/api/protected/customer-form/route.ts | 13 ++- app/customer-form/[id]/page.tsx | 35 +++++++- app/customer-form/page.tsx | 34 ++++---- app/globals.css | 4 +- components/Input.tsx | 15 +--- utils/types.ts | 15 +++- 8 files changed, 149 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 6070e46..ca76ca1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - [ ] Add user profile and settings (i.e. language) - [ ] Add user roles - [ ] Add user permissions -- [ ] Add module CRUD with protected routes +- [ ] Add customer form CRUD with protected routes - [ ] Customize Auth0 login page - [ ] Add user notifications and emails - [ ] Add user invoices diff --git a/app/api/protected/customer-form/[id]/route.ts b/app/api/protected/customer-form/[id]/route.ts index 7f6791a..d6ecbae 100644 --- a/app/api/protected/customer-form/[id]/route.ts +++ b/app/api/protected/customer-form/[id]/route.ts @@ -1,22 +1,83 @@ +import { getSession, withApiAuthRequired } from '@auth0/nextjs-auth0'; +import { CustomerFormType } from '@prisma/client'; +import prisma from '@prisma/prisma'; +import { CustomerForm } from '@utils/types'; import { NextRequest, NextResponse } from 'next/server'; -export async function GET( - request: NextRequest, - { params }: { params: { id: number } } -) { - return NextResponse.json(`GET ${params.id}`); -} +export const GET = withApiAuthRequired(async request => { + const session = await getSession(); + + const x = console.log('request', request); + + const result = await prisma.customerForm.findUnique({ + where: { + id: 'params.id', + createdBy: { + email: session?.user.email + } + } + }); + + if (!result) { + return NextResponse.json( + { success: false, message: 'Something went wrong.' }, + { status: 500 } + ); + } + + return NextResponse.json({ success: true, data: [] }); +}); export async function PUT( request: NextRequest, - { params }: { params: { id: number } } + { params }: { params: CustomerForm } ) { - return NextResponse.json(`PUT ${params.id}`); + const session = await getSession(); + + const result = await prisma.customerForm.update({ + where: { + id: params.id, + createdBy: { + email: session?.user.email + } + }, + data: { + type: params.type as CustomerFormType, + text: params.text + } + }); + + if (!result) { + return NextResponse.json( + { success: false, message: 'Something went wrong.' }, + { status: 500 } + ); + } + + return NextResponse.json({ success: true, data: result }); } export async function DELETE( request: NextRequest, - { params }: { params: { id: number } } + { params }: { params: { id: string } } ) { - return NextResponse.json(`DELETE ${params.id}`); + const session = await getSession(); + + const result = await prisma.customerForm.delete({ + where: { + id: params.id, + createdBy: { + email: session?.user.email + } + } + }); + + if (!result) { + return NextResponse.json( + { success: false, message: 'Something went wrong.' }, + { status: 500 } + ); + } + + return NextResponse.json({ success: true }); } diff --git a/app/api/protected/customer-form/route.ts b/app/api/protected/customer-form/route.ts index 25ef8bf..43c4317 100644 --- a/app/api/protected/customer-form/route.ts +++ b/app/api/protected/customer-form/route.ts @@ -1,14 +1,13 @@ import { getSession, withApiAuthRequired } from '@auth0/nextjs-auth0'; import { CustomerForm } from '@prisma/client'; import prisma from '@prisma/prisma'; -import { randomUUID } from 'crypto'; import { NextResponse } from 'next/server'; export const GET = withApiAuthRequired(async () => { const session = await getSession(); try { - const userModules = await prisma.user.findUniqueOrThrow({ + const userCustomerForms = await prisma.user.findUniqueOrThrow({ where: { email: session?.user.email }, @@ -17,7 +16,7 @@ export const GET = withApiAuthRequired(async () => { } }); - const customerForms: CustomerForm[] = userModules.CustomerForm; + const customerForms: CustomerForm[] = userCustomerForms.CustomerForm; return NextResponse.json({ success: true, data: customerForms }); } catch (error) { @@ -40,10 +39,16 @@ export const POST = withApiAuthRequired(async request => { text: body.text, createdBy: { connect: { - id: randomUUID(), email: session?.user.email } } + }, + select: { + id: true, + type: true, + text: true, + createdAt: true, + updatedAt: true } }); diff --git a/app/customer-form/[id]/page.tsx b/app/customer-form/[id]/page.tsx index cf74286..cf59c61 100644 --- a/app/customer-form/[id]/page.tsx +++ b/app/customer-form/[id]/page.tsx @@ -1,9 +1,42 @@ 'use client'; +import { CustomerForm, CustomerFormSchema } from '@utils/types'; +import axios from 'axios'; +import { useEffect, useState } from 'react'; + export default function SingleCustomerForm({ params }: { params: { id: string }; }) { - return
Module {params.id}
; + const [customerForm, setCustomerForm] = useState(null); + + useEffect(() => { + (async () => { + const response = await axios.get( + `/api/protected/customer-form/${params.id}` + ); + + const validatedResponse = CustomerFormSchema.safeParse( + response.data.data + ); + + if (!validatedResponse.success) { + console.error(validatedResponse.error); + return; + } + + setCustomerForm(validatedResponse.data); + })(); + }, [params.id]); + + if (!customerForm) { + return
Loading...
; + } + + return ( +
+ Form {params.id} {JSON.stringify(customerForm)} +
+ ); } diff --git a/app/customer-form/page.tsx b/app/customer-form/page.tsx index 65b0924..c94b93e 100644 --- a/app/customer-form/page.tsx +++ b/app/customer-form/page.tsx @@ -10,6 +10,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { CustomerFormType } from '@prisma/client'; import { CustomerForm, + CustomerFormCreate, + CustomerFormCreateSchema, CustomerFormListSchema, CustomerFormSchema } from '@utils/types'; @@ -17,11 +19,11 @@ import axios from 'axios'; import { useEffect, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; -export default function Modules() { - const [modules, setModules] = useState([]); +export default function CustomerForms() { + const [customerForms, setCustomerForms] = useState([]); - const form = useForm({ - resolver: zodResolver(CustomerFormSchema), + const form = useForm({ + resolver: zodResolver(CustomerFormCreateSchema), defaultValues: { type: CustomerFormType.TYPE1, text: '' @@ -41,11 +43,11 @@ export default function Modules() { return; } - setModules(validatedResponse.data); + setCustomerForms(validatedResponse.data); })(); }, []); - async function handleSubmit(values: CustomerForm) { + async function handleSubmit(values: CustomerFormCreate) { console.log('values', values); try { @@ -62,6 +64,8 @@ export default function Modules() { } ); + console.log('response', response.data.data); + const validatedResponse = CustomerFormSchema.safeParse( response.data.data ); @@ -71,7 +75,7 @@ export default function Modules() { return; } - setModules([...modules, validatedResponse.data]); + setCustomerForms([...customerForms, validatedResponse.data]); } catch (error) { console.error(error); } @@ -79,15 +83,15 @@ export default function Modules() { return ( <> -

Modules

- {modules && - modules.map(module => ( -
-

{module.type}

-

{module.text}

+

Forms

+ {customerForms && + customerForms.map(customerForm => ( +
+

{customerForm.type}

+

{customerForm.text}

))} -

Create Module

+

New form

)} /> - +
diff --git a/app/globals.css b/app/globals.css index 875c01e..5c8f2e5 100644 --- a/app/globals.css +++ b/app/globals.css @@ -16,7 +16,7 @@ } } -body { +/* body { color: rgb(var(--foreground-rgb)); background: linear-gradient( to bottom, @@ -24,7 +24,7 @@ body { rgb(var(--background-end-rgb)) ) rgb(var(--background-start-rgb)); -} +} */ @layer utilities { .text-balance { diff --git a/components/Input.tsx b/components/Input.tsx index ac87667..de2c09b 100644 --- a/components/Input.tsx +++ b/components/Input.tsx @@ -1,21 +1,10 @@ -import { cn } from '@utils/cn'; import * as React from 'react'; const Input = React.forwardRef< HTMLInputElement, React.InputHTMLAttributes ->(({ className, type, ...props }, ref) => { - return ( - - ); +>(({ type, ...props }, ref) => { + return ; }); Input.displayName = 'Input'; diff --git a/utils/types.ts b/utils/types.ts index 7d65365..9256bc8 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -5,18 +5,25 @@ export const UserSchema = z.object({ name: z.string(), email: z.string().email(), deleted: z.boolean(), - createdAt: z.date().transform(date => date.toISOString()), - updatedAt: z.date().transform(date => date.toISOString()) + createdAt: z.string().transform(arg => new Date(arg)), + updatedAt: z.string().transform(arg => new Date(arg)) }); export type User = z.infer; +export const CustomerFormCreateSchema = z.object({ + type: z.string(), + text: z.string() +}); + +export type CustomerFormCreate = z.infer; + export const CustomerFormSchema = z.object({ id: z.string(), type: z.string(), text: z.string(), - createdAt: z.date().transform(date => date.toISOString()), - updatedAt: z.date().transform(date => date.toISOString()) + createdAt: z.string().transform(arg => new Date(arg)), + updatedAt: z.string().transform(arg => new Date(arg)) }); export const CustomerFormListSchema = z.array(CustomerFormSchema);