diff --git a/package-lock.json b/package-lock.json
index bba5b5d..48e3528 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@ant-design/icons": "^5.2.6",
"antd": "^5.12.1",
"axios": "^1.6.5",
+ "lodash": "^4.17.21",
"next": "14.0.3",
"next-intl": "^3.3.1",
"react": "^18",
@@ -22,9 +23,11 @@
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.0.4",
+ "@types/lodash": "^4.14.202",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
+ "@types/react-slick": "^0.23.13",
"autoprefixer": "^10.0.1",
"eslint": "^8.55.0",
"eslint-config-next": "^14.0.3",
@@ -640,6 +643,12 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
+ "node_modules/@types/lodash": {
+ "version": "4.14.202",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
+ "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
+ "dev": true
+ },
"node_modules/@types/node": {
"version": "20.9.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
@@ -675,6 +684,15 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-slick": {
+ "version": "0.23.13",
+ "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.13.tgz",
+ "integrity": "sha512-bNZfDhe/L8t5OQzIyhrRhBr/61pfBcWaYJoq6UDqFtv5LMwfg4NsVDD2J8N01JqdAdxLjOt66OZEp6PX+dGs/A==",
+ "dev": true,
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/scheduler": {
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
@@ -3209,6 +3227,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -5705,6 +5728,12 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
+ "@types/lodash": {
+ "version": "4.14.202",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
+ "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
+ "dev": true
+ },
"@types/node": {
"version": "20.9.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
@@ -5740,6 +5769,15 @@
"@types/react": "*"
}
},
+ "@types/react-slick": {
+ "version": "0.23.13",
+ "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.13.tgz",
+ "integrity": "sha512-bNZfDhe/L8t5OQzIyhrRhBr/61pfBcWaYJoq6UDqFtv5LMwfg4NsVDD2J8N01JqdAdxLjOt66OZEp6PX+dGs/A==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/scheduler": {
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
@@ -7606,6 +7644,11 @@
"p-locate": "^5.0.0"
}
},
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
diff --git a/package.json b/package.json
index ac8b2e7..f34c878 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@ant-design/icons": "^5.2.6",
"antd": "^5.12.1",
"axios": "^1.6.5",
+ "lodash": "^4.17.21",
"next": "14.0.3",
"next-intl": "^3.3.1",
"react": "^18",
@@ -23,9 +24,11 @@
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.0.4",
+ "@types/lodash": "^4.14.202",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
+ "@types/react-slick": "^0.23.13",
"autoprefixer": "^10.0.1",
"eslint": "^8.55.0",
"eslint-config-next": "^14.0.3",
diff --git a/src/app/[locale]/(main)/@experts/page.tsx b/src/app/[locale]/(main)/@experts/page.tsx
index 8f6fd3c..44eee4d 100644
--- a/src/app/[locale]/(main)/@experts/page.tsx
+++ b/src/app/[locale]/(main)/@experts/page.tsx
@@ -1,16 +1,9 @@
import React from 'react';
-import { getTranslations } from 'next-intl/server';
-import { getFilter } from '../../../../utils/filter';
-import { getExpertsList } from '../../../../actions/experts';
-import { getTagList } from '../../../../actions/tags';
+import { useTranslations } from 'next-intl';
import { Experts } from '../../../../components/Experts/Experts';
-export default async function ExpertsPage({ params, searchParams }: { params: { locale: string }, searchParams: { [key: string]: string | string[] | undefined } }) {
- const searchData = await getTagList(params.locale);
- const filter = getFilter(searchData, searchParams);
- console.log('filter main page', filter);
- const experts = await getExpertsList(filter, params.locale);
- const t = await getTranslations('Experts');
+export default function ExpertsPage({ params }: { params: { locale: string } }) {
+ const t = useTranslations('Experts');
return (
@@ -21,10 +14,7 @@ export default async function ExpertsPage({ params, searchParams }: { params: {
-
+
);
diff --git a/src/app/[locale]/blog/[newsId]/page.tsx b/src/app/[locale]/blog/[blogId]/page.tsx
similarity index 97%
rename from src/app/[locale]/blog/[newsId]/page.tsx
rename to src/app/[locale]/blog/[blogId]/page.tsx
index f09beb4..131333a 100644
--- a/src/app/[locale]/blog/[newsId]/page.tsx
+++ b/src/app/[locale]/blog/[blogId]/page.tsx
@@ -3,16 +3,16 @@ import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
export const metadata: Metadata = {
- title: 'Bbuddy - News item',
- description: 'Bbuddy desc news item'
+ title: 'Bbuddy - Blog item',
+ description: 'Bbuddy desc blog item'
};
export function generateStaticParams() {
- return [{ newsId: 'news-1' }, { newsId: 'news-2' }];
+ return [{ blogId: 'news-1' }, { blogId: 'news-2' }];
}
-export default function NewsItem({ params }: { params: { newsId: string } }) {
- if (!params?.newsId) notFound();
+export default function BlogItem({ params }: { params: { blogId: string } }) {
+ if (!params?.blogId) notFound();
return (
@@ -20,7 +20,7 @@ export default function NewsItem({ params }: { params: { newsId: string } }) {
6 learnings from Shivpuri to Silicon Valley
Leadership & Management
- {`news id ${params.newsId}`}
+ {`news id ${params.blogId}`}
I’m excited to kick off this series of newsletters where I’ll be sharing my experiences, learnings,
and best practices which helped me to grow both in my personal and professional life. My hope is to
give back to the community and help anyone connect directly with me who may have got impacted with
diff --git a/src/app/[locale]/blog/page.tsx b/src/app/[locale]/blog/page.tsx
index 235089f..20f2989 100644
--- a/src/app/[locale]/blog/page.tsx
+++ b/src/app/[locale]/blog/page.tsx
@@ -2,11 +2,11 @@ import React from 'react';
import type { Metadata } from 'next';
export const metadata: Metadata = {
- title: 'Bbuddy - News',
- description: 'Bbuddy desc news'
+ title: 'Bbuddy - Blog',
+ description: 'Bbuddy desc blog'
};
-export default function News() {
+export default function Blog() {
return (
diff --git a/src/app/[locale]/experts/page.tsx b/src/app/[locale]/experts/page.tsx
index 33fa566..eafd99a 100644
--- a/src/app/[locale]/experts/page.tsx
+++ b/src/app/[locale]/experts/page.tsx
@@ -1,9 +1,6 @@
import React from 'react';
import type { Metadata } from 'next';
-import { getTranslations } from 'next-intl/server';
-import { getFilter } from '../../../utils/filter';
-import { getExpertsList } from '../../../actions/experts';
-import { getTagList } from '../../../actions/tags';
+import { useTranslations } from 'next-intl';
import { Experts } from '../../../components/Experts/Experts';
export const metadata: Metadata = {
@@ -11,12 +8,8 @@ export const metadata: Metadata = {
description: 'Bbuddy desc experts'
};
-export default async function ExpertsPage({ params, searchParams }: { params: { locale: string }, searchParams: { [key: string]: string | string[] | undefined } }) {
- const searchData = await getTagList(params.locale);
- const filter = getFilter(searchData, searchParams);
- console.log('filter experts page', filter);
- const experts = await getExpertsList(filter, params.locale);
- const t = await getTranslations('Experts');
+export default function ExpertsPage({ params }: { params: { locale: string } }) {
+ const t = useTranslations('Experts');
return (
@@ -29,8 +22,8 @@ export default async function ExpertsPage({ params, searchParams }: { params: {
diff --git a/src/components/Experts/AdditionalFilter.tsx b/src/components/Experts/AdditionalFilter.tsx
index b039f69..ed3f0db 100644
--- a/src/components/Experts/AdditionalFilter.tsx
+++ b/src/components/Experts/AdditionalFilter.tsx
@@ -1,20 +1,20 @@
'use client';
import React, { useCallback, useState } from 'react';
-import {Button, Select} from 'antd';
+import { Button } from 'antd';
import { useSearchParams } from 'next/navigation';
import { useRouter } from '../../navigation';
import { AdditionalFilter } from '../../types/experts';
import { LOCALES } from '../../constants/locale';
import { getObjectByFilter, getObjectByAdditionalFilter } from '../../utils/filter';
-import { CustomInput } from '../view';
+import { CustomInput, CustomSelect, CustomMultiSelect } from '../view';
type ExpertAdditionalFilterProps = {
searchPlaceholder: string;
sortLabel: string;
langLabel: string;
buttonFind: string;
- basePath?: string;
+ basePath: string;
};
export const ExpertsAdditionalFilter = ({
@@ -22,28 +22,61 @@ export const ExpertsAdditionalFilter = ({
sortLabel,
langLabel,
buttonFind,
- basePath = '/',
-}): ExpertAdditionalFilterProps => {
+ basePath,
+}: ExpertAdditionalFilterProps) => {
const searchParams = useSearchParams();
const router = useRouter();
const [filter, setFilter] = useState
(getObjectByAdditionalFilter(searchParams));
- const onChangeFilter = useCallback((key: string, value: any) => {
- // setFilter({
- // ...filter,
- // [key]: value
- // })
+ const onChangeInput = useCallback((e: any) => {
+ if (e?.target?.value) {
+ setFilter({
+ ...filter,
+ text: e.target.value
+ });
+ } else {
+ if (filter?.text) {
+ const newFilter = { ...filter };
+ delete newFilter.text;
+
+ setFilter(newFilter);
+ }
+ }
+ }, [filter]);
+
+ const onChangeSort = useCallback((value: string) => {
+ const newFilter: AdditionalFilter = { ...filter };
+
+ if (value) {
+ newFilter.sort = value;
+ } else {
+ delete newFilter?.sort;
+ }
+
+ setFilter(newFilter);
+ }, [filter]);
+
+ const onChangeLang = useCallback((value: string[]) => {
+ const newFilter: AdditionalFilter = { ...filter };
+
+ if (value.length > 0) {
+ newFilter.language = value;
+ } else {
+ delete newFilter?.language;
+ }
+
+ setFilter(newFilter);
}, [filter]);
const goToFilterPage = useCallback(() => {
router.push({
- pathname: basePath,
+ pathname: basePath as any,
query: {
...getObjectByFilter(searchParams),
...filter
}
})
- }, [filter, searchParams]);
+ }, [filter, searchParams, router]);
return (
@@ -51,13 +84,14 @@ export const ExpertsAdditionalFilter = ({
onChangeFilter('text', e?.target?.value)}
+ onChange={onChangeInput}
/>
- onChangeFilter('sort', val)}
+
- onChangeFilter('language', val)}
+ ({ value, label }))}
/>
diff --git a/src/components/Experts/Experts.tsx b/src/components/Experts/Experts.tsx
index 904058f..3ca44a9 100644
--- a/src/components/Experts/Experts.tsx
+++ b/src/components/Experts/Experts.tsx
@@ -1,28 +1,31 @@
import React from 'react';
-import { useTranslations } from 'next-intl';
-import { SearchData } from '../../types/tags';
-import { ExpertsData } from '../../types/experts';
+import { getTranslations } from 'next-intl/server';
+import { getTagList } from '../../actions/tags';
+import { getFilter } from '../../utils/filter';
+import { getExpertsList } from '../../actions/experts';
import { ExpertsFilter } from './Filter';
import { ExpertsAdditionalFilter } from './AdditionalFilter';
import { ExpertsList } from './ExpertsList';
-import { CustomPagination } from '../view/CustomPagination';
type ExpertsProps = {
- searchData?: SearchData;
- experts?: ExpertsData;
+ basePath?: string;
+ locale: string;
};
-export const Experts = ({ searchData, experts }: ExpertsProps) => {
- const t = useTranslations('Experts');
+export const Experts = async ({ basePath = '/', locale }: ExpertsProps) => {
+ const t = await getTranslations('Experts');
+ const searchData = await getTagList(locale);
+ const filter = getFilter(searchData);
+ const experts = await getExpertsList(filter, locale);
return (
@@ -32,15 +35,16 @@ export const Experts = ({ searchData, experts }: ExpertsProps) => {
sortLabel={t('filter.sort')}
langLabel={t('filter.language')}
buttonFind={t('filter.find')}
- basePath="/experts"
+ basePath={basePath}
/>
-
)
diff --git a/src/components/Experts/ExpertsList.tsx b/src/components/Experts/ExpertsList.tsx
index eef04e8..0a16204 100644
--- a/src/components/Experts/ExpertsList.tsx
+++ b/src/components/Experts/ExpertsList.tsx
@@ -1,77 +1,107 @@
'use client';
-import React from 'react';
+import React, { useEffect, useState } from 'react';
+import { useSearchParams } from 'next/navigation';
import { List, Tag } from 'antd';
import { RightOutlined } from '@ant-design/icons';
+import isEqual from 'lodash/isEqual';
import Image from 'next/image';
import { Link } from '../../navigation';
-import { ExpertsData } from '../../types/experts';
+import { ExpertsData, Filter } from '../../types/experts';
+import { getObjectByFilter } from '../../utils/filter';
+import { getExpertsList } from '../../actions/experts';
+import { CustomPagination, CustomSpin } from '../view';
type ExpertListProps = {
- data: ExpertsData;
+ data?: ExpertsData;
priceTitle: string;
durationTitle: string;
detailButton: string;
+ locale: string;
+ baseFilter: Filter;
};
export const ExpertsList = ({
data,
priceTitle,
durationTitle,
- detailButton
+ detailButton,
+ locale,
+ baseFilter
}: ExpertListProps) => {
+ const searchParams = useSearchParams();
const getTitle = (str: string, value?: any): string => (value ? str.replace('0', value) : str);
+ const [experts, setExperts] = useState();
- return (
- (
-
-
-
-
- )}
- description={(
-
-
-
{`${item.name} ${item?.surname || ''}`}
-
-
- {getTitle(priceTitle, item?.sessionCost)} / {getTitle(durationTitle, item?.sessionDuration)}
+ useEffect(() => {
+ const filter = {
+ ...baseFilter,
+ ...getObjectByFilter(searchParams)
+ };
+
+ if (!isEqual(baseFilter, filter)) {
+ getExpertsList(filter, locale)
+ .then((experts) => {
+ setExperts(experts);
+ });
+ } else {
+ setExperts(data);
+ }
+ }, []);
+
+ return experts ? (
+ <>
+ (
+
+
+
+ )}
+ description={(
+
+
+
{`${item.name} ${item?.surname || ''}`}
+
+
+ {getTitle(priceTitle, item?.sessionCost)} / {getTitle(durationTitle, item?.sessionDuration)}
+
+
+ )}
+ />
+
+
+ {item?.tags?.slice(0, 2).map((skill) => {skill?.name} )}
+ {item?.tags?.length > 2
+ ? (
+
+
+ {`+${item?.tags?.length - 2}`}
+
+
+ ) : null}
- )}
- />
-
-
- {item?.tags?.slice(0, 2).map((skill) => {skill?.name} )}
- {item?.tags?.length > 2
- ? (
-
-
- {`+${item?.tags?.length - 2}`}
-
-
- ) : null}
-
-
{item?.speciality}
-
{item?.specialityDesc}
-
{item?.description}
-
-
- {detailButton}
-
-
-
-
- )}
- />
- );
+
{item?.speciality}
+
{item?.specialityDesc}
+
{item?.description}
+
+
+ {detailButton}
+
+
+
+
+ )}
+ />
+
+ >
+ ) :
;
};
diff --git a/src/components/Experts/Filter.tsx b/src/components/Experts/Filter.tsx
index 3f55f0d..f08ac33 100644
--- a/src/components/Experts/Filter.tsx
+++ b/src/components/Experts/Filter.tsx
@@ -10,8 +10,8 @@ import { getObjectByFilter, getObjectByAdditionalFilter } from '../../utils/filt
import { CustomSwitch, CustomSlider } from '../view';
type ExpertsFilterProps = {
- searchData: SearchData;
- basePath?: string;
+ searchData?: SearchData;
+ basePath: string;
priceTitle: string;
durationTitle: string;
buttonApply: string;
@@ -19,7 +19,7 @@ type ExpertsFilterProps = {
export const ExpertsFilter = ({
searchData,
- basePath = '/',
+ basePath,
priceTitle,
durationTitle,
buttonApply
@@ -83,7 +83,7 @@ export const ExpertsFilter = ({
const goToFilterPage = useCallback(() => {
router.push({
- pathname: basePath,
+ pathname: basePath as any,
query: {
...filter,
...getObjectByAdditionalFilter(searchParams)
@@ -116,7 +116,7 @@ export const ExpertsFilter = ({
return (
- {searchData.themesGroups?.length && searchData.themesGroups.map(({ id, name, tags }) => (
+ {searchData?.themesGroups?.length && searchData.themesGroups.map(({ id, name, tags }) => (
{name}
{getList(tags)}
@@ -127,9 +127,9 @@ export const ExpertsFilter = ({
@@ -138,9 +138,9 @@ export const ExpertsFilter = ({
diff --git a/src/components/Modals/AuthModal.tsx b/src/components/Modals/AuthModal.tsx
index f48f8a7..1ee1f51 100644
--- a/src/components/Modals/AuthModal.tsx
+++ b/src/components/Modals/AuthModal.tsx
@@ -3,12 +3,13 @@
import React, { FC, useState } from 'react';
import { usePathname } from 'next/navigation';
import Image from 'next/image';
+import Link from 'next/link';
import {Button, Modal as AntdModal, Form, notification} from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import { styled } from 'styled-components';
-import { CustomInput } from '../view';
+import { CustomInput, CustomInputPassword } from '../view';
import { getAuth } from '../../actions/auth';
-import {setAuthToken} from "../../utils/storage/auth";
+import { setAuthToken } from '../../utils/storage/auth';
type AuthModalProps = {
open: boolean;
@@ -74,7 +75,7 @@ export const AuthModal: FC
= ({
mode,
updateMode
}) => {
- const [form] = Form.useForm<{ login: string, password: string, name: string, surname: string, phone: string }>();
+ const [form] = Form.useForm<{ login: string, password: string, confirmPassword: string }>();
const [isLoading, setIsLoading] = useState(false);
const paths = usePathname().split('/');
@@ -134,10 +135,9 @@ export const AuthModal: FC = ({
/>
-
@@ -176,25 +176,6 @@ export const AuthModal: FC = ({
{mode === 'register' && (
<>
-
-
-
-
-
-
-
-
= ({
/>
-
+
+
+
@@ -214,22 +200,7 @@ export const AuthModal: FC = ({
>
Register
- or
- }
- >
- Facebook account
-
- }
- >
- Apple account
-
- }
- >
- Google account
-
+ updateMode('enter')}>Enter
>
)}
{mode === 'reset' && (
@@ -242,10 +213,9 @@ export const AuthModal: FC = ({
/>
-
@@ -277,7 +247,7 @@ export const AuthModal: FC = ({
)}
I have read and agree with the terms of the
- User Agreement, Privacy Policy
+ User Agreement, Privacy Policy
diff --git a/src/components/Page/Header/HeaderAuthLinks.tsx b/src/components/Page/Header/HeaderAuthLinks.tsx
index 6ffeaf8..e4143f1 100644
--- a/src/components/Page/Header/HeaderAuthLinks.tsx
+++ b/src/components/Page/Header/HeaderAuthLinks.tsx
@@ -2,10 +2,11 @@
import React, { FC, useState, useEffect } from 'react';
import { Button } from 'antd';
+import { useSelectedLayoutSegment } from 'next/navigation';
import { styled } from 'styled-components';
import { AuthModal } from '../../Modals/AuthModal';
-import {checkAuthToken} from "../../../utils/storage/auth";
-import {Link} from "../../../navigation";
+import { checkAuthToken } from '../../../utils/storage/auth';
+import { Link } from '../../../navigation';
type HeaderAuthLinksProps = {
enterTitle: string;
@@ -32,6 +33,8 @@ export const HeaderAuthLinks: FC
= ({
}) => {
const [isOpenModal, setIsOpenModal] = useState(false);
const [mode, setMode] = useState<'enter' | 'register' | 'reset' | 'finish'>('enter');
+ const selectedLayoutSegment = useSelectedLayoutSegment();
+ const pathname = selectedLayoutSegment || '';
useEffect(() => {
if (!isOpenModal) {
@@ -47,7 +50,7 @@ export const HeaderAuthLinks: FC = ({
return checkAuthToken()
? (
- {accountTitle}
+ {accountTitle}
)
: (
diff --git a/src/components/Page/Header/HeaderMenu.tsx b/src/components/Page/Header/HeaderMenu.tsx
index 1731c81..de5776b 100644
--- a/src/components/Page/Header/HeaderMenu.tsx
+++ b/src/components/Page/Header/HeaderMenu.tsx
@@ -1,20 +1,38 @@
-import React, { ReactNode } from 'react';
+'use client';
+
+import React from 'react';
+import { useSelectedLayoutSegment } from 'next/navigation';
+import { Link } from '../../../navigation';
import { HeaderAuthLinks } from './HeaderAuthLinks';
type HeaderMenuProps = {
- children: ReactNode;
enterTitle: string;
registerTitle: string;
accountTitle: string;
+ linkConfig: { path: string, title: string }[];
};
-export const HeaderMenu = ({ children, enterTitle, registerTitle, accountTitle }: HeaderMenuProps) => (
-
-);
+export const HeaderMenu = ({
+ enterTitle,
+ registerTitle,
+ accountTitle,
+ linkConfig
+}: HeaderMenuProps) => {
+ const selectedLayoutSegment = useSelectedLayoutSegment();
+ const pathname = selectedLayoutSegment || '';
+
+ return (
+
+
+
+ {linkConfig.map(({ path, title }) => (
+
+ {title}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/components/Page/Header/HeaderMobileMenu.tsx b/src/components/Page/Header/HeaderMobileMenu.tsx
index 3a2f869..e69d060 100644
--- a/src/components/Page/Header/HeaderMobileMenu.tsx
+++ b/src/components/Page/Header/HeaderMobileMenu.tsx
@@ -1,17 +1,26 @@
'use client'
-import React, { FC, ReactNode, useState } from 'react';
+import React, { FC, useState } from 'react';
+import { useSelectedLayoutSegment } from 'next/navigation';
import { HeaderAuthLinks } from './HeaderAuthLinks';
+import { Link } from '../../../navigation';
type HeaderMenuMobileProps = {
- children: ReactNode;
+ linkConfig: { path: string, title: string }[];
enterTitle: string;
registerTitle: string;
accountTitle: string;
};
-export const HeaderMobileMenu: FC = ({ children, enterTitle, registerTitle, accountTitle }) => {
+export const HeaderMobileMenu: FC = ({
+ linkConfig,
+ enterTitle,
+ registerTitle,
+ accountTitle
+}) => {
const [showMobileMenu, setShowMobileMenu] = useState(false);
+ const selectedLayoutSegment = useSelectedLayoutSegment();
+ const pathname = selectedLayoutSegment || '';
return (
<>
@@ -40,7 +49,11 @@ export const HeaderMobileMenu: FC = ({ children, enterTit
- {children}
+ {linkConfig.map(({ path, title }) => (
+
+ {title}
+
+ ))}
diff --git a/src/components/Page/Header/index.tsx b/src/components/Page/Header/index.tsx
index 1413497..80497ab 100644
--- a/src/components/Page/Header/index.tsx
+++ b/src/components/Page/Header/index.tsx
@@ -13,11 +13,10 @@ type HeaderProps = {
export const Header: FC = ({ locale }) => {
const t = useTranslations('Header');
- const routes = HEAD_ROUTES.map((item) => (
-
- {t(`menu.${item}`)}
-
- ));
+ const routes: { path: string, title: string }[] = HEAD_ROUTES.map((item) => ({
+ path: item,
+ title: t(`menu.${item}`)
+ }));
return (
<>
@@ -30,15 +29,21 @@ export const Header: FC = ({ locale }) => {
alt=""
/>
-
- {routes}
-
+
-
- {routes}
-
+
>
);
};
diff --git a/src/components/view/CustomInputPassword.tsx b/src/components/view/CustomInputPassword.tsx
new file mode 100644
index 0000000..a32ee9e
--- /dev/null
+++ b/src/components/view/CustomInputPassword.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import styled from 'styled-components';
+import { Input as AntdInput } from 'antd';
+import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
+
+const Input = styled(AntdInput.Password)`
+ padding: 15px 16px !important;
+ background: #F8F8F7 !important;
+ border: 1px solid #F8F8F7 !important;
+ border-radius: 8px !important;
+ color: #000 !important;
+ box-shadow: none !important;
+
+ input {
+ background: transparent !important;
+ }
+
+ &:focus, &:hover, &.ant-input-affix-wrapper-focused {
+ border-color: #66A5AD !important;
+ box-shadow: none !important;
+ }
+
+ input::placeholder {
+ color: #000 !important;
+ opacity: .4 !important;
+ }
+
+ &.ant-input-status-error:not(.ant-input-disabled):not(.ant-input-borderless) {
+ border-color: #ff4d4f !important;
+ }
+
+ .ant-input-suffix {
+ opacity: .3;
+ }
+`;
+
+export const CustomInputPassword = (props: any) => (
+ (visible
+ ?
+ :
+ )}
+ {...props}
+ />
+);
diff --git a/src/components/view/CustomMultiSelect.tsx b/src/components/view/CustomMultiSelect.tsx
index e69de29..501e1d0 100644
--- a/src/components/view/CustomMultiSelect.tsx
+++ b/src/components/view/CustomMultiSelect.tsx
@@ -0,0 +1,106 @@
+import React, {useEffect, useState} from 'react';
+import styled from 'styled-components';
+import { Select as AntdSelect, Tag } from 'antd';
+import type { SelectProps } from 'antd';
+
+type TagRender = SelectProps['tagRender'];
+
+const Select = styled(AntdSelect)`
+ width: 100% !important;
+ height: 54px !important;
+
+ .ant-select-selector {
+ background-color: #F8F8F7 !important;
+ border-color: #F8F8F7 !important;
+ border-radius: 8px !important;
+ padding: 22px 16px 8px !important;
+ box-shadow: none !important;
+
+ .ant-select-selection-item {
+ font-size: 15px !important;
+ font-weight: 400 !important;
+ line-height: 24px !important;
+ color: #313131 !important;
+ }
+ }
+
+ .ant-select-selection-overflow-item {
+ margin-right: 4px;
+ }
+
+ .ant-select-arrow {
+ color: #2c7873 !important;
+ }
+
+ &.ant-select-focused, &:hover {
+ .ant-select-selector {
+ border-color: #2c7873 !important;
+ box-shadow: none !important;
+ }
+ }
+`;
+
+const SelectWrap = styled.div`
+ position: relative;
+ width: 100%;
+`;
+
+const SelectLabel = styled.div`
+ font-size: 15px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 24px;
+ color: #000;
+ opacity: .3;
+ position: absolute;
+ left: 16px;
+ top: 15px;
+ z-index: 1;
+ transition: all .1s ease;
+
+ .b-multiselect__active & {
+ font-size: 12px;
+ font-weight: 300;
+ line-height: 14px;
+ top: 8px;
+ }
+`;
+
+const tagRender: TagRender = (props) => {
+ const { label } = props;
+
+ return (
+
+ {label}
+
+ );
+};
+
+export const CustomMultiSelect = (props: any) => {
+ const { label, value, ...other } = props;
+ const [isActiveLabel, setIsActiveLabel] = useState(false);
+
+ useEffect(() => {
+ if (label) {
+ setIsActiveLabel(!!value?.length);
+ } else {
+ setIsActiveLabel(false);
+ }
+ }, [value]);
+
+ return (
+
+ {label}
+ setIsActiveLabel(true) : undefined}
+ onBlur={() => setIsActiveLabel(!!value?.length)}
+ {...other}
+ />
+
+ );
+};
diff --git a/src/components/view/CustomSelect.tsx b/src/components/view/CustomSelect.tsx
index e69de29..936bcfc 100644
--- a/src/components/view/CustomSelect.tsx
+++ b/src/components/view/CustomSelect.tsx
@@ -0,0 +1,85 @@
+import React, { useEffect, useState } from 'react';
+import styled from 'styled-components';
+import { Select as AntdSelect} from 'antd';
+
+const Select = styled(AntdSelect)`
+ width: 100% !important;
+ height: 54px !important;
+
+ .ant-select-selector {
+ background-color: #F8F8F7 !important;
+ border-color: #F8F8F7 !important;
+ border-radius: 8px !important;
+ padding: 22px 16px 8px !important;
+ box-shadow: none !important;
+
+ .ant-select-selection-item {
+ font-size: 15px !important;
+ font-weight: 400 !important;
+ line-height: 24px !important;
+ color: #313131 !important;
+ }
+ }
+
+ .ant-select-arrow {
+ color: #2c7873 !important;
+ }
+
+ &.ant-select-focused, &:hover {
+ .ant-select-selector {
+ border-color: #2c7873 !important;
+ box-shadow: none !important;
+ }
+ }
+`;
+
+const SelectWrap = styled.div`
+ position: relative;
+ width: 100%;
+`;
+
+const SelectLabel = styled.div`
+ font-size: 15px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 24px;
+ color: #000;
+ opacity: .3;
+ position: absolute;
+ left: 16px;
+ top: 15px;
+ z-index: 1;
+ transition: all .1s ease;
+
+ .b-select__active & {
+ font-size: 12px;
+ font-weight: 300;
+ line-height: 14px;
+ top: 8px;
+ }
+`;
+
+export const CustomSelect = (props: any) => {
+ const { label, value, ...other } = props;
+ const [isActiveLabel, setIsActiveLabel] = useState(false);
+
+ useEffect(() => {
+ if (label) {
+ setIsActiveLabel(!!value);
+ } else {
+ setIsActiveLabel(false);
+ }
+ }, [value]);
+
+ return (
+
+ {label}
+ setIsActiveLabel(true) : undefined}
+ onBlur={() => setIsActiveLabel(!!value)}
+ {...other}
+ />
+
+ );
+};
diff --git a/src/components/view/CustomSpin.tsx b/src/components/view/CustomSpin.tsx
new file mode 100644
index 0000000..844c7c6
--- /dev/null
+++ b/src/components/view/CustomSpin.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import { Spin as AntdSpin } from 'antd';
+import { styled } from 'styled-components';
+
+const Spin = styled(AntdSpin)`
+ width: 100%;
+ margin: 24px 0;
+`;
+
+export const CustomSpin = (props: any) => (
+
+);
diff --git a/src/components/view/index.ts b/src/components/view/index.ts
index 380f0db..b7b0905 100644
--- a/src/components/view/index.ts
+++ b/src/components/view/index.ts
@@ -5,3 +5,7 @@ export * from './CustomSlider';
export * from './CustomPagination';
export * from './CustomRate';
export * from './CustomInput';
+export * from './CustomInputPassword';
+export * from './CustomSelect';
+export * from './CustomMultiSelect';
+export * from './CustomSpin';
diff --git a/src/middleware.ts b/src/middleware.ts
index 6ff174d..24342a4 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -9,5 +9,4 @@ export default createMiddleware({
export const config = {
matcher: ['/', '/(en|ru|de|it|es|fr)/:path*']
- // matcher: ['/', '/(en|ru|de|it|es|fr).html']
};
diff --git a/src/styles/_default.scss b/src/styles/_default.scss
index 96bf644..53e4b73 100644
--- a/src/styles/_default.scss
+++ b/src/styles/_default.scss
@@ -15,6 +15,10 @@ body{
color: #fff;
}
+a {
+ color: #66A5AD !important;
+}
+
.b-wrapper {
width: 100%;
height: 100%;
@@ -426,21 +430,21 @@ body{
.btn-apply {
user-select: none;
- outline: none;
- border: none;
+ outline: none !important;
+ border: none !important;
text-decoration: none;
width: 100%;
cursor: pointer;
- border-radius: 8px;
- background: #FFBD00;
- box-shadow: 0px 2px 4px 0px rgba(252, 214, 70, 0.16);
+ border-radius: 8px !important;
+ background: #FFBD00 !important;
+ box-shadow: 0px 2px 4px 0px rgba(252, 214, 70, 0.16) !important;
display: flex;
gap: 10px;
- height: 54px;
+ height: 54px !important;
padding: 8px 31px;
justify-content: center;
align-items: center;
- color: #003B46;
+ color: #003B46 !important;
@include rem(15);
font-style: normal;
font-weight: 400;
diff --git a/src/styles/_footer.scss b/src/styles/_footer.scss
index 9ab2f0a..e22d94a 100644
--- a/src/styles/_footer.scss
+++ b/src/styles/_footer.scss
@@ -70,7 +70,7 @@
display: inline-flex;
gap: 8px;
text-decoration: none;
- color: #003B46;
+ color: #003B46 !important;
@include rem(16);
font-style: normal;
font-weight: 700;
diff --git a/src/styles/_header.scss b/src/styles/_header.scss
index 6745d43..a5e6e9f 100644
--- a/src/styles/_header.scss
+++ b/src/styles/_header.scss
@@ -66,6 +66,10 @@
display: inline-flex;
align-items: center;
text-decoration: none;
+
+ &.active {
+ color: #003B46;
+ }
}
.text {
diff --git a/src/styles/_main.scss b/src/styles/_main.scss
index 64ad623..4575b30 100644
--- a/src/styles/_main.scss
+++ b/src/styles/_main.scss
@@ -199,7 +199,7 @@
@include rem(14);
border-radius: 24px;
gap: 6px;
- color: $white;
+ color: $white !important;
font-style: normal;
font-weight: 700;
line-height: 133.333%;
diff --git a/src/utils/filter.ts b/src/utils/filter.ts
index 286d279..f357b22 100644
--- a/src/utils/filter.ts
+++ b/src/utils/filter.ts
@@ -62,7 +62,7 @@ export const getObjectByFilter = (searchParams?: any): Filter | undefined => {
let tags = searchParams?.getAll('themesTagIds');
if (tags && tags.length > 0) {
- filter.themesTagIds = tags.map((id) => Number(id));
+ filter.themesTagIds = tags.map((id: string) => Number(id));
}
if (searchParams?.has('priceFrom')) {
diff --git a/src/utils/storage/auth.ts b/src/utils/storage/auth.ts
index 9b2696f..9f4a7df 100644
--- a/src/utils/storage/auth.ts
+++ b/src/utils/storage/auth.ts
@@ -7,7 +7,7 @@ export function checkAuthToken() {
}
export function getAuthToken() {
- return 'tr';
+ return '';
}
// export function getAuthToken() {
@@ -18,6 +18,6 @@ export function getAuthToken() {
// localStorage.removeItem(AUTH_TOKEN_KEY);
// }
//
-// export function setAuthToken(token: string) {
-// localStorage.setItem(AUTH_TOKEN_KEY, token);
-// }
+export function setAuthToken(token: string) {
+ // localStorage.setItem(AUTH_TOKEN_KEY, token);
+}