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
2 changes: 2 additions & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ node_modules/
dist/
.jest/
.DS_Store

*storybook.log
18 changes: 18 additions & 0 deletions client/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { StorybookConfig } from '@storybook/react-webpack5';

const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-webpack5-compiler-swc',
'@storybook/addon-onboarding',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
};
export default config;
14 changes: 14 additions & 0 deletions client/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Preview } from '@storybook/react';

const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};

export default preview;
10,065 changes: 6,784 additions & 3,281 deletions client/package-lock.json

Large diffs are not rendered by default.

26 changes: 24 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
"build": "webpack --mode production",
"test": "jest src",
"lint": "eslint src --fix",
"schemagen": "graphql-codegen && ts-node enhance.server.types.ts && node src/app/client/possibleTypesGen.js"
"schemagen": "graphql-codegen && ts-node enhance.server.types.ts && node src/app/client/possibleTypesGen.js",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"dependencies": {
"@ant-design/icons": "^5.0.1",
"@apollo/client": "^3.7.14",
"@corex/hook-form-yup-resolver": "^3.0.611",
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@mui/icons-material": "^5.11.16",
Expand All @@ -34,25 +37,37 @@
"react-addons-shallow-compare": "^15.6.3",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.53.0",
"react-i18next": "^12.2.0",
"react-markdown": "^8.0.7",
"react-redux": "^8.0.5",
"react-router-dom": "^6.10.0",
"redux-saga": "^1.2.3",
"socket.io-client": "^4.7.2",
"symbol-observable": "^4.0.0",
"unchanged": "^2.2.1"
"unchanged": "^2.2.1",
"yup": "^1.4.0"
},
"devDependencies": {
"@babel/core": "^7.21.4",
"@babel/preset-env": "^7.21.4",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.4",
"@chromatic-com/storybook": "^1.8.0",
"@graphql-codegen/cli": "^4.0.0",
"@graphql-codegen/introspection": "^4.0.0",
"@graphql-codegen/typescript": "^4.0.0",
"@graphql-codegen/typescript-operations": "^4.0.0",
"@graphql-codegen/typescript-react-apollo": "^3.3.7",
"@storybook/addon-essentials": "^8.2.9",
"@storybook/addon-interactions": "^8.2.9",
"@storybook/addon-links": "^8.2.9",
"@storybook/addon-onboarding": "^8.2.9",
"@storybook/addon-webpack5-compiler-swc": "^1.0.5",
"@storybook/blocks": "^8.2.9",
"@storybook/react": "^8.2.9",
"@storybook/react-webpack5": "^8.2.9",
"@storybook/test": "^8.2.9",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.5.2",
Expand All @@ -78,6 +93,7 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-storybook": "^0.8.0",
"fork-ts-checker-webpack-plugin": "^8.0.0",
"html-webpack-plugin": "^5.5.0",
"identity-obj-proxy": "^3.0.0",
Expand All @@ -89,6 +105,7 @@
"prettier": "^2.8.7",
"sass": "^1.61.0",
"sass-loader": "^13.2.2",
"storybook": "^8.2.9",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.2",
"ts-jest": "^29.1.0",
Expand All @@ -97,5 +114,10 @@
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"eslintConfig": {
"extends": [
"plugin:storybook/recommended"
]
}
}
5 changes: 5 additions & 0 deletions client/src/features/forms/GoodsForm/goodsForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.goods-form-container {
display: flex;
flex-direction: column;
gap: 12px;
}
12 changes: 12 additions & 0 deletions client/src/features/forms/GoodsForm/goodsForm.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { GoodsForm } from "./goodsForm"

export default {
title: "UI/Form/GoodsForm",
component: GoodsForm,
tags: ['autodocs']
}


export const Default = {
args: {}
}
41 changes: 41 additions & 0 deletions client/src/features/forms/GoodsForm/goodsForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// import { yupResolver } from "@corex/hook-form-yup-resolver";
import React from "react";
import { useForm } from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import './goodsForm.css';

// типизация полей
type Inputs = {
goodsName: string;
};

// Схема валидации
const schema = yup.object({
goodsName: yup.string().max(12).required(),
});

export const GoodsForm = () => {

const { handleSubmit, reset, register, formState: { errors } } = useForm<Inputs>({
resolver: yupResolver(schema),
});
const onSubmit = (data: Inputs) => {
console.log('Sended to server: ' + JSON.stringify(data));
reset();
}

return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="goods-form-container">
<label>Наименование товара</label>
<input id="goodsName" {...register("goodsName")} />
{errors.goodsName &&
<p style={{ color: "red" }}> {errors.goodsName.message}</p>
}

<input type="submit" />
</div>
</form>
);
}
1 change: 1 addition & 0 deletions client/src/features/forms/GoodsForm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './goodsForm';
11 changes: 11 additions & 0 deletions client/src/features/forms/LoginForm/LoginForm.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { LoginForm } from "./LoginForm";

export default {
title: "UI/Form/LoginForm",
component: LoginForm,
tags: ['autodocs'],
}

export const Default = {
args: {}
}
51 changes: 51 additions & 0 deletions client/src/features/forms/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react";
import { useForm } from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";

// типизация полей
type LoginFormFields = {
login: string;
password: string;
}

// Валидация
const validationSchem = yup
.object()
.shape({
login: yup.string().required(),
password: yup.string().max(12).required(),
})

export const LoginForm = () => {

const { reset, handleSubmit, register, formState: { errors } } = useForm<LoginFormFields>(
{ resolver: yupResolver(validationSchem) }
);

const handleOnSubmit = (data: LoginFormFields) => {
console.log('Data sended to server' + JSON.stringify(data));
reset();
}

return (
<form onSubmit={handleSubmit(handleOnSubmit)}>
<div>
<label>Логин</label>
<input id="login" {...register("login")} />
{errors.login &&
<p style={{ color: "red" }}> {errors.login.message}</p>
}

<label>Пароль</label>
<input id="password" {...register("password")} />
{errors.password &&
<p style={{ color: "red" }}> {errors.password.message}</p>
}

<input type="submit" />
</div>
</form>
);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { UserProfileForm } from "./userProfileForm";

export default {
title: "UI/Form/UserProfileForm",
component: UserProfileForm,
tags: ['autodocs'],
}

export const Default = {
args:{}
}
110 changes: 110 additions & 0 deletions client/src/features/forms/UserProfileForm/userProfileForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from "react";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";

// типизация полей
type Inputs = {
name: string;
age: string;
document: string;
infoMethod: string;
};

// валидация полей
const schema = yup
.object()
.shape({
name: yup.string().required(),
age: yup.number().required(),
document: yup.string().required(),
infoMethod: yup.string().required(),
})
.required();

export const UserProfileForm = () => {
const {
register,
handleSubmit,
reset,
watch,
formState: { errors },
} = useForm<Inputs>({
mode: "onSubmit",
defaultValues: {
name: "",
age: "",
document: "Паспорт",
infoMethod: "",
},
resolver: yupResolver(schema),
});

const customHandleSubmit = (values: Inputs) => {
console.log(`Values sended to server: ${JSON.stringify(values)}`);
reset();
};

// Отслеживаем значение поля с именем
const nameField = watch("name");

useEffect(() => {
console.log("nameField: ", nameField);
}, [nameField]);
// =================================

return (
<form onSubmit={handleSubmit(customHandleSubmit)}>
<label htmlFor="name">Имя</label>
<input
id="name"
type="text"
{...register("name", {
min: {
value: 3,
message: "error message",
},
})}
/>
{errors.name && <p style={{ color: "red" }}>{errors.name.message}</p>}

<label htmlFor="age">Возраст</label>
<input id="age" type="number" {...register("age")} />
{errors.age && <p style={{ color: "red" }}>{errors.age.message}</p>}

<hr />
<select {...register("document")}>
<option>Паспорт</option>
<option>Удостоверение</option>
</select>

<hr />
<input
type="radio"
id="infoMethodPhone"
// почему важно указывать value?
value="phone"
{...register("infoMethod")}
/>
<label htmlFor="infoMethodPhone">Phone</label>

<input
type="radio"
id="infoMethodPhoneMail"
// почему важно указывать value?
value="mail"
{...register("infoMethod")}
/>
<label htmlFor="infoMethodPhoneMail">Mail</label>

<hr />
<button type="button" onClick={() => reset()}>
Сбросить
</button>

<button type="submit">Отправить</button>

</form>
);
};