Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
provider = "prisma-client-js"
previewFeatures = ["referentialIntegrity"]
}

Expand Down Expand Up @@ -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?
Expand Down
4 changes: 3 additions & 1 deletion src/components/Global/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const Input = ({
value,
setInputVal,
disabled,
onClick
onClick,
pattern
}: InputProps) => {
const [input, setInput] = useState('');

Expand Down Expand Up @@ -45,6 +46,7 @@ const Input = ({
}}
disabled={disabled} // This will be false if disabled is not passed in
onClick={onClick}
pattern={pattern}
/>
</div>
</>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Global/LogStatusButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const LogStatusButton = ({ status, useLogIn }: LogStatusButtonProps) => {
) : useLogIn ? (
<Button style={'flat'} content={'Login'} onClick={() => signIn()} />
) : (
<Button style={'flat'} content={'Sign In'} link={'/auth/signup'} />
<Button style={'flat'} content={'Sign Up'} link={'/auth/signup'} />
);
};

Expand Down
36 changes: 19 additions & 17 deletions src/components/Global/Navbar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import React, {useState, useEffect, useCallback} from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import styles from './Navbar.module.scss';

import Link from 'next/link';
import Image from 'next/image';
import {useRouter} from 'next/router';
import {Button, Logo, Sidebar, LogStatusButton} from '..';
import {HeaderProps} from '../../../types/global';
import {isAdmin} from '../../../services';
import {useSession} from 'next-auth/react';
import { useRouter } from 'next/router';
import { Button, Logo, Sidebar, LogStatusButton } from '..';
import { HeaderProps } from '../../../types/global';
import { isAdmin } from '../../../services';
import { useSession } from 'next-auth/react';

const Header = ({profilePicture}: HeaderProps) => {
const Header = ({ profilePicture }: HeaderProps) => {
const [activeTab, setActiveTab] = useState<0 | 1>(0);
const router = useRouter();
const [validAdmin, setValidAdmin] = useState(false);
const {data: session, status} = useSession();
const { data: session, status } = useSession();
const email = session?.user?.email;
const [menuOpen, setMenuOpen] = useState<boolean>(false);

useEffect(() => {
isAdmin({email}).then(res => setValidAdmin(res));
isAdmin({ email }).then(res => setValidAdmin(res));
}, [email]);

const openMenu = () => {
setMenuOpen(true);
};

const NavContent = useCallback(
(displayMenu: boolean) => {
return (
Expand Down Expand Up @@ -53,11 +53,13 @@ const Header = ({profilePicture}: HeaderProps) => {
</nav>
{status !== 'authenticated' ? (
<div className={styles.right}>
<LogStatusButton status={status} useLogIn/>
<LogStatusButton status={status} useLogIn />
</div>
) : (
<>
{validAdmin && <Button style={'flat'} content={'Admin'} link={'/admin'}/>}
{validAdmin && (
<Button style={'flat'} content={'Admin'} link={'/admin'} />
)}
<Button
style={'outline'}
content={'Profile'}
Expand All @@ -80,10 +82,10 @@ const Header = ({profilePicture}: HeaderProps) => {
},
[router.asPath, status, validAdmin, profilePicture]
);

return (
<div className={styles.header}>
<Logo showMark={true} showType={true} link={true}/>
<Logo showMark={true} showType={true} link={true} />
<div className={styles.header_content}>{NavContent(false)}</div>
<button className={styles.header_menu__button} onClick={openMenu}>
<svg
Expand All @@ -102,7 +104,7 @@ const Header = ({profilePicture}: HeaderProps) => {
</svg>
</button>
<Sidebar sidebarOpen={menuOpen} setSidebarOpen={setMenuOpen}>
<Logo showMark={true} showType={false} link={true}/>
<Logo showMark={true} showType={false} link={true} />
{NavContent(true)}
</Sidebar>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/admin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[] }) => {
Expand Down
50 changes: 50 additions & 0 deletions src/pages/api/birthYear/birthYear.ts
Original file line number Diff line number Diff line change
@@ -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;
55 changes: 55 additions & 0 deletions src/pages/auth/birthYear/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<main className={styles.birthYearPage}>
<Logo showMark={true} showType={true} link={true} />
<h2 className={styles.title}>Birth Year</h2>
{/*<p>This is the last step to finish user setup. You are almost there!!</p>*/}
<form className={styles.inputSection}>
<Input
type={'text'}
id={'birthYear'}
required={true}
pattern={'.{4}'}
placeholder={'Enter birth year: yyyy'}
setInputVal={setBirthString}
/>
<Button
style={'primary'}
content={'Add Birth Year'}
type={'submit'}
onClick={submitHandler}
/>
</form>
</main>
);
};
//TODO: redirect back to puzzle submission (or wherever user came from)
export default BirthYearPage;
5 changes: 3 additions & 2 deletions src/pages/auth/profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand Down Expand Up @@ -143,7 +144,7 @@ const ProfilePage = () => {
<span>Birth year:</span>
{/* TODO: Load birthyear */}
<Input
type="number"
type="text"
id="birthyear"
placeholder={''}
required={false}
Expand Down
6 changes: 6 additions & 0 deletions src/services/birthYear.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Axios from './axios';
import { addBirthYearProp } from '../types/api/birthYear';

export const addBirthYear = async (data: addBirthYearProp) => {
return Axios.post('api/birthYear/birthYear', data);
};
43 changes: 43 additions & 0 deletions src/styles/pages/birthYear.module.scss
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
}
4 changes: 4 additions & 0 deletions src/types/api/birthYear/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type addBirthYearProp = {
birthYear: string;
email: string;
};
3 changes: 2 additions & 1 deletion src/types/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -24,4 +24,5 @@ export type InputProps = {
setInputVal?: Dispatch<SetStateAction<string>>;
disabled?: boolean;
onClick?: () => void;
pattern?: string;
};