diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 23328ae..ae519a9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,10 +1,11 @@ + datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" previewFeatures = ["referentialIntegrity"] } @@ -48,6 +49,7 @@ model User { id Int @id @default(autoincrement()) email String? @unique password String? + birthYear String? name String? @unique emailVerified DateTime? @map(name: "emailVerified") image String? diff --git a/src/components/Global/Input/index.tsx b/src/components/Global/Input/index.tsx index 27fd4b0..088e3fc 100644 --- a/src/components/Global/Input/index.tsx +++ b/src/components/Global/Input/index.tsx @@ -13,7 +13,8 @@ const Input = ({ value, setInputVal, disabled, - onClick + onClick, + pattern }: InputProps) => { const [input, setInput] = useState(''); @@ -45,6 +46,7 @@ const Input = ({ }} disabled={disabled} // This will be false if disabled is not passed in onClick={onClick} + pattern={pattern} /> diff --git a/src/components/Global/LogStatusButton/index.tsx b/src/components/Global/LogStatusButton/index.tsx index a7577aa..32fc90f 100644 --- a/src/components/Global/LogStatusButton/index.tsx +++ b/src/components/Global/LogStatusButton/index.tsx @@ -9,7 +9,7 @@ const LogStatusButton = ({ status, useLogIn }: LogStatusButtonProps) => { ) : useLogIn ? ( - + {NavContent(true)} diff --git a/src/pages/admin/index.tsx b/src/pages/admin/index.tsx index a1a7c8b..e6c4d13 100644 --- a/src/pages/admin/index.tsx +++ b/src/pages/admin/index.tsx @@ -9,7 +9,7 @@ import { } from '../../components/App'; import { getAllPuzzles, isAdmin } from '../../services'; import { GetServerSideProps } from 'next'; -import { Header } from '../../components/Global'; +import { Header } from '../../components/Product'; import type { PuzzleCustom } from '../../types/api/puzzles/puzzle'; const Admin = ({ puzzlesList }: { puzzlesList: PuzzleCustom[] }) => { diff --git a/src/pages/api/birthYear/birthYear.ts b/src/pages/api/birthYear/birthYear.ts new file mode 100644 index 0000000..a8bfe5b --- /dev/null +++ b/src/pages/api/birthYear/birthYear.ts @@ -0,0 +1,50 @@ +import { PrismaClient } from '@prisma/client'; +import { NextApiRequest, NextApiResponse } from 'next'; +import { addBirthYearProp } from '../../../types/api/birthYear'; + +const prisma = new PrismaClient(); +const birthYearHandler = async (req: NextApiRequest, res: NextApiResponse) => { + //check (1)birthYearPage: (a)too big: if birthYearPage > 2022 (b) too small: birthYearPage <= 1900 (2) check if user exist? + const { birthYear, email } = req.body as addBirthYearProp; + + if (parseInt(birthYear) > new Date().getFullYear()) { + res.status(400).json({ + message: 'Birth year cannot be greater than the current year' + }); + return; + } + + if (parseInt(birthYear) <= new Date().getFullYear() - 100) { + res.status(400).json({ + message: 'Birth year too small. There might be a typo.' + }); + return; + } + + const user = await prisma.user.findUnique({ + where: { + email + } + }); + + if (!user) { + res.status(400).json({ + message: 'User not found' + }); + return; + } + + await prisma.user.update({ + where: { + email + }, + data: { + birthYear: birthYear + } + }); + + res.status(200).json({ + message: 'Birth year successfully added to user profile' + }); +}; +export default birthYearHandler; diff --git a/src/pages/auth/birthYear/index.tsx b/src/pages/auth/birthYear/index.tsx new file mode 100644 index 0000000..0734446 --- /dev/null +++ b/src/pages/auth/birthYear/index.tsx @@ -0,0 +1,55 @@ +import React, { useState } from 'react'; +import { Button, Input, Logo } from '../../../components/Global'; +import { useSession } from 'next-auth/react'; +import { addBirthYear } from '../../../services/birthYear'; +import styles from '../../../styles/pages/birthYear.module.scss'; + +const BirthYearPage = () => { + //design it to look like sign-up page & say this is the last step for setting up the account + const { data: session, status } = useSession(); + const [birthString, setBirthString] = useState('-1'); + + const checkBirthYearRange = (birthInt: number) => { + //TODO: add toaster to notify the user of typo + if (birthInt > new Date().getFullYear()) return; + if (birthInt <= new Date().getFullYear() - 100) return; + return true; + }; + const submitHandler = async () => { + const email = session?.user?.email; + if (!email) return; + if (typeof birthString !== 'number') return; + const birthInt = parseInt(birthString); + if (checkBirthYearRange(birthInt) === false) return; + + await addBirthYear({ + birthYear: birthString, + email: email + }); + }; + return ( +
+ +

Birth Year

+ {/*

This is the last step to finish user setup. You are almost there!!

*/} +
+ +
+ ); +}; +//TODO: redirect back to puzzle submission (or wherever user came from) +export default BirthYearPage; diff --git a/src/pages/auth/profile/index.tsx b/src/pages/auth/profile/index.tsx index 32a896e..1895866 100644 --- a/src/pages/auth/profile/index.tsx +++ b/src/pages/auth/profile/index.tsx @@ -9,7 +9,8 @@ import { getUserByEmail, updateUsername } from '../../../services'; -import { Header, Input, Button } from '../../../components/Global'; +import { Input, Button } from '../../../components/Global'; +import { Header } from '../../../components/Product'; import styles from '../../../styles/pages/profile.module.scss'; const ProfilePage = () => { @@ -143,7 +144,7 @@ const ProfilePage = () => { Birth year: {/* TODO: Load birthyear */} { + return Axios.post('api/birthYear/birthYear', data); +}; diff --git a/src/styles/pages/birthYear.module.scss b/src/styles/pages/birthYear.module.scss new file mode 100644 index 0000000..0dd6078 --- /dev/null +++ b/src/styles/pages/birthYear.module.scss @@ -0,0 +1,43 @@ +@import 'src/styles/abstracts/_variables'; +@import 'src/styles/abstracts/_mixins'; + +.birthYearPage { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100vh; + width: 100vw; +} + +.title { + font-size: 2.25rem; + text-align: center; +} + +.inputSection { + display: flex; + flex-direction: column; + gap: 1rem; + width: 20rem; + padding: 1rem; + + @include mobile() { + width: 100%; + } + + .buttonContainer { + margin-top: 1rem; + display: flex; + flex-direction: column; + gap: 1rem; + + button { + width: 100%; + + div { + justify-content: center; + } + } + } +} diff --git a/src/types/api/birthYear/index.ts b/src/types/api/birthYear/index.ts new file mode 100644 index 0000000..acaaccb --- /dev/null +++ b/src/types/api/birthYear/index.ts @@ -0,0 +1,4 @@ +export type addBirthYearProp = { + birthYear: string; + email: string; +}; diff --git a/src/types/global.ts b/src/types/global.ts index 661e9ba..473d658 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -13,7 +13,7 @@ export type LogoProps = { }; export type InputProps = { - type: 'text' | 'password' | 'email' | 'number'; + type: 'text' | 'password' | 'email'; id: string; required: boolean; placeholder?: string; @@ -24,4 +24,5 @@ export type InputProps = { setInputVal?: Dispatch>; disabled?: boolean; onClick?: () => void; + pattern?: string; };