diff --git a/apps/portal/prisma/migrations/20221006064944_add_resume_schemas/migration.sql b/apps/portal/prisma/migrations/20221006090216_add_resume_schemas/migration.sql similarity index 95% rename from apps/portal/prisma/migrations/20221006064944_add_resume_schemas/migration.sql rename to apps/portal/prisma/migrations/20221006090216_add_resume_schemas/migration.sql index 67b66abf..fac3cdd7 100644 --- a/apps/portal/prisma/migrations/20221006064944_add_resume_schemas/migration.sql +++ b/apps/portal/prisma/migrations/20221006090216_add_resume_schemas/migration.sql @@ -6,8 +6,11 @@ CREATE TABLE "ResumesResume" ( "id" TEXT NOT NULL, "userId" TEXT NOT NULL, "title" TEXT NOT NULL, - "additionalInfo" TEXT NOT NULL, + "role" TEXT NOT NULL, + "experience" TEXT NOT NULL, + "location" TEXT NOT NULL, "url" TEXT NOT NULL, + "additionalInfo" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, diff --git a/apps/portal/prisma/schema.prisma b/apps/portal/prisma/schema.prisma index b62ad310..95c4381f 100644 --- a/apps/portal/prisma/schema.prisma +++ b/apps/portal/prisma/schema.prisma @@ -94,9 +94,12 @@ model ResumesResume { id String @id @default(cuid()) userId String title String @db.Text - additionalInfo String @db.Text - // TODO: Add role, experience, location from Enums + // TODO: Update role, experience, location to use Enums + role String @db.Text + experience String @db.Text + location String @db.Text url String + additionalInfo String? @db.Text createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) diff --git a/apps/portal/src/pages/resumes/submit.tsx b/apps/portal/src/pages/resumes/submit.tsx index e725a730..54bb0e6d 100644 --- a/apps/portal/src/pages/resumes/submit.tsx +++ b/apps/portal/src/pages/resumes/submit.tsx @@ -1,10 +1,13 @@ import Head from 'next/head'; +import { useRouter } from 'next/router'; import { useMemo, useState } from 'react'; import type { SubmitHandler } from 'react-hook-form'; import { useForm } from 'react-hook-form'; import { PaperClipIcon } from '@heroicons/react/24/outline'; import { Button, Select, TextInput } from '@tih/ui'; +import { trpc } from '~/utils/trpc'; + const TITLE_PLACEHOLDER = 'e.g. Applying for Company XYZ, please help me to review!'; const ADDITIONAL_INFO_PLACEHOLDER = `e.g. I’m applying for company XYZ. I have been resume-rejected by N companies that I have applied for. Please help me to review so company XYZ gives me an interview!`; @@ -13,7 +16,7 @@ const FILE_UPLOAD_ERROR = 'Please upload a PDF file that is less than 10MB.'; const MAX_FILE_SIZE_LIMIT = 10485760; type IFormInput = { - additionalInformation?: string; + additionalInfo?: string; experience: string; file: File; location: string; @@ -68,6 +71,9 @@ export default function SubmitResumeForm() { }, ]; + const resumeCreateMutation = trpc.useMutation('resumes.resume.user.create'); + const router = useRouter(); + const [resumeFile, setResumeFile] = useState(); const [invalidFileUploadError, setInvalidFileUploadError] = useState< string | null @@ -81,10 +87,11 @@ export default function SubmitResumeForm() { formState: { errors }, } = useForm(); - // TODO: Add Create resume mutation - const onSubmit: SubmitHandler = (data) => { - alert(JSON.stringify(data)); - onClickReset(); + const onSubmit: SubmitHandler = async (data) => { + await resumeCreateMutation.mutate({ + ...data, + }); + router.push('/resumes'); }; const onUploadFile = (event: React.ChangeEvent) => { @@ -196,10 +203,10 @@ export default function SubmitResumeForm() {
{/* TODO: Use TextInputArea instead */} setValue('additionalInformation', val)} + onChange={(val) => setValue('additionalInfo', val)} />
diff --git a/apps/portal/src/server/router/index.ts b/apps/portal/src/server/router/index.ts index 050f95ea..92cb47cf 100644 --- a/apps/portal/src/server/router/index.ts +++ b/apps/portal/src/server/router/index.ts @@ -2,6 +2,7 @@ import superjson from 'superjson'; import { createRouter } from './context'; import { protectedExampleRouter } from './protected-example-router'; +import { resumesResumeUserRouter } from './resumes-resume-user-router'; import { todosRouter } from './todos'; import { todosUserRouter } from './todos-user-router'; @@ -12,7 +13,8 @@ export const appRouter = createRouter() // Example routers. Learn more about tRPC routers: https://trpc.io/docs/v9/router .merge('auth.', protectedExampleRouter) .merge('todos.', todosRouter) - .merge('todos.user.', todosUserRouter); + .merge('todos.user.', todosUserRouter) + .merge('resumes.resume.user.', resumesResumeUserRouter); // Export type definition of API export type AppRouter = typeof appRouter; diff --git a/apps/portal/src/server/router/resumes-resume-user-router.ts b/apps/portal/src/server/router/resumes-resume-user-router.ts new file mode 100644 index 00000000..3d47ee57 --- /dev/null +++ b/apps/portal/src/server/router/resumes-resume-user-router.ts @@ -0,0 +1,30 @@ +import { z } from 'zod'; + +import { createProtectedRouter } from './context'; + +export const resumesResumeUserRouter = createProtectedRouter().mutation( + 'create', + { + // TODO: Use enums for experience, location, role + input: z.object({ + additionalInfo: z.string().optional(), + experience: z.string(), + location: z.string(), + role: z.string(), + title: z.string(), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user.id; + + // TODO: Store file in file storage and retrieve URL + + return await ctx.prisma.resumesResume.create({ + data: { + ...input, + url: '', + userId, + }, + }); + }, + }, +);