Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OV-4: Sign Up flow #20

Merged
merged 24 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5fe0d63
OV-4: + name and repeatPassword properties for sign-up form
lfelix3011 Aug 18, 2024
aadec52
OV-4: + link to sign-in from sign-up
lfelix3011 Aug 18, 2024
9ebace7
OV-4: * change property name from repeatPass... to confirmPass...
lfelix3011 Aug 18, 2024
6fbcf26
OV-4: + validation between passowrd and it confirms
lfelix3011 Aug 19, 2024
98d6dfe
OV-4: + special input for password
lfelix3011 Aug 19, 2024
e94407c
OV-4: + redirect to root after sign-up submit
lfelix3011 Aug 19, 2024
547891c
OV-4: + save authenticated user after sign-up
lfelix3011 Aug 19, 2024
60dec10
OV-4: * Improvement in sign-up form validations
lfelix3011 Aug 19, 2024
1fdbd56
OV-4: + script to use lint fix and icons form chakra
lfelix3011 Aug 19, 2024
efa87dd
OV-4: * change structure to match, the one already made
lfelix3011 Aug 19, 2024
95c3a32
OV-4: * change names to match, the one already made
lfelix3011 Aug 19, 2024
253804a
OV-4: * change to match layout already made
lfelix3011 Aug 19, 2024
dcff059
OV-4: * improvement styles in sign-up form
lfelix3011 Aug 20, 2024
5295a8d
OV-4: * change of pixel to make horizontally center the icon when error
lfelix3011 Aug 20, 2024
71abbc5
OV-4: * use of prettier for code styles
lfelix3011 Aug 20, 2024
fb00d6f
Merge branch 'next' into task/OV-4-add-sign-up-flow
lfelix3011 Aug 20, 2024
c871b36
OV-4: * Using 25px to match what is already done
lfelix3011 Aug 20, 2024
d2b03a9
OV-4: * adjust in script to use lint fix
lfelix3011 Aug 21, 2024
939115e
OV-4: * adjust in script to use lint fix
lfelix3011 Aug 21, 2024
fc1d021
Merge branch 'next' of https://github.com/BinaryStudioAcademy/bsa-202…
lfelix3011 Aug 21, 2024
e106f81
OV-4: * required message for fields
lfelix3011 Aug 21, 2024
bcad14b
OV-4: + script to use lint fix in backend folder
lfelix3011 Aug 21, 2024
c95f612
OV-4: * adjust in script to use lint fix with workspace
lfelix3011 Aug 21, 2024
fd90ba7
Merge branch 'next' of https://github.com/BinaryStudioAcademy/bsa-202…
lfelix3011 Aug 21, 2024
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
2 changes: 2 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"scripts": {
"lint:type": "npx tsc --noEmit",
"lint:js": "npx eslint \"src/**/*.ts\"",
"lint:js:fix": "npx eslint --fix \"src/**/*.ts\"",
"lint": "npm run lint:type && npm run lint:js",
"lint:fix": "npm run lint:type && npm run lint:js:fix",
"start:dev": "nodemon --exec tsx src/index.ts",
"migrate:dev": "node --loader ts-paths-esm-loader ../node_modules/knex/bin/cli.js migrate:latest",
"migrate:dev:make": "node --loader ts-paths-esm-loader ../node_modules/knex/bin/cli.js migrate:make -x ts",
Expand Down
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
"scripts": {
"lint:css": "npx stylelint \"src/**/*.scss\" --aei",
"lint:js": "npx eslint \"src/**/*.{ts,tsx}\"",
"lint:js:fix": "npx eslint --fix \"src/**/*.{ts,tsx}\"",
"lint:type": "npx tsc --noEmit",
"lint": "npm run lint:type && npm run lint:js",
"lint:fix": "npm run lint:type && npm run lint:js:fix",
"start:dev": "vite",
"build": "tsc -p tsconfig.build.json && vite build",
"preview": "vite preview"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { type UserSignUpRequestDto } from '~/bundles/users/users.js';

const DEFAULT_SIGN_UP_PAYLOAD: UserSignUpRequestDto = {
name: '',
email: '',
password: '',
confirmPassword: '',
};

export { DEFAULT_SIGN_UP_PAYLOAD };
Original file line number Diff line number Diff line change
@@ -1,52 +1,99 @@
import { UserValidationMessage } from 'shared/src/bundles/users/users.js';

import {
Box,
Button,
FormProvider,
Heading,
Input,
Link,
VStack,
} from '~/bundles/common/components/components.js';
import { useAppForm } from '~/bundles/common/hooks/hooks.js';
import { AppRoute, DataStatus } from '~/bundles/common/enums/enums.js';
import {
useAppForm,
useAppSelector,
useMemo,
} from '~/bundles/common/hooks/hooks.js';
import {
type UserSignUpRequestDto,
userSignUpValidationSchema,
} from '~/bundles/users/users.js';

import { FormError, FormHeader, PasswordInput } from '../common/components.js';
import { DEFAULT_SIGN_UP_PAYLOAD } from './constants/constants.js';

type Properties = {
onSubmit: (payload: UserSignUpRequestDto) => void;
};

const SignUpForm: React.FC<Properties> = ({ onSubmit }) => {
const { dataStatus } = useAppSelector(({ auth }) => ({
dataStatus: auth.dataStatus,
}));
const form = useAppForm<UserSignUpRequestDto>({
initialValues: DEFAULT_SIGN_UP_PAYLOAD,
validationSchema: userSignUpValidationSchema,
onSubmit,
});

const { handleSubmit } = form;
const { handleSubmit, errors, values } = form;

const isEmpty = useMemo(
() => Object.values(values).some((value) => value.trim().length === 0),
[values],
);

return (
<FormProvider value={form}>
<Box bg="brand.200" w={64} p={6} rounded="md">
<Heading as="h1">Sign Up</Heading>

<Box w="55%" color="white">
<FormHeader
headerText="Create an account"
subheader={
<>
Already registerd?{' '}
<Link to={AppRoute.SIGN_IN} variant="secondary">
Log In
</Link>
</>
}
/>
<form onSubmit={handleSubmit}>
<VStack spacing={4} align="flex-start">
<Input
type="text"
label="Full Name"
placeholder="Name"
name="name"
/>
<Input
type="email"
label="Email"
placeholder="Enter your email"
placeholder="[email protected]"
name="email"
/>
<Input
type="password"
<PasswordInput
label="Password"
placeholder="Enter your password"
name="password"
hasError={Boolean(errors.password)}
/>
<PasswordInput
label="Repeat password"
name="confirmPassword"
hasError={Boolean(errors.confirmPassword)}
/>
<FormError
isVisible={dataStatus === DataStatus.REJECTED}
message={
UserValidationMessage.USER_IS_NOT_AVAILABLE
}
/>
<Button
type="submit"
label="Sign up"
size="lg"
sx={{ mt: '16px' }}
isDisabled={isEmpty}
/>
<Button type="submit" label="Sign up" />
</VStack>
</form>
</Box>
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/bundles/auth/store/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ const { reducer, actions, name } = createSlice({
builder.addCase(signUp.pending, (state) => {
state.dataStatus = DataStatus.PENDING;
});
builder.addCase(signUp.fulfilled, (state) => {
builder.addCase(signUp.fulfilled, (state, action) => {
const payload = action.payload;

state.dataStatus = DataStatus.FULFILLED;
state.user = payload;
});
builder.addCase(signUp.rejected, (state) => {
state.dataStatus = DataStatus.REJECTED;
state.user = null;
});
},
});
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
"lint:fs": "ls-lint",
"lint:type": "npm run lint:type --workspaces --if-present",
"lint:js": "npm run lint:js --workspaces --if-present -- --max-warnings=0",
"lint:js:fix": "eslint --fix \"**/*.{ts,tsx}\" --max-warnings=0",
"lint:css": "npm run lint:css --workspaces --if-present",
"lint:css:fix": "stylelint --fix \"**/*.{scss,css}\"",
"lint:format": "prettier --check \"**/*.{ts,tsx,json,md,scss,html,yml}\"",
"lint": "npm run lint:editor && npm run lint:fs && npm run lint:format && npm run lint:type && npm run lint:js && npm run lint:css",
"lint:fix": "npm run lint:fix -w frontend && npm run lint:fix -w backend",
"format": "prettier --write \"**/*.{ts,tsx,json,md,css,html,yml}\""
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ const UserValidationMessage = {
FIELD_REQUIRE: 'Please fill out this field',
EMAIL_INVALID: 'Please enter a valid email',
PASSWORD_LENGTH: 'Password must have from 6 to 12 characters',
PASS_DONT_MATCH: 'Passwords must be identical',
INVALID_DATA: 'Incorrect email or password. Please try again.',
WRONG_CREDENTIALS: 'Email or password are incorrect',
USER_IS_NOT_AVAILABLE:
'User with this email already exists. Log in if it is you',
} as const;

export { UserValidationMessage };
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
type UserSignUpRequestDto = {
name: string;
email: string;
password: string;
confirmPassword: string;
};

export { type UserSignUpRequestDto };
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,52 @@ import { z } from 'zod';
import { UserValidationMessage, UserValidationRule } from '../enums/enums.js';

type UserSignUpRequestValidationDto = {
name: z.ZodString;
email: z.ZodString;
password: z.ZodString;
confirmPassword: z.ZodString;
};

const userSignUp = z
.object<UserSignUpRequestValidationDto>({
name: z
.string({ required_error: UserValidationMessage.FIELD_REQUIRE })
.trim(),
email: z
.string()
.string({ required_error: UserValidationMessage.FIELD_REQUIRE })
.trim()
.min(UserValidationRule.EMAIL_MINIMUM_LENGTH, {
message: UserValidationMessage.EMAIL_REQUIRE,
message: UserValidationMessage.EMAIL_INVALID,
})
.max(UserValidationRule.EMAIL_MAXIMUM_LENGTH, {
message: UserValidationMessage.EMAIL_INVALID,
})
.email({
message: UserValidationMessage.EMAIL_WRONG,
message: UserValidationMessage.EMAIL_INVALID,
}),
password: z
.string({ required_error: UserValidationMessage.FIELD_REQUIRE })
.trim()
.min(UserValidationRule.PASSWORD_MINIMUM_LENGTH, {
message: UserValidationMessage.PASSWORD_LENGTH,
})
.max(UserValidationRule.PASSWORD_MAXIMUM_LENGTH, {
message: UserValidationMessage.PASSWORD_LENGTH,
}),
confirmPassword: z
.string({ required_error: UserValidationMessage.FIELD_REQUIRE })
.trim()
.min(UserValidationRule.PASSWORD_MINIMUM_LENGTH, {
message: UserValidationMessage.PASSWORD_LENGTH,
})
.max(UserValidationRule.PASSWORD_MAXIMUM_LENGTH, {
message: UserValidationMessage.PASSWORD_LENGTH,
}),
password: z.string().trim(),
})
.required();
.required()
.refine((data) => data.password === data.confirmPassword, {
message: UserValidationMessage.PASS_DONT_MATCH,
path: ['confirmPassword'],
});

export { userSignUp };
Loading