Skip to content

Commit d7f1162

Browse files
committed
feat: homework routing
1 parent 5f5dd7f commit d7f1162

File tree

13 files changed

+148
-74
lines changed

13 files changed

+148
-74
lines changed

src/app/App.tsx

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React from 'react';
22
import { nanoid } from 'nanoid';
3-
import { BrowserRouter, Route, RouteProps, Routes } from 'react-router';
3+
import { BrowserRouter, NavLink, Route, RouteProps, Router, Routes, useLocation } from 'react-router';
44
import { useTranslation } from 'react-i18next';
55
import './tailwind.css';
66
import { Layout } from '../entities';
7-
import { AccountServicePage, Store, StoreBasket, StoreCard, StoreList } from '../pages';
7+
import { AccountServicePage, ProfilePage, Store, StoreBasket, StoreCard, StoreList } from '../pages';
88
import { defaultContext, ELangVariables, EThemeVariables, IStoreContext, StoreContext } from './StoreContext';
99

1010
function App() {
@@ -30,6 +30,10 @@ function App() {
3030
path: '/account-service',
3131
element: <AccountServicePage />,
3232
},
33+
{
34+
path: '/profile',
35+
element: <ProfilePage />,
36+
},
3337
];
3438
const { theme, lang } = contextValue;
3539
const { i18n, t } = useTranslation();
@@ -74,36 +78,46 @@ function App() {
7478
path: '/account-service',
7579
text: t('tempLinks.toAccountService'),
7680
},
81+
{
82+
path: '/profile',
83+
text: t('tempLinks.toProfilePage'),
84+
},
7785
];
78-
const currentUrl = window.location.pathname;
86+
// const currentUrl = window.location.pathname;
7987
// END TODO
8088

8189
return (
8290
<StoreContext.Provider value={{ theme, lang, themeSwitchHandler, langSwitchHandler }}>
83-
<Layout>
84-
{/* TODO: Delete this Links and translation in future */}
85-
<nav className="container mx-auto my-4 px-3">
86-
<ol className="flex gap-2">
87-
{tempLinks.map((item) =>
88-
item.path !== currentUrl ? (
91+
<BrowserRouter>
92+
<Layout>
93+
{/* TODO: Delete this Links and translation in future */}
94+
<nav className="container mx-auto my-4 px-3">
95+
<ol className="flex flex-wrap gap-2">
96+
{tempLinks.map((item) => (
8997
<li key={nanoid()}>
90-
<a href={item.path}>{item.text}</a>
98+
<NavLink
99+
className={({ isActive }) =>
100+
[isActive ? 'bg-black text-white' : '', 'p-1 hover:text-white hover:bg-slate-400 rounded'].join(
101+
' '
102+
)
103+
}
104+
to={item.path}
105+
>
106+
{item.text}
107+
</NavLink>
91108
</li>
92-
) : (
93-
<React.Fragment key={nanoid()}></React.Fragment>
94-
)
95-
)}
96-
</ol>
97-
</nav>
98-
{/* END TODO */}
99-
<BrowserRouter>
109+
))}
110+
</ol>
111+
</nav>
112+
{/* END TODO */}
113+
100114
<Routes>
101115
{pages.map((item) => (
102116
<Route key={nanoid()} path={item.path} element={item.element} />
103117
))}
104118
</Routes>
105-
</BrowserRouter>
106-
</Layout>
119+
</Layout>
120+
</BrowserRouter>
107121
</StoreContext.Provider>
108122
);
109123
}

src/app/i18n/translation.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const resources = {
88
toBasket: 'to Basket',
99
toList: 'to Goods List',
1010
toAccountService: 'to Account Service',
11+
toProfilePage: 'to Profile',
1112
},
1213
card: {
1314
stockStatus: {
@@ -43,6 +44,7 @@ export const resources = {
4344
},
4445
listPage: {
4546
addMore: 'Add more',
47+
addGoodToStore: 'Add good to store',
4648
},
4749
modal: {
4850
close: 'Close modal window',
@@ -65,8 +67,11 @@ export const resources = {
6567
submit: 'Submit',
6668
goods: {
6769
title: 'Title',
70+
titlePlaceholder: 'Enter goods title',
6871
details: 'Details',
72+
detailsPlaceholder: 'Tell more about goods',
6973
price: 'Price',
74+
pricePlaceholder: 'Enter price',
7075
},
7176
authReg: {
7277
login: {
@@ -103,6 +108,7 @@ export const resources = {
103108
toBasket: 'В корзину',
104109
toList: 'К списку товаров',
105110
toAccountService: 'К сервису для Аккаунта',
111+
toProfilePage: 'К профилю',
106112
},
107113
card: {
108114
stockStatus: {
@@ -138,6 +144,7 @@ export const resources = {
138144
},
139145
listPage: {
140146
addMore: 'Добавить ещё',
147+
addGoodToStore: 'Добавить новый товар',
141148
},
142149
modal: {
143150
close: 'Закрыть модальное окно',
@@ -160,8 +167,11 @@ export const resources = {
160167
submit: 'Отправить',
161168
goods: {
162169
title: 'Название',
170+
titlePlaceholder: 'Введите название товара',
163171
details: 'Описание',
172+
detailsPlaceholder: 'Введите описание товара',
164173
price: 'Цена',
174+
pricePlaceholder: 'Введите цену товара',
165175
},
166176
authReg: {
167177
login: {

src/entities/Aside/AsideLayout/AsideLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ import React from 'react';
22
import { ILayout } from '../../interfaces';
33

44
export const AsideLayout: React.FC<ILayout> = ({ children }) => (
5-
<aside className="pt-6 pl-[18px] pr-[14px] pb-8 border-solid border-[1px] border-b-100 rounded-md ">{children}</aside>
5+
<aside className="pt-6 pl-[18px] pr-[14px] pb-8 border-solid border-[1px] border-b-100 rounded-md">{children}</aside>
66
);

src/entities/Header/Header.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import clsx from 'clsx';
33
import { useTranslation } from 'react-i18next';
4+
import { NavLink } from 'react-router';
45
import { LangSwitcherBtn, Logo, ThemeSwitcherBtn } from '../../shared';
56
import { ELogoType } from '../../shared/interfaces';
67
import { EThemeVariables, StoreContext } from '../../app/StoreContext';
@@ -17,9 +18,9 @@ export const Header: React.FC = () => {
1718
return (
1819
<header className={className}>
1920
<div className="flex flex-row justify-between items-center container mx-auto px-3">
20-
<a href="/">
21+
<NavLink to="/">
2122
<Logo type={ELogoType.DARK} text={t('storeName')} />
22-
</a>
23+
</NavLink>
2324
<div className="flex flex-row justify-between items-center gap-4">
2425
<ThemeSwitcherBtn />
2526
<LangSwitcherBtn />

src/entities/Modal/ModalBackgorund/ModalBackgorund.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const ModalBackgorund: React.FC<IModal> = ({ children, changeVisibility }
66
const { t } = useTranslation();
77

88
return (
9-
<div className="w-full absolute top-0 left-0">
9+
<div className="w-full absolute top-0 left-0 z-90">
1010
<div className="flex justify-center items-center min-h-dvh relative">
1111
<div className="w-full h-full bg-b-500 opacity-40 absolute top-0 left-0"></div>
1212
<div className="w-fit opacity-1 relative">

src/features/forms/AddGoodForm.tsx

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,20 @@ import React from 'react';
22
import { useForm } from 'react-hook-form';
33
import { useTranslation } from 'react-i18next';
44
import clsx from 'clsx';
5-
import { goods } from '../../assets/goods';
65
import { EThemeVariables, StoreContext } from '../../app/StoreContext';
76
import { Btn } from '../../shared';
8-
import { IGoodsItem } from 'src/entities/interfaces';
9-
import { generateRandomNumber } from '../generators';
7+
import { IGoodsItem } from '../../entities/interfaces';
108

11-
export const AddGoodForm: React.FC = () => {
12-
const {
13-
handleSubmit,
14-
register,
15-
reset,
16-
formState: { errors },
17-
} = useForm<IGoodsItem>();
18-
const [lastId, setLastId] = React.useState<number>(goods[goods.length - 1].id);
19-
const { t } = useTranslation();
9+
interface IAddGoodForm {
10+
/** Новый id */
11+
newId: number;
12+
/** функция сабмита формы */
13+
onSubmit: (data: Partial<IGoodsItem>) => void;
14+
}
2015

21-
const onSubmit = (data: Partial<IGoodsItem>): void => {
22-
setLastId(lastId + 1);
23-
console.log('Form :', data);
24-
reset();
25-
};
16+
export const AddGoodForm: React.FC<IAddGoodForm> = ({ newId, onSubmit }) => {
17+
const { handleSubmit, register } = useForm<IGoodsItem>();
18+
const { t } = useTranslation();
2619

2720
const { theme } = React.useContext(StoreContext);
2821
const isDarkTheme = theme === EThemeVariables.DARK;
@@ -40,40 +33,42 @@ export const AddGoodForm: React.FC = () => {
4033
<label htmlFor="id" className="pt-2">
4134
ID:
4235
</label>
43-
<input id="id" value={lastId} className={className} disabled />
36+
<input id="id" value={newId} className={className} disabled />
4437
<label htmlFor="title" className="pt-2">
4538
{t('forms.goods.title')}
4639
</label>
4740
<input
4841
{...register('title', {
49-
value: `Some cool goods ${lastId}`,
42+
value: '',
5043
required: true,
5144
})}
5245
id="title"
5346
className={className}
47+
placeholder={t('forms.goods.titlePlaceholder')}
5448
/>
5549
<label htmlFor="details" className="pt-2">
5650
{t('forms.goods.details')}
5751
</label>
5852
<textarea
5953
{...register('details', {
60-
value:
61-
'Curabitur tincidunt ex vel magna iaculis varius. Duis eleifend ligula vitae lectus cursus, eu luctus leo rutrum. ',
54+
value: '',
6255
required: true,
6356
})}
6457
className={className}
6558
name="details"
59+
placeholder={t('forms.goods.detailsPlaceholder')}
6660
required
6761
/>
6862
<label htmlFor="price" className="pt-2">
6963
{t('forms.goods.price')}
7064
</label>
7165
<input
7266
{...register('price', {
73-
value: generateRandomNumber(50, 250),
67+
value: Number(''),
7468
required: true,
7569
})}
7670
id="price"
71+
placeholder={t('forms.goods.pricePlaceholder')}
7772
className={className}
7873
/>
7974
<Btn type="submit">{t('forms.submit')}</Btn>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
import { Container } from '../../entities';
3+
import { ProfileForm } from '../../features/forms';
4+
5+
export const ProfilePage: React.FC = () => {
6+
return (
7+
<Container>
8+
<div className="max-w-xs">
9+
<ProfileForm />
10+
</div>
11+
</Container>
12+
);
13+
};

src/pages/Store/Store.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { createPortal } from 'react-dom';
33
import { useTranslation } from 'react-i18next';
44
import { Container, Modal } from '../../entities';
5-
import { Btn, Input } from 'src/shared';
5+
import { Btn, Input } from '../../shared';
66

77
export const Store: React.FC = () => {
88
const [inputValue, setInputValue] = React.useState<string>('');

src/pages/StoreList/StoreList.tsx

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import React from 'react';
22
import { nanoid } from 'nanoid';
33
import { useTranslation } from 'react-i18next';
4+
import { useForm } from 'react-hook-form';
5+
import { createPortal } from 'react-dom';
46
import { goods } from '../../assets/goods';
5-
import { AsideFlter, AsideLayout, Container, ShortCard } from '../../entities';
7+
import { AsideFlter, AsideLayout, Container, Modal, ShortCard } from '../../entities';
68
import { IGoodsItem } from '../../entities/interfaces';
79
import { Btn, RangeSlider } from '../../shared';
810
import { generateRandomCardList } from '../../features/generators';
9-
import { IRangeSliderChange } from 'src/shared/interfaces';
11+
import { AddGoodForm } from '../../features/forms';
12+
import { IRangeSliderChange } from '../../shared/interfaces';
1013

1114
export const StoreList: React.FC = () => {
1215
const [myGoods, setMyGoods] = React.useState<IGoodsItem[]>([]);
1316
const [lastId, setLastId] = React.useState<number>(goods[goods.length - 1].id);
17+
const [isModalVisible, setIsModalVisible] = React.useState<boolean>(false);
1418

1519
React.useLayoutEffect(() => {
1620
const onlyAwailible: IGoodsItem[] = goods.filter((el) => el.isInStock);
@@ -28,32 +32,56 @@ export const StoreList: React.FC = () => {
2832
};
2933

3034
const { t } = useTranslation();
35+
const { reset } = useForm<IGoodsItem>();
3136

3237
const changePriceFilter = ({ min, max }: IRangeSliderChange) => {
3338
console.log(`min = ${min}, max = ${max}`);
3439
};
3540

41+
const changeModalVisibility = (): void => {
42+
setIsModalVisible(!isModalVisible);
43+
};
44+
45+
const onSubmit = (data: Partial<IGoodsItem>): void => {
46+
setLastId(lastId + 1);
47+
console.log('Form :', data);
48+
reset();
49+
setIsModalVisible(!isModalVisible);
50+
};
51+
3652
return (
37-
<Container>
38-
<div className="flex items-start gap-[21px]">
39-
<AsideLayout>
40-
<AsideFlter title="Price">
41-
<RangeSlider min={0} max={100} onChange={changePriceFilter} />
42-
</AsideFlter>
43-
</AsideLayout>
44-
<section>
45-
<ul className="grid grid-cols-3 mb-4">
46-
{myGoods.map((item) => (
47-
<li key={nanoid()}>
48-
<ShortCard {...item} />
49-
</li>
50-
))}
51-
</ul>
52-
<div className="flex gap-3">
53-
<Btn onClick={cardGenerator}>{t('listPage.addMore')}</Btn>
54-
</div>
55-
</section>
56-
</div>
57-
</Container>
53+
<>
54+
<Container>
55+
<div className="flex items-start gap-[21px]">
56+
<AsideLayout>
57+
<AsideFlter title="Price">
58+
<div className="mb-2">
59+
<RangeSlider min={0} max={100} onChange={changePriceFilter} />
60+
</div>
61+
<Btn onClick={changeModalVisibility}>{t('listPage.addGoodToStore')}</Btn>
62+
</AsideFlter>
63+
</AsideLayout>
64+
<section>
65+
<ul className="grid grid-cols-3 mb-4">
66+
{myGoods.map((item) => (
67+
<li key={nanoid()}>
68+
<ShortCard {...item} />
69+
</li>
70+
))}
71+
</ul>
72+
<div className="flex gap-3">
73+
<Btn onClick={cardGenerator}>{t('listPage.addMore')}</Btn>
74+
</div>
75+
</section>
76+
</div>
77+
</Container>
78+
{isModalVisible &&
79+
createPortal(
80+
<Modal changeVisibility={changeModalVisibility}>
81+
<AddGoodForm newId={lastId} onSubmit={onSubmit} />
82+
</Modal>,
83+
document.body
84+
)}
85+
</>
5886
);
5987
};

src/pages/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { AccountServicePage } from './AccountServicePage/AccountServicePage';
2+
export { ProfilePage } from './ProfilePage/ProfilePage';
23
export { Store } from './Store/Store';
34
export { StoreBasket } from './StoreBasket/StoreBasket';
45
export { StoreCard } from './StoreCard/StoreCard';

0 commit comments

Comments
 (0)