| @@ -0,0 +1,29 @@ | |||
| import Card from '@mui/material/Card'; | |||
| import CardContent from '@mui/material/CardContent'; | |||
| import CardMedia from '@mui/material/CardMedia'; | |||
| import Typography from '@mui/material/Typography'; | |||
| const ProfileCard = ({ profileData }) => { | |||
| return ( | |||
| <Card sx={{ maxWidth: 345, marginX: 'auto', marginY: 25, boxShadow: 10 }}> | |||
| <CardMedia | |||
| component="img" | |||
| height="140" | |||
| image="https://www.business2community.com/wp-content/uploads/2017/08/blank-profile-picture-973460_640.png" | |||
| alt="green iguana" | |||
| /> | |||
| <CardContent> | |||
| <Typography gutterBottom variant="h5" component="div"> | |||
| {profileData.name} | |||
| </Typography> | |||
| <Typography variant="body2" color="text.secondary"> | |||
| Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur | |||
| quis odio in libero fringilla pellentesque aliquet et mi. Quisque | |||
| maximus lectus a neque luctus, tempus auctor ipsum ultrices. | |||
| </Typography> | |||
| </CardContent> | |||
| </Card> | |||
| ); | |||
| }; | |||
| export default ProfileCard; | |||
| @@ -0,0 +1,7 @@ | |||
| const base = { | |||
| profileData: { name: 'John Doe' }, | |||
| }; | |||
| export const mockProfilePageProps = { | |||
| base, | |||
| }; | |||
| @@ -0,0 +1,20 @@ | |||
| import ProfileCard from './ProfileCard'; | |||
| import { mockProfilePageProps } from './ProfileCard.mock'; | |||
| const obj = { | |||
| title: 'cards/ProfileCard', | |||
| component: ProfileCard, | |||
| // More on argTypes: https://storybook.js.org/docs/react/api/argtypes | |||
| argTypes: {}, | |||
| }; //eslint-disable-line | |||
| export default obj; | |||
| // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args | |||
| const Template = (args) => <ProfileCard {...args} />; | |||
| export const Base = Template.bind({}); | |||
| // More on args: https://storybook.js.org/docs/react/writing-stories/args | |||
| Base.args = { | |||
| ...mockProfilePageProps.base, | |||
| }; | |||
| @@ -7,12 +7,15 @@ import { | |||
| Typography, | |||
| } from '@mui/material'; | |||
| import { useFormik } from 'formik'; | |||
| import { useTranslation } from 'next-i18next'; | |||
| import Link from 'next/link'; | |||
| import React from 'react'; | |||
| import { LOGIN_PAGE } from '../../../constants/pages'; | |||
| import { forgotPasswordSchema } from '../../../schemas/forgotPasswordSchema'; | |||
| const ForgotPasswordForm = () => { | |||
| const { t } = useTranslation('forms', 'forgotPass', 'common'); | |||
| const handleSubmit = (values) => { | |||
| console.log('Values', values); | |||
| }; | |||
| @@ -38,7 +41,7 @@ const ForgotPasswordForm = () => { | |||
| }} | |||
| > | |||
| <Typography component="h1" variant="h5"> | |||
| Forgot password | |||
| {t('forgotPass:Title')} | |||
| </Typography> | |||
| <Box | |||
| component="form" | |||
| @@ -47,7 +50,7 @@ const ForgotPasswordForm = () => { | |||
| > | |||
| <TextField | |||
| name="email" | |||
| label="Email" | |||
| label={t('forms:Email')} | |||
| margin="normal" | |||
| value={formik.values.email} | |||
| onChange={formik.handleChange} | |||
| @@ -62,10 +65,10 @@ const ForgotPasswordForm = () => { | |||
| sx={{ mt: 3, mb: 2 }} | |||
| fullWidth | |||
| > | |||
| Send email | |||
| {t('forgotPass:SendBtn')} | |||
| </Button> | |||
| <Grid container justifyContent="center"> | |||
| <Link href={LOGIN_PAGE}>Back</Link> | |||
| <Link href={LOGIN_PAGE}>{t('common:Back')}</Link> | |||
| </Grid> | |||
| </Box> | |||
| </Box> | |||
| @@ -10,6 +10,7 @@ import { | |||
| } from '@mui/material'; | |||
| import { useFormik } from 'formik'; | |||
| import { signIn } from 'next-auth/react'; | |||
| import { useTranslation } from 'next-i18next'; | |||
| import Link from 'next/link'; | |||
| import { useRouter } from 'next/router'; | |||
| import { useState } from 'react'; | |||
| @@ -22,6 +23,7 @@ import { loginSchema } from '../../../schemas/loginSchema'; | |||
| import ErrorMessageComponent from '../../mui/ErrorMessageComponent'; | |||
| const LoginForm = () => { | |||
| const { t } = useTranslation('forms', 'login'); | |||
| const [showPassword, setShowPassword] = useState(false); | |||
| const handleClickShowPassword = () => setShowPassword(!showPassword); | |||
| const handleMouseDownPassword = () => setShowPassword(!showPassword); | |||
| @@ -64,7 +66,7 @@ const LoginForm = () => { | |||
| }} | |||
| > | |||
| <Typography component="h1" variant="h5"> | |||
| Login | |||
| {t('login:Title')} | |||
| </Typography> | |||
| {error.hasError && <ErrorMessageComponent error={error.errorMessage} />} | |||
| <Box | |||
| @@ -74,7 +76,7 @@ const LoginForm = () => { | |||
| > | |||
| <TextField | |||
| name="username" | |||
| label="Username" | |||
| label={t('forms:Username')} | |||
| margin="normal" | |||
| value={formik.values.username} | |||
| onChange={formik.handleChange} | |||
| @@ -85,7 +87,7 @@ const LoginForm = () => { | |||
| /> | |||
| <TextField | |||
| name="password" | |||
| label="Password" | |||
| label={t('forms:Password')} | |||
| margin="normal" | |||
| type={showPassword ? 'text' : 'password'} | |||
| value={formik.values.password} | |||
| @@ -110,7 +112,7 @@ const LoginForm = () => { | |||
| sx={{ mt: 3, mb: 2 }} | |||
| fullWidth | |||
| > | |||
| Login | |||
| {t('login:LoginBtn')} | |||
| </Button> | |||
| <Grid container> | |||
| <Grid | |||
| @@ -119,7 +121,9 @@ const LoginForm = () => { | |||
| md={6} | |||
| sx={{ textAlign: { xs: 'center', md: 'left' } }} | |||
| > | |||
| <Link href={FORGOT_PASSWORD_PAGE}>Forgot your password?</Link> | |||
| <Link href={FORGOT_PASSWORD_PAGE}> | |||
| {t('login:ForgotPassword')} | |||
| </Link> | |||
| </Grid> | |||
| <Grid | |||
| item | |||
| @@ -127,7 +131,7 @@ const LoginForm = () => { | |||
| md={6} | |||
| sx={{ textAlign: { xs: 'center', md: 'right' } }} | |||
| > | |||
| <Link href={REGISTER_PAGE}>Dont have an account?</Link> | |||
| <Link href={REGISTER_PAGE}>{t('login:NoAccount')}</Link> | |||
| </Grid> | |||
| </Grid> | |||
| </Box> | |||
| @@ -9,6 +9,7 @@ import { | |||
| Typography, | |||
| } from '@mui/material'; | |||
| import { useFormik } from 'formik'; | |||
| import { useTranslation } from 'next-i18next'; | |||
| import Link from 'next/link'; | |||
| import { useState } from 'react'; | |||
| @@ -18,6 +19,8 @@ import { registerSchema } from '../../../schemas/registerSchema'; | |||
| import ErrorMessageComponent from '../../mui/ErrorMessageComponent'; | |||
| const RegisterForm = () => { | |||
| const { t } = useTranslation('forms', 'register'); | |||
| const [showPassword, setShowPassword] = useState(false); | |||
| const handleClickShowPassword = () => setShowPassword(!showPassword); | |||
| const handleMouseDownPassword = () => setShowPassword(!showPassword); | |||
| @@ -69,7 +72,7 @@ const RegisterForm = () => { | |||
| }} | |||
| > | |||
| <Typography component="h1" variant="h5"> | |||
| Register | |||
| {t('register:Title')} | |||
| </Typography> | |||
| {error.hasError && <ErrorMessageComponent error={error.errorMessage} />} | |||
| <Box | |||
| @@ -79,7 +82,7 @@ const RegisterForm = () => { | |||
| > | |||
| <TextField | |||
| name="fullName" | |||
| label="Full name" | |||
| label={t('forms:FullName')} | |||
| margin="normal" | |||
| value={formik.values.fullName} | |||
| onChange={formik.handleChange} | |||
| @@ -90,7 +93,7 @@ const RegisterForm = () => { | |||
| /> | |||
| <TextField | |||
| name="username" | |||
| label="Username" | |||
| label={t('forms:Username')} | |||
| margin="normal" | |||
| value={formik.values.username} | |||
| onChange={formik.handleChange} | |||
| @@ -100,7 +103,7 @@ const RegisterForm = () => { | |||
| /> | |||
| <TextField | |||
| name="email" | |||
| label="Email" | |||
| label={t('forms:Email')} | |||
| margin="normal" | |||
| value={formik.values.email} | |||
| onChange={formik.handleChange} | |||
| @@ -110,7 +113,7 @@ const RegisterForm = () => { | |||
| /> | |||
| <TextField | |||
| name="password" | |||
| label="Password" | |||
| label={t('forms:Password')} | |||
| margin="normal" | |||
| type={showPassword ? 'text' : 'password'} | |||
| value={formik.values.password} | |||
| @@ -131,7 +134,7 @@ const RegisterForm = () => { | |||
| /> | |||
| <TextField | |||
| name="confirmPassword" | |||
| label="Confirm password" | |||
| label={t('forms:ConfirmPassword')} | |||
| margin="normal" | |||
| type={showPassword ? 'text' : 'password'} | |||
| value={formik.values.confirmPassword} | |||
| @@ -161,7 +164,7 @@ const RegisterForm = () => { | |||
| sx={{ mt: 3, mb: 2 }} | |||
| fullWidth | |||
| > | |||
| Register | |||
| {t('register:RegisterBtn')} | |||
| </Button> | |||
| <Grid container> | |||
| <Grid | |||
| @@ -170,7 +173,9 @@ const RegisterForm = () => { | |||
| md={6} | |||
| sx={{ textAlign: { xs: 'center', md: 'left' } }} | |||
| > | |||
| <Link href={FORGOT_PASSWORD_PAGE}>Forgot your password?</Link> | |||
| <Link href={FORGOT_PASSWORD_PAGE}> | |||
| {t('register:ForgotPassword')} | |||
| </Link> | |||
| </Grid> | |||
| <Grid | |||
| item | |||
| @@ -178,7 +183,7 @@ const RegisterForm = () => { | |||
| md={6} | |||
| sx={{ textAlign: { xs: 'center', md: 'right' } }} | |||
| > | |||
| <Link href={LOGIN_PAGE}>Already have an account?</Link> | |||
| <Link href={LOGIN_PAGE}>{t('register:HaveAccount')}</Link> | |||
| </Grid> | |||
| </Grid> | |||
| </Box> | |||
| @@ -0,0 +1,30 @@ | |||
| import { useState } from 'react'; | |||
| import { usePagination } from '../../../hooks/use-pagination'; | |||
| const PaginationComponentRQ = () => { | |||
| const [pageIndex, setPageIndex] = useState(1); | |||
| const { data: paginationData } = usePagination(pageIndex); | |||
| return ( | |||
| <div> | |||
| {paginationData?.data.map((item) => ( | |||
| <div key={item._id}>{item.name}</div> | |||
| ))} | |||
| <button | |||
| disabled={pageIndex === 1} | |||
| onClick={() => setPageIndex(pageIndex - 1)} | |||
| > | |||
| Previous | |||
| </button> | |||
| <button | |||
| disabled={pageIndex * 5 > paginationData?.dataCount} | |||
| onClick={() => setPageIndex(pageIndex + 1)} | |||
| > | |||
| Next | |||
| </button> | |||
| </div> | |||
| ); | |||
| }; | |||
| export default PaginationComponentRQ; | |||
| @@ -0,0 +1,5 @@ | |||
| const base = {}; | |||
| export const mockPaginationComponentQRProps = { | |||
| base, | |||
| }; | |||
| @@ -0,0 +1,20 @@ | |||
| import PaginationComponentRQ from './PaginationComponentRQ'; | |||
| import { mockPaginationComponentQRProps } from './PaginationComponentRQ.mock'; | |||
| const obj = { | |||
| title: 'pagination/PaginationComponentRQ', | |||
| component: PaginationComponentRQ, | |||
| // More on argTypes: https://storybook.js.org/docs/react/api/argtypes | |||
| argTypes: {}, | |||
| }; //eslint-disable-line | |||
| export default obj; | |||
| // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args | |||
| const Template = (args) => <PaginationComponentRQ {...args} />; | |||
| export const Base = Template.bind({}); | |||
| // More on args: https://storybook.js.org/docs/react/writing-stories/args | |||
| Base.args = { | |||
| ...mockPaginationComponentQRProps.base, | |||
| }; | |||
| @@ -0,0 +1,34 @@ | |||
| import { useState } from 'react'; | |||
| import useSWRWithFallbackData from '../../../hooks/use-swr-with-initial-data'; | |||
| import { getData } from '../../../requests/dataRequest'; | |||
| const PaginationComponent = ({ initialData = {} }) => { | |||
| const [pageIndex, setPageIndex] = useState(1); | |||
| const fetcher = (page) => getData(page); | |||
| const { data: paginationData } = useSWRWithFallbackData(pageIndex, fetcher, { | |||
| fallbackData: initialData, | |||
| }); | |||
| return ( | |||
| <div> | |||
| {paginationData?.data?.map((item) => ( | |||
| <div key={item._id}>{item.name}</div> | |||
| ))} | |||
| <button | |||
| disabled={pageIndex === 1} | |||
| onClick={() => setPageIndex(pageIndex - 1)} | |||
| > | |||
| Previous | |||
| </button> | |||
| <button | |||
| disabled={pageIndex * 5 > paginationData?.dataCount} | |||
| onClick={() => setPageIndex(pageIndex + 1)} | |||
| > | |||
| Next | |||
| </button> | |||
| </div> | |||
| ); | |||
| }; | |||
| export default PaginationComponent; | |||
| @@ -0,0 +1,5 @@ | |||
| const base = {}; | |||
| export const mockPaginationComponentSWRProps = { | |||
| base, | |||
| }; | |||
| @@ -0,0 +1,20 @@ | |||
| import PaginationComponentSWR from './PaginationComponentSWR'; | |||
| import { mockPaginationComponentSWRProps } from './PaginationComponentSWR.mock'; | |||
| const obj = { | |||
| title: 'pagination/PaginationComponentSWR', | |||
| component: PaginationComponentSWR, | |||
| // More on argTypes: https://storybook.js.org/docs/react/api/argtypes | |||
| argTypes: {}, | |||
| }; //eslint-disable-line | |||
| export default obj; | |||
| // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args | |||
| const Template = (args) => <PaginationComponentSWR {...args} />; | |||
| export const Base = Template.bind({}); | |||
| // More on args: https://storybook.js.org/docs/react/writing-stories/args | |||
| Base.args = { | |||
| ...mockPaginationComponentSWRProps.base, | |||
| }; | |||
| @@ -0,0 +1,10 @@ | |||
| import { useQuery } from '@tanstack/react-query'; | |||
| import { getData } from '../requests/dataRequest'; | |||
| export const usePagination = (activePage) => { | |||
| return useQuery(['randomData', activePage], () => getData(activePage), { | |||
| keepPreviousData: true, | |||
| refetchOnMount: false, | |||
| refetchOnWindowFocus: false, | |||
| }); | |||
| }; | |||
| @@ -0,0 +1,15 @@ | |||
| import { useEffect, useRef } from 'react'; | |||
| import useSWR from 'swr'; | |||
| export default function useSWRWithFallbackData(key, fetcher, options = {}) { | |||
| const hasMounted = useRef(false); | |||
| useEffect(() => { | |||
| hasMounted.current = true; | |||
| }, []); | |||
| return useSWR(key, fetcher, { | |||
| ...options, | |||
| fallbackData: hasMounted.current ? undefined : options?.fallbackData, | |||
| }); | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| module.exports = { | |||
| i18n: { | |||
| defaultLocale: 'en', | |||
| locales: ['en'], | |||
| }, | |||
| }; | |||
| @@ -1,7 +1,10 @@ | |||
| /** @type {import('next').NextConfig} */ | |||
| const { i18n } = require('./next-i18next.config'); | |||
| const nextConfig = { | |||
| reactStrictMode: true, | |||
| swcMinify: true, | |||
| } | |||
| i18n, | |||
| }; | |||
| module.exports = nextConfig | |||
| module.exports = nextConfig; | |||
| @@ -18,16 +18,19 @@ | |||
| "@mui/codemod": "^5.8.7", | |||
| "@mui/icons-material": "^5.8.4", | |||
| "@mui/material": "^5.9.2", | |||
| "@tanstack/react-query": "^4.0.10", | |||
| "bcryptjs": "^2.4.3", | |||
| "date-fns": "^2.29.1", | |||
| "formik": "^2.2.9", | |||
| "mongodb": "^4.8.1", | |||
| "next": "12.2.3", | |||
| "next-auth": "^4.10.2", | |||
| "next-i18next": "^11.3.0", | |||
| "prop-types": "^15.8.1", | |||
| "react": "18.2.0", | |||
| "react-dom": "18.2.0", | |||
| "sass": "^1.54.0", | |||
| "swr": "^1.3.0", | |||
| "yup": "^0.32.11" | |||
| }, | |||
| "devDependencies": { | |||
| @@ -44,6 +47,7 @@ | |||
| "@storybook/manager-webpack5": "^6.5.9", | |||
| "@storybook/react": "^6.5.9", | |||
| "@storybook/testing-library": "^0.0.13", | |||
| "@tanstack/react-query-devtools": "^4.0.10", | |||
| "babel-loader": "^8.2.5", | |||
| "babel-plugin-import": "^1.13.5", | |||
| "cross-env": "^7.0.3", | |||
| @@ -1,7 +1,39 @@ | |||
| import '../styles/globals.css' | |||
| import { | |||
| Hydrate, | |||
| QueryClient, | |||
| QueryClientProvider, | |||
| } from '@tanstack/react-query'; | |||
| import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; | |||
| import { SessionProvider } from 'next-auth/react'; | |||
| import { appWithTranslation } from 'next-i18next'; | |||
| import { useState } from 'react'; | |||
| import '../styles/globals.css'; | |||
| function MyApp({ Component, pageProps }) { | |||
| return <Component {...pageProps} /> | |||
| function MyApp({ Component, pageProps: { session, ...pageProps } }) { | |||
| const [queryClient] = useState(() => new QueryClient()); | |||
| return ( | |||
| <QueryClientProvider client={queryClient}> | |||
| <Hydrate state={pageProps.dehydratedState}> | |||
| <SessionProvider session={session}> | |||
| <Component {...pageProps} /> | |||
| </SessionProvider> | |||
| <ReactQueryDevtools initialIsOpen={false} /> | |||
| </Hydrate> | |||
| </QueryClientProvider> | |||
| ); | |||
| } | |||
| export default MyApp | |||
| MyApp.getInitialProps = async ({ Component, ctx }) => { | |||
| let pageProps = {}; | |||
| if (Component.getInitialProps) { | |||
| pageProps = await Component.getInitialProps(ctx); | |||
| } | |||
| return { | |||
| pageProps, | |||
| }; | |||
| }; | |||
| export default appWithTranslation(MyApp); | |||
| @@ -0,0 +1,54 @@ | |||
| import { connectToDatabase } from '../../utils/helpers/dbHelpers'; | |||
| async function handler(req, res) { | |||
| if (req.method !== 'GET') { | |||
| return; | |||
| } | |||
| const pageIndex = req.query.page; | |||
| if (pageIndex < 1) { | |||
| res.status(422).json({ | |||
| message: 'Page does not exist ', | |||
| }); | |||
| return; | |||
| } | |||
| const client = await connectToDatabase(); | |||
| const db = client.db(); | |||
| const dataCount = await db.collection('randomData').countDocuments(); | |||
| if ((pageIndex - 1) * 5 >= dataCount) { | |||
| res.status(422).json({ | |||
| message: 'Page does not exist ', | |||
| }); | |||
| client.close(); | |||
| return; | |||
| } | |||
| const dataFromDB = await db | |||
| .collection('randomData') | |||
| .find() | |||
| .skip((pageIndex - 1) * 5) | |||
| .limit(5) | |||
| .toArray(); | |||
| if (!dataFromDB) { | |||
| res.status(422).json({ message: 'No data!' }); | |||
| client.close(); | |||
| return; | |||
| } | |||
| res.status(201).json({ | |||
| message: 'Created user!', | |||
| data: dataFromDB, | |||
| dataCount: dataCount, | |||
| }); | |||
| setTimeout(() => { | |||
| client.close(); | |||
| }, 1500); | |||
| } | |||
| export default handler; | |||
| @@ -1,4 +1,5 @@ | |||
| import { getSession } from 'next-auth/react'; | |||
| import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; | |||
| import { useRouter } from 'next/router'; | |||
| import { useEffect } from 'react'; | |||
| import ForgotPasswordForm from '../../../components/forms/forgot-password/ForgotPasswordForm'; | |||
| @@ -18,4 +19,16 @@ const ForgotPasswordPage = () => { | |||
| return <ForgotPasswordForm />; | |||
| }; | |||
| export async function getStaticProps({ locale }) { | |||
| return { | |||
| props: { | |||
| ...(await serverSideTranslations(locale, [ | |||
| 'forms', | |||
| 'forgotPass', | |||
| 'common', | |||
| ])), | |||
| }, | |||
| }; | |||
| } | |||
| export default ForgotPasswordPage; | |||
| @@ -1,4 +1,5 @@ | |||
| import { getSession } from 'next-auth/react'; | |||
| import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; | |||
| import { useRouter } from 'next/router'; | |||
| import { useEffect } from 'react'; | |||
| import LoginForm from '../../components/forms/login/LoginForm'; | |||
| @@ -18,4 +19,12 @@ const AuthPage = () => { | |||
| return <LoginForm />; | |||
| }; | |||
| export async function getStaticProps({ locale }) { | |||
| return { | |||
| props: { | |||
| ...(await serverSideTranslations(locale, ['forms', 'login'])), | |||
| }, | |||
| }; | |||
| } | |||
| export default AuthPage; | |||
| @@ -1,4 +1,5 @@ | |||
| import { getSession } from 'next-auth/react'; | |||
| import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; | |||
| import { useRouter } from 'next/router'; | |||
| import { useEffect } from 'react'; | |||
| import RegisterForm from '../../../components/forms/register/RegisterForm'; | |||
| @@ -18,4 +19,12 @@ const RegisterPage = () => { | |||
| return <RegisterForm />; | |||
| }; | |||
| export async function getStaticProps({ locale }) { | |||
| return { | |||
| props: { | |||
| ...(await serverSideTranslations(locale, ['forms', 'register'])), | |||
| }, | |||
| }; | |||
| } | |||
| export default RegisterPage; | |||
| @@ -1,4 +1,7 @@ | |||
| import { dehydrate, QueryClient } from '@tanstack/react-query'; | |||
| import { signOut } from 'next-auth/react'; | |||
| import PaginationComponentRQ from '../components/pagination/react-query/PaginationComponentRQ'; | |||
| import { getData } from '../requests/dataRequest'; | |||
| const Home = () => { | |||
| function logoutHandler() { | |||
| @@ -8,8 +11,21 @@ const Home = () => { | |||
| <> | |||
| <h1>Home</h1> | |||
| <button onClick={logoutHandler}>Logout</button> | |||
| <PaginationComponentRQ></PaginationComponentRQ> | |||
| </> | |||
| ); | |||
| }; | |||
| export async function getServerSideProps() { | |||
| const queryClient = new QueryClient(); | |||
| await queryClient.prefetchQuery(['randomData', 1], () => getData(1)); | |||
| return { | |||
| props: { | |||
| dehydratedState: dehydrate(queryClient), | |||
| }, | |||
| }; | |||
| } | |||
| export default Home; | |||
| @@ -0,0 +1,28 @@ | |||
| import { getSession, useSession } from 'next-auth/react'; | |||
| import ProfileCard from '../../components/cards/profile-card/ProfileCard'; | |||
| import { LOGIN_PAGE } from '../../constants/pages'; | |||
| const ProfilePage = () => { | |||
| const { data: session } = useSession(); | |||
| return <ProfileCard profileData={{ name: session.user.name }} />; | |||
| }; | |||
| export async function getServerSideProps(context) { | |||
| const session = await getSession({ req: context.req }); | |||
| if (!session) { | |||
| return { | |||
| redirect: { | |||
| destination: LOGIN_PAGE, | |||
| permanent: false, | |||
| }, | |||
| }; | |||
| } | |||
| return { | |||
| props: { session }, | |||
| }; | |||
| } | |||
| export default ProfilePage; | |||
| @@ -0,0 +1,3 @@ | |||
| { | |||
| "Back": "Back" | |||
| } | |||
| @@ -0,0 +1,4 @@ | |||
| { | |||
| "Title": "Forgot password", | |||
| "SendBtn": "Send email" | |||
| } | |||
| @@ -0,0 +1,7 @@ | |||
| { | |||
| "FullName": "Full name", | |||
| "Username": "Username", | |||
| "Email": "Email", | |||
| "Password": "Password", | |||
| "ConfirmPassword": "Confirm password" | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| { | |||
| "Title": "Login", | |||
| "ForgotPassword": "Forgot your password?", | |||
| "NoAccount": "Dont have an account?", | |||
| "LoginBtn": "Login" | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| { | |||
| "Title": "Register", | |||
| "ForgotPassword": "Forgot your password?", | |||
| "HaveAccount": "Already have an account?", | |||
| "RegisterBtn": "Register" | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| export default { | |||
| account: { | |||
| createUser: "/api/auth/signup", | |||
| createUser: '/api/auth/signup', | |||
| }, | |||
| data: '/api/data', | |||
| }; | |||
| @@ -0,0 +1,15 @@ | |||
| import apiEndpoints from './apiEndpoints'; | |||
| export const getData = async (pageIndex) => { | |||
| const response = await fetch( | |||
| `http://localhost:3000/${apiEndpoints.data}?page=${pageIndex}` | |||
| ); | |||
| const data = await response.json(); | |||
| if (!response.ok) { | |||
| throw new Error(data.message || 'Something went wrong!'); | |||
| } | |||
| return data; | |||
| }; | |||
| @@ -1073,7 +1073,7 @@ | |||
| dependencies: | |||
| regenerator-runtime "^0.13.2" | |||
| "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": | |||
| "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.18.9", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": | |||
| version "7.18.9" | |||
| resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" | |||
| integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== | |||
| @@ -2854,6 +2854,36 @@ | |||
| dependencies: | |||
| tslib "^2.4.0" | |||
| "@tanstack/match-sorter-utils@^8.0.0-alpha.82": | |||
| version "8.1.1" | |||
| resolved "https://registry.yarnpkg.com/@tanstack/match-sorter-utils/-/match-sorter-utils-8.1.1.tgz#895f407813254a46082a6bbafad9b39b943dc834" | |||
| integrity sha512-IdmEekEYxQsoLOR0XQyw3jD1GujBpRRYaGJYQUw1eOT1eUugWxdc7jomh1VQ1EKHcdwDLpLaCz/8y4KraU4T9A== | |||
| dependencies: | |||
| remove-accents "0.4.2" | |||
| "@tanstack/query-core@^4.0.0-beta.1": | |||
| version "4.0.10" | |||
| resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.0.10.tgz#cae6f818006616dc72c95c863592f5f68b47548a" | |||
| integrity sha512-9LsABpZXkWZHi4P1ozRETEDXQocLAxVzQaIhganxbNuz/uA3PsCAJxJTiQrknG5htLMzOF5MqM9G10e6DCxV1A== | |||
| "@tanstack/react-query-devtools@^4.0.10": | |||
| version "4.0.10" | |||
| resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-4.0.10.tgz#d1b3e5b1917f1c22bcee5830ef7af1ccfc4879f4" | |||
| integrity sha512-3J7LLYQjfjTI0DbPo0bA+M3l4kdvYSWAqihpeG1u93WVyZj0OEFviUv+4cK7+k2AVgQJAPMZ5xvtewKxOOFVrw== | |||
| dependencies: | |||
| "@tanstack/match-sorter-utils" "^8.0.0-alpha.82" | |||
| "@types/use-sync-external-store" "^0.0.3" | |||
| use-sync-external-store "^1.2.0" | |||
| "@tanstack/react-query@^4.0.10": | |||
| version "4.0.10" | |||
| resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.0.10.tgz#92c71a2632c06450d848d4964959bd216cde03c0" | |||
| integrity sha512-Wn5QhZUE5wvr6rGClV7KeQIUsdTmYR9mgmMZen7DSRWauHW2UTynFg3Kkf6pw+XlxxOLsyLWwz/Q6q1lSpM3TQ== | |||
| dependencies: | |||
| "@tanstack/query-core" "^4.0.0-beta.1" | |||
| "@types/use-sync-external-store" "^0.0.3" | |||
| use-sync-external-store "^1.2.0" | |||
| "@testing-library/dom@^8.3.0": | |||
| version "8.16.0" | |||
| resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.16.0.tgz#d6fc50250aed17b1035ca1bd64655e342db3936a" | |||
| @@ -2948,6 +2978,14 @@ | |||
| dependencies: | |||
| "@types/unist" "*" | |||
| "@types/hoist-non-react-statics@^3.3.1": | |||
| version "3.3.1" | |||
| resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" | |||
| integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== | |||
| dependencies: | |||
| "@types/react" "*" | |||
| hoist-non-react-statics "^3.3.0" | |||
| "@types/html-minifier-terser@^5.0.0": | |||
| version "5.1.2" | |||
| resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" | |||
| @@ -3124,6 +3162,11 @@ | |||
| resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" | |||
| integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== | |||
| "@types/use-sync-external-store@^0.0.3": | |||
| version "0.0.3" | |||
| resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" | |||
| integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== | |||
| "@types/webidl-conversions@*": | |||
| version "6.1.1" | |||
| resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e" | |||
| @@ -4555,7 +4598,7 @@ core-js-pure@^3.20.2, core-js-pure@^3.8.1: | |||
| resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.24.1.tgz#8839dde5da545521bf282feb7dc6d0b425f39fd3" | |||
| integrity sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg== | |||
| core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.2: | |||
| core-js@^3, core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.2: | |||
| version "3.24.1" | |||
| resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f" | |||
| integrity sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg== | |||
| @@ -6320,7 +6363,7 @@ highlight.js@^10.4.1, highlight.js@~10.7.0: | |||
| resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" | |||
| integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== | |||
| hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1: | |||
| hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: | |||
| version "3.3.2" | |||
| resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" | |||
| integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== | |||
| @@ -6375,6 +6418,13 @@ html-minifier-terser@^6.0.2: | |||
| relateurl "^0.2.7" | |||
| terser "^5.10.0" | |||
| html-parse-stringify@^3.0.1: | |||
| version "3.0.1" | |||
| resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" | |||
| integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== | |||
| dependencies: | |||
| void-elements "3.1.0" | |||
| html-tags@^3.1.0: | |||
| version "3.2.0" | |||
| resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961" | |||
| @@ -6442,6 +6492,18 @@ husky@^8.0.1: | |||
| resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9" | |||
| integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw== | |||
| i18next-fs-backend@^1.1.4: | |||
| version "1.1.4" | |||
| resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-1.1.4.tgz#d0e9b9ed2fa7a0f11002d82b9fa69c3c3d6482da" | |||
| integrity sha512-/MfAGMP0jHonV966uFf9PkWWuDjPYLIcsipnSO3NxpNtAgRUKLTwvm85fEmsF6hGeu0zbZiCQ3W74jwO6K9uXA== | |||
| i18next@^21.8.13: | |||
| version "21.8.16" | |||
| resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.8.16.tgz#31fe4682e4e2077dbf229a88e5a58b7020e4ddc8" | |||
| integrity sha512-acJLCk38YMfEPjBR/1vS13SFY7rBQLs9E5m1tSRnWc9UW3f+SZszgH+NP1fZRA1+O+CdG2eLGGmuUMJW52EwzQ== | |||
| dependencies: | |||
| "@babel/runtime" "^7.17.2" | |||
| [email protected]: | |||
| version "0.4.24" | |||
| resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" | |||
| @@ -7874,6 +7936,19 @@ next-auth@^4.10.2: | |||
| preact-render-to-string "^5.1.19" | |||
| uuid "^8.3.2" | |||
| next-i18next@^11.3.0: | |||
| version "11.3.0" | |||
| resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-11.3.0.tgz#bfce51d8df07fb5cd61097423eeb7d744e09ae25" | |||
| integrity sha512-xl0oIRtiVrk9ZaWBRUbNk/prva4Htdu59o9rFWzd9ax/KemaDVuTTuBZTQMkmXohUQk/MJ7w1rV/mICL6TzyGw== | |||
| dependencies: | |||
| "@babel/runtime" "^7.18.6" | |||
| "@types/hoist-non-react-statics" "^3.3.1" | |||
| core-js "^3" | |||
| hoist-non-react-statics "^3.3.2" | |||
| i18next "^21.8.13" | |||
| i18next-fs-backend "^1.1.4" | |||
| react-i18next "^11.18.0" | |||
| [email protected]: | |||
| version "12.2.3" | |||
| resolved "https://registry.yarnpkg.com/next/-/next-12.2.3.tgz#c29d235ce480e589894dfab3120dade25d015a22" | |||
| @@ -8937,6 +9012,14 @@ react-fast-compare@^2.0.1: | |||
| resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" | |||
| integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== | |||
| react-i18next@^11.18.0: | |||
| version "11.18.3" | |||
| resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.18.3.tgz#50211810bcc9fdea2d70c8aefdfff5f1eb39a923" | |||
| integrity sha512-EttTX31HbqzZymUM3SIrMPuvamfSXFZVsDHm/ZAqoDfTLjhzlwyxqfbDNxcKNAGOi2mjZaXfR7hSNMlvLNpB/g== | |||
| dependencies: | |||
| "@babel/runtime" "^7.14.5" | |||
| html-parse-stringify "^3.0.1" | |||
| react-inspector@^5.1.0: | |||
| version "5.1.1" | |||
| resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-5.1.1.tgz#58476c78fde05d5055646ed8ec02030af42953c8" | |||
| @@ -9242,6 +9325,11 @@ [email protected]: | |||
| dependencies: | |||
| mdast-squeeze-paragraphs "^4.0.0" | |||
| [email protected]: | |||
| version "0.4.2" | |||
| resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" | |||
| integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== | |||
| remove-trailing-separator@^1.0.1: | |||
| version "1.1.0" | |||
| resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" | |||
| @@ -10001,6 +10089,11 @@ supports-preserve-symlinks-flag@^1.0.0: | |||
| resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" | |||
| integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== | |||
| swr@^1.3.0: | |||
| version "1.3.0" | |||
| resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8" | |||
| integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw== | |||
| symbol.prototype.description@^1.0.0: | |||
| version "1.0.5" | |||
| resolved "https://registry.yarnpkg.com/symbol.prototype.description/-/symbol.prototype.description-1.0.5.tgz#d30e01263b6020fbbd2d2884a6276ce4d49ab568" | |||
| @@ -10538,7 +10631,7 @@ url-loader@^4.1.1: | |||
| mime-types "^2.1.27" | |||
| schema-utils "^3.0.0" | |||
| [email protected]: | |||
| [email protected], use-sync-external-store@^1.2.0: | |||
| version "1.2.0" | |||
| resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" | |||
| integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== | |||
| @@ -10641,6 +10734,11 @@ vfile@^4.0.0: | |||
| unist-util-stringify-position "^2.0.0" | |||
| vfile-message "^2.0.0" | |||
| [email protected]: | |||
| version "3.1.0" | |||
| resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" | |||
| integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== | |||
| walker@^1.0.7, walker@~1.0.5: | |||
| version "1.0.8" | |||
| resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" | |||