Skip to content

Commit

Permalink
Refactor/Features and create page
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryczko committed Jan 16, 2024
1 parent 3f364db commit c6ceca9
Show file tree
Hide file tree
Showing 64 changed files with 1,199 additions and 1,017 deletions.
213 changes: 166 additions & 47 deletions package-lock.json

Large diffs are not rendered by default.

13 changes: 5 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@
"@heroicons/react": "^1.0.6",
"@next-auth/prisma-adapter": "^1.0.6",
"@prisma/client": "^4.14.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/emoji-mart": "^3.0.9",
"@types/jest": "^29.5.0",
"@types/node": "^18.15.3",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"axios": "^1.6.0",
"bcrypt": "^5.1.0",
"clsx": "^1.1.1",
Expand Down Expand Up @@ -60,8 +52,13 @@
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/bcrypt": "^5.0.0",
"@types/emoji-mart": "^3.0.9",
"@types/jest": "^29.5.0",
"@types/node": "^18.15.3",
"@types/nprogress": "^0.2.0",
"@types/react": "^18.0.28",
"@types/react-beautiful-dnd": "^13.1.4",
"@types/react-dom": "^18.0.11",
"@types/uuid": "^9.0.1",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
Expand Down
97 changes: 97 additions & 0 deletions src/features/account/Account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { TrashIcon } from '@heroicons/react/outline';

import useTranslation from 'next-translate/useTranslation';
import { useAccountManager } from 'features/account/accountManager';
import Button, { ButtonVariant } from 'shared/components/Button/Button';
import StyledDialog from 'shared/components/StyledDialog/StyledDialog';
import Avatar from 'shared/components/Avatar/Avatar';
import { formatDateDistance } from 'shared/utilities/convertTime';
import Header from 'shared/components/Header/Header';

export default function Account() {
const { t } = useTranslation('account');

const {
user,
isOpen,
openDeleteModal,
closeDeleteModal,
handleOnAccountDelete,
isRemoving,
} = useAccountManager();

return (
<>
<Header>Your account</Header>

{user ? (
<div className="mt-4 flex w-full items-center justify-center gap-12 text-left">
<Avatar size={160} src={user.image} classNames="border" />

<div className="mb-4">
<h2 className="mb-2 text-2xl">{user?.name}</h2>
<p>{user?.email}</p>
<p>Account created: {formatDateDistance(user.createdAt)}</p>
</div>
</div>
) : (
<></>
)}

{process.env.NEXT_PUBLIC_REMOVE_ACCOUNT && (
<>
<div className="flex flex-col items-center justify-center space-y-2">
<div className="flex w-full md:ml-2 md:w-auto">
<Button
variant={ButtonVariant.DANGER}
title={t('deleteAccountButtonTitle')}
className="ml-2 mt-2 w-full justify-center px-3 sm:mt-0 md:w-auto"
onClick={openDeleteModal}
icon={<TrashIcon className="h-5 w-5" />}
>
{t('deleteAccountButton')}
</Button>
</div>
</div>
<StyledDialog
isOpen={isOpen}
onClose={closeDeleteModal}
title={t('dialogTitle')}
content={
<>
<div className="mt-2">
<p className="text-sm text-red-500">
{t('dialogContentFirst')}&nbsp;
<span className="font-bold">
{t('dialogContentSecond')}
</span>{' '}
{t('dialogContentThird')}
</p>
</div>
<div className="mt-6 flex justify-between space-x-3">
<Button
variant={ButtonVariant.SECONDARY}
onClick={closeDeleteModal}
className="uppercase"
disabled={isRemoving}
>
{t('buttonCancle')}
</Button>
<Button
variant={ButtonVariant.DANGER}
onClick={handleOnAccountDelete}
icon={<TrashIcon className="h-5 w-5" />}
className="uppercase"
isLoading={isRemoving}
>
{t('buttonConfirm')}
</Button>
</div>
</>
}
/>
</>
)}
</>
);
}
16 changes: 9 additions & 7 deletions src/features/application/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ import data from '@emoji-mart/data/sets/14/apple.json';
import { init as emojisInit } from 'emoji-mart';
import { EMOJI_STYLE, customEmojisData } from 'shared/constants/emojisConfig';

export interface ApplicationManager {
user: User | undefined;
loading: boolean;
error: boolean;
}

export const useApplicationManager = (): ApplicationManager => {
export const useApplicationManager = () => {
const [loading, setIsLoading] = useState(true);
const [error, setError] = useState(false);
const [user, setUser] = useState<User>();
const [isBrowser, setIsBrowser] = useState(false);

useEffect(() => {
if (typeof window !== 'undefined') {
setIsBrowser(true);
}

init();
}, []);

Expand All @@ -37,5 +36,8 @@ export const useApplicationManager = (): ApplicationManager => {
user,
loading,
error,
isBrowser,
};
};

export type ApplicationManager = ReturnType<typeof useApplicationManager>;
100 changes: 100 additions & 0 deletions src/features/authorization/LoginCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Form, Formik } from 'formik';
import Link from 'next/link';
import Header from 'shared/components/Header/Header';
import LoginButton from 'shared/components/LoginButton/LoginButton';
import Input from 'shared/components/Input/Input';
import { useLoginManager } from 'features/authorization/managers/loginManager';
import Github from '../../../public/images/github.svg';
import Google from '../../../public/images/google.svg';
import useTranslation from 'next-translate/useTranslation';
import AuthFormWrapper from 'features/authorization/components/AuthFormWrapper';

export default function LoginCard() {
const { t } = useTranslation('login');

const {
initialValues,
LoginSchema,
onSubmit,
onGoogleLogin,
onGithubLogin,
isSubmitting,
isGoogleLoading,
isGithubLoading,
} = useLoginManager();

return (
<AuthFormWrapper>
<Header>{t('login:heading')}</Header>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={LoginSchema}
>
{({ values, errors, handleChange, handleSubmit, touched }) => (
<Form className="flex w-full flex-col">
<LoginButton
isLoading={isGoogleLoading}
image={Google}
onClick={onGoogleLogin}
>
{t('login:googleButton')}
</LoginButton>
<LoginButton
image={Github}
isLoading={isGithubLoading}
onClick={onGithubLogin}
className="mb-3"
>
{t('login:githubButton')}
</LoginButton>
<p>{t('login:or')}</p>

<Input
type="email"
value={values.email}
required
error={touched.email ? errors.email : undefined}
placeholder={t('login:email')}
className="!mb-1 mt-3"
onChange={handleChange('email')}
/>
<Input
type="password"
value={values.password}
error={touched.password ? errors.password : undefined}
required
placeholder={t('login:password')}
className="!my-1"
onChange={handleChange('password')}
/>

{!!errors.message && (
<p className="mb-4 max-w-sm self-center text-center text-sm text-red-300">
{errors.message}
</p>
)}
<div className="flex flex-col items-center justify-center">
<LoginButton
className="mb-2 mt-1 border-indigo-200 !bg-indigo-200 !text-indigo-900 hover:!bg-indigo-300"
type="submit"
onClick={handleSubmit}
isLoading={isSubmitting}
>
{t('login:signInButton')}
</LoginButton>
</div>
<Link scroll={false} href={'/signup'} passHref>
<p
data-test-id="signup-link"
className="mt-2 text-center text-sm text-zinc-600 underline hover:cursor-pointer"
>
{t('login:dontHaveAccount')}
</p>
</Link>
</Form>
)}
</Formik>
</AuthFormWrapper>
);
}
80 changes: 80 additions & 0 deletions src/features/authorization/SignUpCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Form, Formik } from 'formik';
import Link from 'next/link';
import Header from 'shared/components/Header/Header';
import LoginButton from 'shared/components/LoginButton/LoginButton';
import Input from 'shared/components/Input/Input';
import { useRegisterManager } from 'features/authorization/managers/registerManager';
import useTranslation from 'next-translate/useTranslation';
import AuthFormWrapper from 'features/authorization/components/AuthFormWrapper';

export default function SignUpCard() {
const { t } = useTranslation('signup');

const { initialValues, onSubmit, SignupSchema, isRegistering } =
useRegisterManager();

return (
<AuthFormWrapper>
<Header>{t('heading')}</Header>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={SignupSchema}
>
{({ values, errors, handleChange, handleSubmit, touched }) => (
<Form className="flex w-full flex-col">
<Input
type="text"
name="name"
value={values.name}
required
error={touched.name ? errors.name : undefined}
placeholder={t('name')}
onChange={handleChange('name')}
className="!my-1"
/>
<Input
type="email"
className="!my-1"
value={values.email}
required
error={touched.email ? errors.email : undefined}
placeholder={t('email')}
onChange={handleChange('email')}
/>
<Input
type="password"
className="!my-1"
value={values.password}
error={touched.password ? errors.password : undefined}
required
placeholder={t('password')}
onChange={handleChange('password')}
/>
{!!errors.message && (
<p className="mb-4 max-w-sm self-center text-center text-sm text-red-300">
{errors.message}
</p>
)}

<div className="flex flex-col items-center justify-center">
<LoginButton
className="mb-2 mt-1 border-indigo-200 !bg-indigo-200 !text-indigo-900 hover:!bg-indigo-300"
type="submit"
onClick={handleSubmit}
isLoading={isRegistering}
>
{t('signUpButton')}
</LoginButton>
</div>
<Link scroll={false} href={'/login'} passHref>
<p className="mt-2 text-center text-sm text-zinc-600 underline hover:cursor-pointer">
{t('alreadyHaveAccount')}
</p>
</Link>
</Form>
)}
</Formik>
</AuthFormWrapper>
);
}
Loading

0 comments on commit c6ceca9

Please sign in to comment.