feat: add more translate, fix styles

This commit is contained in:
SD 2024-07-29 23:57:04 +04:00
parent 4a00d715df
commit abf04b4c5b
53 changed files with 873 additions and 546 deletions

View File

@ -1,20 +1,10 @@
{
"Header": {
"registration": "Registration",
"enter": "Enter",
"account": "My Account",
"menu": {
"bb-client": "Start grow with BB",
"bb-expert": "Become BB Expert",
"blog": "Blog&News"
}
},
"Main": {
"title": "Bbuddy - Main",
"description": "Bbuddy desc",
"header": "Mentorship, Career\nDevelopment & Coaching.",
"header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.",
"news": "Professional Articles & Project News",
"header": "BBuddy: Plattform für persönlichen und beruflichen Erfolg",
"header-desc": "Erhalten Sie Beratungen von führenden Coaches und Mentoren auf BBuddy. Unsere Experten helfen Ihnen, sich zu entwickeln, zu lernen und Ihre persönlichen und beruflichen Ziele zu erreichen. Nutzen Sie unsere Web-Plattform und mobile App für professionelle Unterstützung und Wachstum.",
"news": "Fachartikel & Projektneuigkeiten",
"popular": "Popular Topics"
},
"BbClient": {
@ -89,7 +79,7 @@
}
},
"Experts": {
"title": "Find a expert",
"title": "Find an expert",
"filter": {
"price": "Price from {from}€ to {to}€",
"duration": "Duration from {from}min to {to}min",

View File

@ -2,8 +2,8 @@
"Main": {
"title": "Bbuddy - Main",
"description": "Bbuddy desc",
"header": "Mentorship, Career\nDevelopment & Coaching.",
"header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.",
"header": "BBuddy: Platform for Personal and Career Success",
"header-desc": "Receive consultations from leading coaches and mentors on BBuddy. Our experts will help you develop, learn, and achieve your personal and career goals. Use our web platform and mobile app for professional support and growth.",
"news": "Professional Articles & Project News",
"popular": "Popular Topics"
},
@ -69,7 +69,7 @@
}
},
"Experts": {
"title": "Find a expert",
"title": "Find an expert",
"filter": {
"price": "Price from {from}€ to {to}€",
"duration": "Duration from {from}min to {to}min",

View File

@ -1,20 +1,10 @@
{
"Header": {
"registration": "Registration",
"enter": "Enter",
"account": "My Account",
"menu": {
"bb-client": "Start grow with BB",
"bb-expert": "Become BB Expert",
"blog": "Blog&News"
}
},
"Main": {
"title": "Bbuddy - Main",
"description": "Bbuddy desc",
"header": "Mentorship, Career\nDevelopment & Coaching.",
"header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.",
"news": "Professional Articles & Project News",
"header": "BBuddy: Plataforma para el éxito personal y profesional",
"header-desc": "Reciba consultas de entrenadores y mentores líderes en BBuddy. Nuestros expertos le ayudarán a desarrollarse, aprender y alcanzar sus objetivos personales y profesionales. Utilice nuestra plataforma web y aplicación móvil para apoyo profesional y crecimiento.",
"news": "Artículos profesionales y Noticias de proyectos",
"popular": "Popular Topics"
},
"BbClient": {
@ -89,7 +79,7 @@
}
},
"Experts": {
"title": "Find a expert",
"title": "Find an expert",
"filter": {
"price": "Price from {from}€ to {to}€",
"duration": "Duration from {from}min to {to}min",

View File

@ -1,20 +1,10 @@
{
"Header": {
"registration": "Registration",
"enter": "Enter",
"account": "My Account",
"menu": {
"bb-client": "Start grow with BB",
"bb-expert": "Become BB Expert",
"blog": "Blog&News"
}
},
"Main": {
"title": "Bbuddy - Main",
"description": "Bbuddy desc",
"header": "Mentorship, Career\nDevelopment & Coaching.",
"header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.",
"news": "Professional Articles & Project News",
"header": "BBuddy: Plateforme pour le succès personnel et professionnel",
"header-desc": "Recevez des consultations de coachs et mentors de premier plan sur BBuddy. Nos experts vous aideront à développer, apprendre et atteindre vos objectifs personnels et professionnels. Utilisez notre plateforme web et notre application mobile pour un soutien professionnel et une croissance.",
"news": "Articles professionnels et actualités des projets",
"popular": "Popular Topics"
},
"BbClient": {
@ -89,7 +79,7 @@
}
},
"Experts": {
"title": "Find a expert",
"title": "Find an expert",
"filter": {
"price": "Price from {from}€ to {to}€",
"duration": "Duration from {from}min to {to}min",

View File

@ -1,20 +1,10 @@
{
"Header": {
"registration": "Registration",
"enter": "Enter",
"account": "My Account",
"menu": {
"bb-client": "Start grow with BB",
"bb-expert": "Become BB Expert",
"blog": "Blog&News"
}
},
"Main": {
"title": "Bbuddy - Main",
"description": "Bbuddy desc",
"header": "Mentorship, Career\nDevelopment & Coaching.",
"header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.",
"news": "Professional Articles & Project News",
"header": "BBuddy: Piattaforma per il successo personale e professionale",
"header-desc": "Ricevi consulenze da coach e mentori leader su BBuddy. I nostri esperti ti aiuteranno a svilupparti, imparare e raggiungere i tuoi obiettivi personali e professionali. Usa la nostra piattaforma web e l'app mobile per supporto professionale e crescita.",
"news": "Articoli professionali e novità sui progetti",
"popular": "Popular Topics"
},
"BbClient": {
@ -89,7 +79,7 @@
}
},
"Experts": {
"title": "Find a expert",
"title": "Find an expert",
"filter": {
"price": "Price from {from}€ to {to}€",
"duration": "Duration from {from}min to {to}min",

View File

@ -1,20 +1,10 @@
{
"Header": {
"registration": "Регистрация",
"enter": "Вход",
"account": "Мой аккаунт",
"menu": {
"bb-client": "Начни вместе с BB",
"bb-expert": "Стань BB экспертом",
"blog": "Блог&Новости"
}
},
"Main": {
"title": "Bbuddy - Главная",
"description": "Bbuddy описание",
"header": "Mentorship, Career\nDevelopment & Coaching.",
"header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.",
"news": "Professional Articles & Project News",
"header": "BBuddy: Платформа для Личного и Карьерного Успеха",
"header-desc": "Получайте консультации от ведущих коучей и менторов в BBuddy. Наши эксперты помогут вам развиваться, обучаться и достигать личных и карьерных целей. Используйте нашу веб-платформу и мобильное приложение для получения профессиональной поддержки и роста.",
"news": "Профессиональные статьи и новости проекта",
"popular": "Popular Topics"
},
"BbClient": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,26 +1,14 @@
import { AxiosResponse } from 'axios';
import { apiClient } from '../lib/apiClient';
import { apiRequest } from './helpers';
export const getAuth = (locale: string, data: { login: string, password: string }): Promise<AxiosResponse<{ jwtToken: string }>> => (
apiClient.post(
'/auth/login',
export const getAuth = (locale: string, data: { login: string, password: string }): Promise<{ jwtToken: string }> => apiRequest({
url: '/auth/login',
method: 'post',
data,
{
headers: {
'X-User-Language': locale
}
}
)
);
locale
});
export const getRegister = (locale: string): Promise<AxiosResponse<{ jwtToken: string }>> => (
apiClient.post(
'/auth/register',
{},
{
headers: {
'X-User-Language': locale
}
}
)
);
export const getRegister = (locale: string): Promise<{ jwtToken: string }> => apiRequest({
url: '/auth/register',
method: 'post',
locale
});

View File

@ -1,30 +1,16 @@
import { apiClient } from '../lib/apiClient';
import { GeneralFilter, ExpertsData, ExpertDetails } from '../types/experts';
import { apiRequest } from './helpers';
export const getExpertsList = async (locale: string, filter?: GeneralFilter) => {
const response = await apiClient.post(
'/home/coachsearch1',
{ ...filter },
{
headers: {
'X-User-Language': locale
}
}
);
export const getExpertsList = (locale: string, filter?: GeneralFilter): Promise<ExpertsData> => apiRequest({
url: '/home/coachsearch1',
method: 'post',
data: { ...filter },
locale
});
return response.data as ExpertsData || null;
};
export const getExpertById = async (id: string, locale: string) => {
const response = await apiClient.post(
'/home/coachdetails',
{ id },
{
headers: {
'X-User-Language': locale
}
}
);
return response.data as ExpertDetails || null;
};
export const getExpertById = (id: string, locale: string): Promise<ExpertDetails> => apiRequest({
url: '/home/coachdetails',
method: 'post',
data: { id },
locale
});

43
src/actions/helpers.ts Normal file
View File

@ -0,0 +1,43 @@
import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { apiClient } from '../lib/apiClient';
type RequiredConfigParams<D = any> = Required<Pick<AxiosRequestConfig, 'url' | 'method'>> & Pick<AxiosRequestConfig<D>, 'data'>;
export type PageRequestConfig<D = any> = RequiredConfigParams<D> & { locale?: string, token?: string };
export const apiRequest = async <T = any, K = any>(
baseParams: PageRequestConfig<T>,
): Promise<K> => {
try {
const config = {
url: baseParams.url,
method: baseParams.method,
data: baseParams?.data,
headers: {
'X-User-Language': baseParams?.locale || 'en',
'X-Referrer-Channel': 'site',
...(baseParams?.token ? { Authorization: `Bearer ${baseParams.token}` } : {})
}
};
const response: AxiosResponse<K> = await apiClient.request<any, AxiosResponse<K>, T>(config as AxiosRequestConfig<T>);
return response.data;
} catch (err) {
const {
response: {
status: responseCode = null,
statusText = '',
data: { message = '', status: errorKey = '' } = {},
} = {},
code: statusCode = '',
} = err as AxiosError;
throw new Error(
JSON.stringify({
statusCode,
statusMessage: message || statusText,
responseCode,
errorKey,
}),
);
}
};

View File

@ -15,7 +15,7 @@ export const useProfileSettings = (locale: string) => {
useEffect(() => {
if (jwt) {
getPersonalData(locale, jwt)
.then(({ data }) => {
.then((data) => {
setProfileSettings(data);
})
.catch((err) => {

View File

@ -18,8 +18,8 @@ export const useSessionDetails = (locale: string, sessionId: number) => {
setSession(undefined);
getSessionDetails(locale, jwt, sessionId)
.then(({ data }) => {
setSession(data);
.then((session) => {
setSession(session);
})
.catch((err) => {
setErrorData(err);

View File

@ -1,29 +1,17 @@
import { AxiosResponse } from 'axios';
import { apiClient } from '../lib/apiClient';
import { Profile } from '../types/profile';
import { apiRequest } from './helpers';
export const setPersonData = (person: { login: string, password: string, role: string, languagesLinks: any[] }, locale: string, jwt: string): Promise<AxiosResponse<{ userData: Profile }>> => (
apiClient.post(
'/home/applyperson1',
{ ...person },
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
export const setPersonData = (data: { login: string, password: string, role: string, languagesLinks: any[] }, locale: string, token: string): Promise<{ userData: Profile }> => apiRequest({
url: '/home/applyperson1',
method: 'post',
data,
locale,
token
});
export const getPersonalData = (locale: string, jwt: string): Promise<AxiosResponse<Profile>> => (
apiClient.post(
'/home/userdata',
{},
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
export const getPersonalData = (locale: string, token: string): Promise<Profile> => apiRequest({
url: '/home/userdata',
method: 'post',
locale,
token
});

View File

@ -1,145 +1,93 @@
import { AxiosResponse } from 'axios';
import { apiClient } from '../lib/apiClient';
import { DeclineSessionData, Session, SessionsFilter, SessionCommentData } from '../types/sessions';
import { apiRequest } from './helpers';
export const getUpcomingSessions = (locale: string, jwt: string, filter?: SessionsFilter): Promise<AxiosResponse<Session[]>> => (
apiClient.post(
'/home/upcomingsessionsall',
{
export const getUpcomingSessions = (locale: string, token: string, filter?: SessionsFilter): Promise<Session[]> => apiRequest({
url: '/home/upcomingsessionsall',
method: 'post',
data: {
sessionType: 'session',
...(filter || {})
},
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
locale,
token
});
export const getRequestedSessions = (locale: string, jwt: string): Promise<AxiosResponse<{ requestedSessions: Session[] }>> => (
apiClient.post(
'/home/coachhomedata',
{},
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
export const getRequestedSessions = (locale: string, token: string): Promise<{ requestedSessions: Session[] }> => apiRequest({
url: '/home/coachhomedata',
method: 'post',
locale,
token
});
export const getRecentSessions = (locale: string, jwt: string, filter?: SessionsFilter): Promise<AxiosResponse<Session[]>> => (
apiClient.post(
'/home/historicalmeetings',
{
export const getRecentSessions = (locale: string, token: string, filter?: SessionsFilter): Promise<Session[]> => apiRequest({
url: '/home/historicalmeetings',
method: 'post',
data: {
sessionType: 'session',
...(filter || {})
},
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
locale,
token
});
export const getSessionDetails = (locale: string, jwt: string, id: number): Promise<AxiosResponse<Session>> => (
apiClient.post(
'/home/session',
{ id },
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
export const getSessionDetails = (locale: string, token: string, id: number): Promise<Session> => apiRequest({
url: '/home/session',
method: 'post',
data: { id },
locale,
token
});
export const approveRequestedSession = (locale: string, jwt: string, sessionId: number): Promise<AxiosResponse> => (
apiClient.post(
'/home/approverequestedsession',
{ sessionId },
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
export const approveRequestedSession = (locale: string, token: string, sessionId: number): Promise<any> => apiRequest({
url: '/home/approverequestedsession',
method: 'post',
data: { sessionId },
locale,
token
});
export const declineRequestedSession = (locale: string, jwt: string, { sessionId, reason }: DeclineSessionData): Promise<AxiosResponse> => (
apiClient.post(
'/home/declinerequestedsession',
{
export const declineRequestedSession = (locale: string, token: string, { sessionId, reason }: DeclineSessionData): Promise<any> => apiRequest({
url: '/home/declinerequestedsession',
method: 'post',
data: {
sessionId,
coachDeclineReason: reason
},
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
locale,
token
});
export const cancelUpcomingSession = (locale: string, jwt: string, { sessionId, reason }: DeclineSessionData): Promise<AxiosResponse> => (
apiClient.post(
'/home/cancelupcomingsession',
{
export const cancelUpcomingSession = (locale: string, token: string, { sessionId, reason }: DeclineSessionData): Promise<any> => apiRequest({
url: '/home/cancelupcomingsession',
method: 'post',
data: {
sessionId,
coachCancelReason: reason
},
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
locale,
token
});
export const addSessionComment = (locale: string, jwt: string, data: SessionCommentData): Promise<AxiosResponse> => (
apiClient.post(
'/home/session_comment',
export const addSessionComment = (locale: string, token: string, data: SessionCommentData): Promise<any> => apiRequest({
url: '/home/session_comment',
method: 'post',
data,
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
locale,
token
});
export const trackingStartSession = (locale: string, jwt: string, id: number): Promise<AxiosResponse> => (
apiClient.post(
'/home/sessiontracking',
{ id },
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
export const trackingStartSession = (locale: string, token: string, id: number): Promise<any> => apiRequest({
url: '/home/sessiontracking',
method: 'post',
data: { id },
locale,
token
});
export const finishSession = (locale: string, jwt: string, sessionId: number): Promise<AxiosResponse> => (
apiClient.post(
'/home/finishsession',
{ sessionId },
{
headers: {
'X-User-Language': locale,
Authorization: `Bearer ${jwt}`
}
}
)
);
export const finishSession = (locale: string, token: string, sessionId: number): Promise<any> => apiRequest({
url: '/home/finishsession',
method: 'post',
data: { sessionId },
locale,
token
});

View File

@ -1,29 +1,14 @@
import { apiClient } from '../lib/apiClient';
import { SearchData, Languages } from '../types/tags';
import { apiRequest } from './helpers';
export const getTagList = async (locale: string) => {
const response = await apiClient.post(
'/home/searchdata',
{},
{
headers: {
'X-User-Language': locale
}
}
);
export const getTagList = (locale: string): Promise<SearchData> => apiRequest({
url: '/home/searchdata',
method: 'post',
locale
});
return response.data as SearchData || null;
};
export const getLanguages = async (locale: string) => {
const response = await apiClient.get(
'/home/languages',
{
headers: {
'X-User-Language': locale
}
}
);
return response.data as Languages || null;
};
export const getLanguages = (locale: string): Promise<Languages> => apiRequest({
url: '/home/languages',
method: 'get',
locale
});

View File

@ -1,10 +1,16 @@
import React from 'react';
import { useTranslations } from 'next-intl';
import { unstable_setRequestLocale } from 'next-intl/server';
import { i18nText } from '../../../../i18nKeys';
export default function News({ params: { locale } }: { params: { locale: string }}) {
unstable_setRequestLocale(locale);
const t = useTranslations('Main');
export default function News() {
return (
<div className="main-articles">
<div className="b-inner">
<h2 className="title-h2">Professional Articles & Project News</h2>
<h2 className="title-h2">{t('news')}</h2>
<div className="row">
<div className="col-lg-4 col-md-6 col-sm-6">
<div className="b-article">
@ -18,7 +24,7 @@ export default function News() {
performance from many angles, such as human resources management, IT, operations
management, risks etc.
</div>
<a href="#" className="b-article__link">Read more
<a href="#" className="b-article__link">{i18nText('readMore', locale)}
<img className="" src="/images/chevron-forward.svg" alt=""/>
</a>
</div>
@ -36,7 +42,7 @@ export default function News() {
performance from many angles, such as human resources management, IT, operations
management, risks etc.
</div>
<a href="#" className="b-article__link">Read more
<a href="#" className="b-article__link">{i18nText('readMore', locale)}
<img className="" src="/images/chevron-forward.svg" alt=""/>
</a>
</div>
@ -54,7 +60,7 @@ export default function News() {
performance from many angles, such as human resources management, IT, operations
management, risks etc.
</div>
<a href="#" className="b-article__link">Read more
<a href="#" className="b-article__link">{i18nText('readMore', locale)}
<img className="" src="/images/chevron-forward.svg" alt=""/>
</a>
</div>

View File

@ -12,17 +12,15 @@ import React, { ReactNode } from 'react';
// };
// }
export default function MainLayout({ children, news, directions, experts }: {
export default function MainLayout({ children, news, experts }: {
children: ReactNode,
news: ReactNode,
directions: ReactNode,
experts: ReactNode
}) {
return (
<>
{children}
{news}
{directions}
{experts}
</>
);

View File

@ -1,7 +1,11 @@
import React from 'react';
import { unstable_setRequestLocale } from 'next-intl/server';
import { Link } from '../../../../../../navigation';
import { i18nText } from '../../../../../../i18nKeys';
export default function Coaching({ params: { locale } }: { params: { locale: string } }) {
unstable_setRequestLocale(locale);
export default function Coaching() {
return (
<>
<ol className="breadcrumb">
@ -94,9 +98,7 @@ export default function Coaching() {
</div>
</div>
<div className="coaching-section">
<h2 className="title-h2">
Professional Certification
</h2>
<h2 className="title-h2">{i18nText('profCertification', locale)}</h2>
<div className="coaching-section__desc">
<div className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra

View File

@ -1,30 +1,24 @@
import React from 'react';
import type { Metadata } from 'next';
import { unstable_setRequestLocale } from 'next-intl/server';
import { useTranslations } from 'next-intl';
import { i18nText } from '../../../../../i18nKeys';
export const metadata: Metadata = {
title: 'Bbuddy - Account - Work with us',
description: 'Bbuddy desc work with us'
};
export default function WorkWithUs({ params: { locale } }: { params: { locale: string } }) {
unstable_setRequestLocale(locale);
const t = useTranslations('Account.WorkWithUs');
return (
<>
<ol className="breadcrumb">
<li className="breadcrumb-item active" aria-current="page">{i18nText('accountMenu.work-with-us', locale)}</li>
</ol>
<div className="b-info">
<div className="b-work">
<div className="image-info">
<img className="" src="/images/info.png" alt="" />
</div>
<div className="b-info__title">{i18nText('insertInfo', locale)}</div>
<div className="b-work__description">
<div className="b-work__text">{i18nText('insertInfo', locale)}</div>
<div className="b-work__text">{i18nText('changeUserData', locale)}</div>
<button className="btn-apply">{i18nText('getStarted', locale)}</button>
<div className="base-text">{i18nText('changeUserData', locale)}</div>
</div>
</div>
</>
);

View File

@ -11,6 +11,7 @@ import {
} from '../../../../components/Experts/ExpertDetails';
import { Details } from '../../../../types/experts';
import { BackButton } from '../../../../components/view/BackButton';
import { i18nText } from '../../../../i18nKeys';
export const metadata: Metadata = {
title: 'Bbuddy - Experts item',
@ -35,6 +36,7 @@ export default async function ExpertItem({ params: { expertId = '', locale} }: {
if (!expertId) notFound();
const expert = await getExpertById(expertId, locale);
console.log(expert);
const getAssociationLevel = (accLevelId?: number) => {
if (accLevelId) {
@ -75,16 +77,16 @@ export default async function ExpertItem({ params: { expertId = '', locale} }: {
<div className="b-inner">
<div className="b-page__back">
<Suspense>
<BackButton className="btn-back">
<BackButton className="btn-back btn-back__auto">
<img src="/images/arrow-back.svg" className="" alt="" />
Back to experts list
{i18nText('backToExperts', locale)}
</BackButton>
</Suspense>
</div>
<ExpertCard expert={expert} />
<ExpertCard expert={expert} locale={locale} />
<ExpertInformation expert={expert} locale={locale} />
<h2 className="title-h2">Expert Background</h2>
<h2 className="title-h2">{i18nText('expertBackground', locale)}</h2>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
@ -92,7 +94,7 @@ export default async function ExpertItem({ params: { expertId = '', locale} }: {
{expert?.publicCoachDetails?.educations && expert.publicCoachDetails.educations?.map(generateDescription)}
{expert?.publicCoachDetails?.certificates && expert.publicCoachDetails.certificates.length > 0 && (
<div>
<h3 className="title-h3">Professional Certification</h3>
<h3 className="title-h3">{i18nText('profCertification', locale)}</h3>
{expert.publicCoachDetails.certificates?.map((cert) => (
<div key={cert.id}>
<p className="base-text">
@ -110,7 +112,7 @@ export default async function ExpertItem({ params: { expertId = '', locale} }: {
{expert?.publicCoachDetails?.trainings && expert.publicCoachDetails.trainings?.map(generateDescription)}
{expert?.publicCoachDetails?.mbas && expert.publicCoachDetails.mbas?.map(generateDescription)}
{expert?.publicCoachDetails?.experiences && expert.publicCoachDetails.experiences?.map(generateDescription)}
<ExpertPractice expert={expert} />
<ExpertPractice expert={expert} locale={locale} />
{/* <h2 className="title-h2">All Offers by this Expert</h2>
<div className="offers-list">

View File

@ -1,20 +1,17 @@
'use client';
import React, { useState } from 'react';
import { Button } from 'antd';
import { useSelectedLayoutSegment, usePathname } from 'next/navigation';
import { Link } from '../../navigation';
import { AUTH_TOKEN_KEY, AUTH_USER } from '../../constants/common';
import { deleteStorageKey } from '../../hooks/useLocalStorage';
import { i18nText } from '../../i18nKeys';
import { DeleteAccountModal } from '../Modals/DeleteAccountModal';
import { getMenuConfig } from '../../utils/account';
export const AccountMenu = ({ locale }: { locale: string }) => {
const selectedLayoutSegment = useSelectedLayoutSegment();
const pathname = selectedLayoutSegment || '';
const paths = usePathname();
const [showDeleteModal, setShowDeleteModal] = useState<boolean>(false);
const menu: { path: string, title: string, count?: number }[] = getMenuConfig(locale);
const onLogout = () => {
@ -23,8 +20,6 @@ export const AccountMenu = ({ locale }: { locale: string }) => {
window?.location?.replace(`/${paths.split('/')[1]}/`);
};
const onDeleteAccount = () => setShowDeleteModal(true);
return (
<ul className="list-sidebar">
{menu.map(({ path, title, count }) => (
@ -46,19 +41,6 @@ export const AccountMenu = ({ locale }: { locale: string }) => {
{i18nText('logout', locale)}
</Button>
</li>
<li className="list-sidebar__item">
<Button
type="link"
onClick={onDeleteAccount}
className="b-button__logout"
>
{i18nText('deleteAcc', locale)}
</Button>
<DeleteAccountModal
open={showDeleteModal}
handleCancel={() => setShowDeleteModal(false)}
/>
</li>
</ul>
);
};

View File

@ -1,15 +1,18 @@
'use client';
import React, { FC, useEffect, useState } from 'react';
import { Form, Upload, Button } from 'antd';
import { Form, Upload } from 'antd';
import type { UploadFile, UploadProps } from 'antd';
import ImgCrop from 'antd-img-crop';
import { CameraOutlined } from '@ant-design/icons';
import { Link } from '../../navigation';
import { CustomInput } from '../view/CustomInput';
import { CameraOutlined, DeleteOutlined } from '@ant-design/icons';
import { useRouter } from '../../navigation';
import { i18nText } from '../../i18nKeys';
import { Profile } from '../../types/profile';
import { useProfileSettings } from '../../actions/hooks/useProfileSettings';
import { i18nText } from '../../i18nKeys';
import { CustomInput } from '../view/CustomInput';
import { OutlinedButton } from '../view/OutlinedButton';
import { FilledYellowButton } from '../view/FilledButton';
import { DeleteAccountModal } from "../Modals/DeleteAccountModal";
type ProfileSettingsProps = {
locale: string;
@ -20,6 +23,8 @@ type ProfileSettingsProps = {
export const ProfileSettings: FC<ProfileSettingsProps> = ({ locale }) => {
const [form] = Form.useForm<Profile>();
const { profileSettings } = useProfileSettings(locale);
const [showDeleteModal, setShowDeleteModal] = useState<boolean>(false);
const router = useRouter();
useEffect(() => {
if (profileSettings) {
@ -27,6 +32,13 @@ export const ProfileSettings: FC<ProfileSettingsProps> = ({ locale }) => {
}
}, [profileSettings]);
const saveProfileSettings = () => {
form.validateFields()
.then(() => {
console.log('success')
})
}
const [fileList, setFileList] = useState<UploadFile[]>();
const onChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
@ -48,6 +60,8 @@ export const ProfileSettings: FC<ProfileSettingsProps> = ({ locale }) => {
// imgWindow?.document.write(image.outerHTML);
};
const onDeleteAccount = () => setShowDeleteModal(true);
return (
<Form form={form} className="form-settings">
<div className="user-avatar">
@ -67,6 +81,7 @@ export const ProfileSettings: FC<ProfileSettingsProps> = ({ locale }) => {
<Button icon={<CameraOutlined />}>Click to Upload</Button>
</Upload>
</ImgCrop> */}
<div className="form-fieldset">
<div className="form-field">
<Form.Item name="username">
<CustomInput placeholder={i18nText('name', locale)} />
@ -87,12 +102,24 @@ export const ProfileSettings: FC<ProfileSettingsProps> = ({ locale }) => {
<CustomInput type="email" placeholder="E-mail" />
</Form.Item>
</div>
<div className="form-link">
<Link href={'change-password' as any}>
{i18nText('changePass', locale)}
</Link>
</div>
<button className="btn-apply">{i18nText('save', locale)}</button>
<div className="form-actions">
<FilledYellowButton onClick={saveProfileSettings}>{i18nText('save', locale)}</FilledYellowButton>
<OutlinedButton onClick={() => router.push('change-password')}>
{i18nText('changePass', locale)}
</OutlinedButton>
<OutlinedButton
onClick={onDeleteAccount}
icon={<DeleteOutlined />}
danger
>
{i18nText('deleteAcc', locale)}
</OutlinedButton>
</div>
<DeleteAccountModal
open={showDeleteModal}
handleCancel={() => setShowDeleteModal(false)}
/>
</Form>
);
};

View File

@ -43,7 +43,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
})
.catch((err) => {
notification.error({
message: 'Error approve session',
message: i18nText('errors.approvingSession', locale),
description: err?.response?.data?.errMessage
});
})
@ -64,7 +64,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
})
.catch((err) => {
notification.error({
message: 'Error finish session',
message: i18nText('errors.finishingSession', locale),
description: err?.response?.data?.errMessage
});
})
@ -166,7 +166,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
icon={<LeftOutlined />}
onClick={goBack}
>
Back
{i18nText('back', locale)}
</Button>
</div>
{Current}
@ -181,8 +181,8 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
disabled={finishLoading}
>
{activeType === SessionType.UPCOMING
? (session?.state === SessionState.STARTED ? 'Join Session' : 'Start Session')
: 'Confirm Session'}
? (session?.state === SessionState.STARTED ? i18nText('session.join', locale) : i18nText('session.start', locale))
: i18nText('session.confirm', locale)}
</Button>
{session?.state === SessionState.STARTED && isCoach && (
<Button
@ -190,7 +190,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
onClick={onFinishSession}
loading={finishLoading}
>
Finish Session
{i18nText('session.finish', locale)}
</Button>
)}
{session?.id && session?.state !== SessionState.STARTED && (
@ -200,7 +200,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
onClick={() => setOpenDeclineModal(true)}
disabled={approveLoading}
>
Decline Session
{i18nText('session.decline', locale)}
</Button>
<DeclineSessionModal
open={openDeclineModal}
@ -218,7 +218,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
<>
{activeType === SessionType.RECENT && (
<>
<div className="card-detail__name">Course Info</div>
<div className="card-detail__name">{i18nText('courseInfo', locale)}</div>
<div className="card-detail__inner">
{/* <div className="card-detail__info">
<div className="card-profile__subtitle">{current?.specialityDesc}</div>
@ -249,7 +249,9 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
<div className="card-detail__comments">
<div className="card-detail__comments_header">
<div className="card-detail__comments_title">
{session?.clientComments?.length === 0 && session?.coachComments?.length === 0 ? 'Comments' : 'My Comments'}
{session?.clientComments?.length === 0 && session?.coachComments?.length === 0
? i18nText('session.comments', locale)
: i18nText('session.myComments', locale)}
</div>
{activeType === SessionType.UPCOMING && (
<>
@ -260,7 +262,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
icon={<PlusOutlined style={{ fontSize: 18 }} />}
onClick={() => setOpenAddCommentModal(true)}
>
Add new
{i18nText('session.addComment', locale)}
</Button>
<AddCommentModal
open={openAddCommentModal}

View File

@ -42,9 +42,9 @@ export const SessionsTabs = ({ locale, activeTab }: SessionsTabsProps) => {
])
.then(([upcoming, requested, recent]) => {
setSessions({
[SessionType.UPCOMING]: upcoming.data || [],
[SessionType.REQUESTED]: requested.data?.requestedSessions || [],
[SessionType.RECENT]: recent.data || []
[SessionType.UPCOMING]: upcoming || [],
[SessionType.REQUESTED]: requested?.requestedSessions || [],
[SessionType.RECENT]: recent || []
});
})
.catch((err) => {
@ -115,7 +115,7 @@ export const SessionsTabs = ({ locale, activeTab }: SessionsTabsProps) => {
</div>
)
}) : (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={i18nText('noData', locale)} />
)}
</div>
</>

View File

@ -7,13 +7,15 @@ import { ZoomInOutlined, ZoomOutOutlined, StarFilled } from '@ant-design/icons';
import { ExpertDetails, ExpertDocument } from '../../types/experts';
import { Locale } from '../../types/locale';
import { CustomRate } from '../view/CustomRate';
import { i18nText } from '../../i18nKeys';
import { FilledYellowButton } from '../view/FilledButton';
type ExpertDetailsProps = {
expert: ExpertDetails;
locale?: string;
};
export const ExpertCard: FC<ExpertDetailsProps> = ({ expert }) => {
export const ExpertCard: FC<ExpertDetailsProps> = ({ expert, locale }) => {
const { publicCoachDetails } = expert || {};
return (
@ -25,39 +27,43 @@ export const ExpertCard: FC<ExpertDetailsProps> = ({ expert }) => {
<div className="expert-card__inner">
<h1 className="expert-card__title">{`${publicCoachDetails?.name} ${publicCoachDetails?.surname || ''}`}</h1>
<div className="expert-card__info">
<span>{`${publicCoachDetails?.practiceHours} Practice hours`}</span>
<span>{`${publicCoachDetails?.practiceHours} ${i18nText('practiceHours', locale)}`}</span>
<i>|</i>
<span>{`${publicCoachDetails?.supervisionPerYearId} Supervision per year`}</span>
<span>{`${publicCoachDetails?.supervisionPerYearId} ${i18nText('supervisionCount', locale)}`}</span>
</div>
<div className="expert-card__rating">
<CustomRate defaultValue={4} character={<StarFilled style={{ fontSize: 32 }} />} disabled />
<span>4/5 (out of 345)</span>
<span>{`4/5 (${i18nText('outOf', locale)} 345)`}</span>
</div>
</div>
</div>
<div className="expert-card__wrap-btn">
<a href="#" className="btn-apply">
<img src="/images/calendar-outline.svg" className="" alt="" />
Schedule
{i18nText('schedule', locale)}
</a>
{/*
<a href="#" className="btn-video">
<img src="/images/videocam-outline.svg" className="" alt=""/>
Video
</a>
*/}
</div>
</div>
);
};
export const ExpertInformation: FC<ExpertDetailsProps> = ({ expert, locale }) => {
const { publicCoachDetails: { tags = [], sessionCost = 0, sessionDuration = 0 } } = expert || {};
const { publicCoachDetails: { tags = [], sessionCost = 0, sessionDuration = 0, coachLanguages = [] } } = expert || {};
const isRus = locale === Locale.ru;
return (
<>
<h2 className="title-h2">Current Offer</h2>
<div className="expert-info">
{/* <h2 className="title-h2">{}</h2> */}
<div className="skills__list">
{tags?.map((skill) => <Tag key={skill?.id} className="skills__list__item">{skill?.name}</Tag>)}
{coachLanguages?.map((skill) => <Tag key={skill} className="skills__list__item">{skill}</Tag>)}
</div>
</div>
<p className="base-text">
Hello, my name is Marcelo. I am a Senior UX Designer with more than 6 years of experience working
@ -74,10 +80,11 @@ export const ExpertInformation: FC<ExpertDetailsProps> = ({ expert, locale }) =>
Oh, and I also speak Spanish!
</p>
<div className="skills__list">
{tags?.map((skill) => <Tag key={skill?.id} className="skills__list__item">{skill?.name}</Tag>)}
</div>
<div className="wrap-btn-prise">
<a href="#" className="btn-apply">
Sign Up Now
</a>
<FilledYellowButton onClick={() => console.log('schedule')}>{i18nText('signUp', locale)}</FilledYellowButton>
<div className="wrap-btn-prise__text">
{`${sessionCost}`} <span>/ {`${sessionDuration}${isRus ? 'мин' : 'min'}`}</span>
</div>
@ -86,7 +93,7 @@ export const ExpertInformation: FC<ExpertDetailsProps> = ({ expert, locale }) =>
);
};
export const ExpertPractice: FC<ExpertDetailsProps> = ({ expert }) => {
export const ExpertPractice: FC<ExpertDetailsProps> = ({ expert, locale }) => {
const { publicCoachDetails: { practiceCases = [], themesGroups = [] } } = expert || {};
return practiceCases?.length > 0 ? (
@ -100,7 +107,7 @@ export const ExpertPractice: FC<ExpertDetailsProps> = ({ expert }) => {
{themesGroupIds && (
<div className="skills__list">
{filtered?.map(({ id, name }) => (
<div key={id} className="skills__list__item">{name}</div>
<Tag key={id} className="skills__list__item">{name}</Tag>
))}
</div>
)}

View File

@ -84,6 +84,7 @@ export const ExpertsList = ({
size="large"
className="search-result"
dataSource={experts.coaches}
locale={{ emptyText: i18nText('notFound', locale) }}
renderItem={(item) => (
<List.Item key={item?.id} className="card-profile">
<List.Item.Meta

View File

@ -179,7 +179,7 @@ export const ExpertsFilter = ({
return searchData?.themesGroups?.length ? searchData.themesGroups.map(({ id, name, tags }) => (
<div key={id}>
<h3 className="title-h5">{name}</h3>
<h3 className="title-h4">{name}</h3>
{getList('themesTagIds', tags)}
</div>
)) : null;
@ -214,7 +214,7 @@ export const ExpertsFilter = ({
key: 'themesTagIds',
label: (
<>
<div className="b-filter__collapsed__title">Direction</div>
<div className="b-filter__collapsed__title">{i18nText('direction', locale)}</div>
{!openedTabs.includes('themesTagIds') && filter?.themesTagIds?.length > 0 && (
<div className="b-filter__collapsed__desc">{getSelectedTags()}</div>
)}

View File

@ -83,7 +83,7 @@ export const AddCommentModal: FC<AddCommentModalProps> = ({
rules={[
{
required: true,
message: 'Please input your comment'
message: i18nText('errors.emptyComment', locale)
}
]}
>
@ -91,7 +91,7 @@ export const AddCommentModal: FC<AddCommentModalProps> = ({
className="b-textarea"
rows={4}
maxLength={1000}
placeholder="Your comment"
placeholder={i18nText('session.commentPlaceholder', locale)}
/>
</Form.Item>
</Form>
@ -101,7 +101,7 @@ export const AddCommentModal: FC<AddCommentModalProps> = ({
onClick={onAddComment}
loading={loading}
>
Send
{i18nText('send', locale)}
</Button>
</div>
</div>

View File

@ -6,6 +6,7 @@ import Link from 'next/link';
import { Modal, Form } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import { RegisterContent, ResetContent, FinishContent, EnterContent } from './authModalContent';
import { i18nText } from '../../i18nKeys';
type AuthModalProps = {
open: boolean;
@ -13,6 +14,7 @@ type AuthModalProps = {
mode: 'enter' | 'register' | 'reset' | 'finish';
updateMode: (mode: 'enter' | 'register' | 'reset' | 'finish') => void;
updateToken: string | Dispatch<SetStateAction<string | undefined>> | undefined;
locale: string;
};
export const AuthModal: FC<AuthModalProps> = ({
@ -20,7 +22,8 @@ export const AuthModal: FC<AuthModalProps> = ({
handleCancel,
mode,
updateMode,
updateToken
updateToken,
locale
}) => {
const [form] = Form.useForm<{ login: string, password: string, confirmPassword: string }>();
const paths = usePathname().split('/');
@ -50,7 +53,7 @@ export const AuthModal: FC<AuthModalProps> = ({
onCancel={handleCancel}
afterClose={onAfterClose}
footer={false}
width={498}
width={598}
closeIcon={<CloseOutlined style={{ fontSize: 20, color: '#000' }}/>}
>
<div className="b-modal__auth__content">
@ -82,8 +85,8 @@ export const AuthModal: FC<AuthModalProps> = ({
<FinishContent locale={paths[1]} />
)}
<div className="b-modal__auth__agreement">
I have read and agree with the terms of the
User Agreement, <Link href={'/docs/BBUDDY_privacy_policy_fin.docx' as any}>Privacy Policy</Link>
{`${i18nText('agreementText', locale)} `}
<Link href={'/docs/BBUDDY_privacy_policy_fin.docx' as any}>{i18nText('privacyPolicy', locale)}</Link>
</div>
</div>
</Modal>

View File

@ -7,7 +7,7 @@ import { SessionType } from '../../types/sessions';
import { AUTH_TOKEN_KEY } from '../../constants/common';
import { useLocalStorage } from '../../hooks/useLocalStorage';
import { cancelUpcomingSession, declineRequestedSession } from '../../actions/sessions';
// import { i18nText } from '../../i18nKeys';
import { i18nText } from '../../i18nKeys';
import { FilledButton } from '../view/FilledButton';
type DeclineModalProps = {
@ -79,7 +79,7 @@ export const DeclineSessionModal: FC<DeclineModalProps> = ({
<img className="" src="/images/decline-sign.svg" alt=""/>
</div>
<div className="b-modal__decline__title">
Enter a reason for cancelling the session
{i18nText('session.cancelReason', locale)}
</div>
<Form form={form} style={{ width: '100%' }}>
<Form.Item
@ -88,14 +88,14 @@ export const DeclineSessionModal: FC<DeclineModalProps> = ({
rules={[
{
required: true,
message: 'Please input the reason'
message: i18nText('errors.emptyCancelReason', locale)
}
]}
>
<Input.TextArea
className="b-textarea"
rows={1}
placeholder="Describe the reason for the rejection"
placeholder={i18nText('session.reasonPlaceholder', locale)}
/>
</Form.Item>
</Form>
@ -106,7 +106,7 @@ export const DeclineSessionModal: FC<DeclineModalProps> = ({
onClick={onDecline}
loading={loading}
>
Decline
{i18nText('decline', locale)}
</FilledButton>
</div>
</div>

View File

@ -37,10 +37,10 @@ export const EnterContent: FC<EnterProps> = ({
const { login, password } = form.getFieldsValue();
setIsLoading(true);
getAuth(locale, { login, password })
.then(({ data }) => {
.then((data) => {
if (data.jwtToken) {
getPersonalData(locale, data.jwtToken)
.then(({ data: profile }) => {
.then((profile) => {
localStorage.setItem(AUTH_USER, JSON.stringify(profile));
updateToken(data.jwtToken);
handleCancel();
@ -110,11 +110,11 @@ export const EnterContent: FC<EnterProps> = ({
rules={[
{
type: 'email',
message: 'The input is not valid E-mail'
message: i18nText('errors.validEmail', locale)
},
{
required: true,
message: 'Please input your E-mail'
message: i18nText('error.emptyEmail', locale)
}
]}
>
@ -129,7 +129,7 @@ export const EnterContent: FC<EnterProps> = ({
noStyle
rules={[{
required: true,
message: 'Please input your password'
message: i18nText('errors.emptyPass', locale)
}]}
>
<CustomInputPassword
@ -152,26 +152,26 @@ export const EnterContent: FC<EnterProps> = ({
type="link"
onClick={() => updateMode('reset')}
>
Forgot password?
{`${i18nText('forgotPass', locale)}?`}
</LinkButton>
<span>or</span>
<span>{i18nText('or', locale)}</span>
<OutlinedButton
icon={<Image src="/images/facebook-logo.png" height={20} width={20} alt="" />}
onClick={() => onSocialEnter(Social.FACEBOOK)}
>
Facebook account
{i18nText('facebook', locale)}
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/apple-logo.png" height={22} width={22} alt="" />}
onClick={() => onSocialEnter(Social.APPLE)}
>
Apple account
{i18nText('apple', locale)}
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/google-logo.png" height={20} width={20} alt="" />}
onClick={() => onSocialEnter(Social.GOOGLE)}
>
Google account
{i18nText('google', locale)}
</OutlinedButton>
</>
);

View File

@ -5,14 +5,10 @@ import { i18nText } from '../../../i18nKeys';
export const FinishContent = ({ locale }: { locale: string }) => (
<>
<div className="b-modal__auth__agreement">
A link to reset your password has been sent
<br />
to your email
{i18nText('resetPassText', locale)}
</div>
<FilledButton
type="primary"
>
{i18nText('enter', locale)}
<FilledButton type="primary">
{i18nText('enterAccount', locale)}
</FilledButton>
</>
);

View File

@ -36,10 +36,10 @@ export const RegisterContent: FC<RegisterProps> = ({
const { login, password } = form.getFieldsValue();
setIsLoading(true);
getRegister(locale)
.then(({ data }) => {
.then((data) => {
if (data.jwtToken) {
setPersonData( { login, password, role: 'client', languagesLinks: [] }, locale, data.jwtToken)
.then(({ data: profile }) => {
.then((profile) => {
updateToken(data.jwtToken);
localStorage.setItem(AUTH_USER, JSON.stringify(profile.userData));
handleCancel();
@ -115,11 +115,11 @@ export const RegisterContent: FC<RegisterProps> = ({
rules={[
{
type: 'email',
message: 'The input is not valid E-mail'
message: i18nText('errors.validEmail', locale)
},
{
required: true,
message: 'Please input your E-mail'
message: i18nText('error.emptyEmail', locale)
}
]}
>
@ -134,7 +134,7 @@ export const RegisterContent: FC<RegisterProps> = ({
noStyle
rules={[{
required: true,
message: 'Please input your password'
message: i18nText('errors.emptyPass', locale)
}]}
>
<CustomInputPassword
@ -150,14 +150,14 @@ export const RegisterContent: FC<RegisterProps> = ({
rules={[
{
required: true,
message: 'Please confirm your password',
message: i18nText('errors.confirmPass', locale),
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('The new password that you entered do not match'));
return Promise.reject(new Error(i18nText('errors.notMatchPass', locale)));
},
}),
]}
@ -176,24 +176,24 @@ export const RegisterContent: FC<RegisterProps> = ({
{i18nText('registration', locale)}
</FilledButton>
<OutlinedButton onClick={() => updateMode('enter')}>{i18nText('enter', locale)}</OutlinedButton>
<span>or</span>
<span>{i18nText('or', locale)}</span>
<OutlinedButton
icon={<Image src="/images/facebook-logo.png" height={20} width={20} alt="" />}
onClick={() => onSocialRegister(Social.FACEBOOK)}
>
Facebook account
{i18nText('facebook', locale)}
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/apple-logo.png" height={22} width={22} alt="" />}
onClick={() => onSocialRegister(Social.APPLE)}
>
Apple account
{i18nText('apple', locale)}
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/google-logo.png" height={20} width={20} alt="" />}
onClick={() => onSocialRegister(Social.GOOGLE)}
>
Google account
{i18nText('google', locale)}
</OutlinedButton>
</>
);

View File

@ -29,11 +29,11 @@ export const ResetContent: FC<ResetProps> = ({
rules={[
{
type: 'email',
message: 'The input is not valid E-mail'
message: i18nText('errors.validEmail', locale)
},
{
required: true,
message: 'Please input your E-mail'
message: i18nText('error.emptyEmail', locale)
}
]}
>
@ -48,7 +48,7 @@ export const ResetContent: FC<ResetProps> = ({
type="primary"
onClick={onResetPassword}
>
Reset Password
{i18nText('resetPass', locale)}
</FilledButton>
<LinkButton
type="link"

View File

@ -12,7 +12,7 @@ export const GeneralTopSection = ({
mainImage
}: GeneralTopSectionProps) => (
<div className="main-top">
<div className="b-inner">
<div className="b-inner b-main-desc">
<h1 className="title-h1">{title}</h1>
<div className="main-top__wrap-text">
{description && <p className="main-top__text">{description}</p>}

View File

@ -72,6 +72,7 @@ function HeaderAuthLinks ({
mode={mode}
updateMode={setMode}
updateToken={setToken}
locale={locale}
/>
</>
);

View File

@ -18,6 +18,7 @@ export const HeaderMenu = ({
}: HeaderMenuProps) => {
const selectedLayoutSegment = useSelectedLayoutSegment();
const pathname = selectedLayoutSegment || '';
const url = pathname === '(main)' ? '' : pathname;
return (
<div className="b-header__nav">
@ -25,7 +26,7 @@ export const HeaderMenu = ({
<ul className="b-header__nav__list">
{linkConfig.map(({ path, title }) => (
<li key={path}>
<Link href={`/${path}` as any} className={pathname === path ? 'active' : ''}>{title}</Link>
<Link href={`/${path}` as any} className={path === url ? 'active' : ''}>{title}</Link>
</li>
))}
<AuthLinks locale={locale} />

View File

@ -13,7 +13,7 @@ type HeaderProps = {
export const Header: FC<HeaderProps> = ({ locale }) => {
const routes: { path: string, title: string }[] = HEAD_ROUTES.map((item) => ({
path: item,
title: i18nText(`menu.${item}`, locale)
title: i18nText(item ? `menu.${item}` : 'menu.home', locale)
}));
return (

View File

@ -6,3 +6,9 @@ export const FilledButton = (props: any) => (
{props.children}
</Button>
);
export const FilledYellowButton = (props: any) => (
<Button className="b-button__filled_yellow" {...props}>
{props.children}
</Button>
);

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Button } from 'antd';
export const OutlinedButton = (props: any) => (
<Button className="b-button__outlined" {...props}>
<Button className={`b-button__outlined${props?.danger ? ' danger': ''}`} {...props}>
{props.children}
</Button>
);

View File

@ -1 +1,2 @@
export const HEAD_ROUTES = ['bb-client', 'bb-expert', 'blog'];
// export const HEAD_ROUTES = ['bb-client', 'bb-expert', 'blog'];
export const HEAD_ROUTES = ['', 'blog'];

View File

@ -11,12 +11,16 @@ export default {
menu: {
'bb-client': 'Mit BB wachsen',
'bb-expert': 'Werde BB-Experte',
home: 'Startseite',
blog: 'Blog&News'
},
registration: 'Registrieren',
enter: 'Anmelden',
enterAccount: 'Konto anmelden',
account: 'Mein Konto',
logout: 'Abmelden',
decline: 'Ablehnen',
send: 'Senden',
deleteAcc: 'Konto löschen',
footer: {
faq: 'FAQ',
@ -25,8 +29,29 @@ export default {
session: {
upcoming: 'Kommende Sitzungen',
requested: 'Angefragte Sitzungen',
recent: 'Letzte Sitzungen'
recent: 'Letzte Sitzungen',
cancelReason: 'Gib einen Grund für die Absage der Sitzung ein',
reasonPlaceholder: 'Beschreibe den Grund für die Ablehnung',
decline: 'Sitzung ablehnen',
confirm: 'Sitzung bestätigen',
join: 'Sitzung beitreten',
start: 'Sitzung starten',
finish: 'Sitzung abschließen',
comments: 'Kommentare',
myComments: 'Meine Kommentare',
addComment: 'Neuen Kommentar hinzufügen',
commentPlaceholder: 'Ihr Kommentar',
},
room: {
upcoming: 'Zukünftige Räume',
requested: 'Angeforderte Räume',
recent: 'Kürzliche Räume',
newRoom: 'Neuer Raum'
},
agreementText: 'Folgendes habe ich gelesen und erkläre mich damit einverstanden: Benutzervereinbarung,',
userAgreement: 'Benutzervereinbarung',
privacyPolicy: 'Datenschutzrichtlinie',
readMore: 'Mehr erfahren',
photoDesc: 'Füge ein echtes Foto hinzu, mit Gesicht wirkt es immer glaubwürdiger.',
dayStart: 'Tagesbeginn',
topic: 'Thema',
@ -37,6 +62,12 @@ export default {
oldPass: 'Altes Passwort',
newPass: 'Neues Passwort',
confirmPass: 'Passwort bestätigen',
forgotPass: 'Passwort vergessen',
resetPassText: 'Ein Link zum Zurücksetzen Ihres Passworts wurde an Ihre E-Mail gesendet',
or: 'oder',
facebook: 'Facebook-Konto',
apple: 'Apple-Konto',
google: 'Google-Konto',
becomeExpert: '',
insertInfo: 'Füge deine persönlichen Informationen ein, um deine Reise als BBuddy-Experte zu beginnen',
changeUserData: 'Du kannst deine Angaben jederzeit ergänzen oder ändern\n',
@ -49,11 +80,36 @@ export default {
sortPriceDesc: 'Nach Preis absteigend',
details: 'Details',
sessionLang: 'Sitzungssprache',
direction: 'Wegbeschreibung',
fromTo: 'von $ bis $',
apply: 'Anwenden',
save: 'Speichern',
changePass: 'Passwort ändern',
resetPass: 'Passwort zurücksetzen',
getStarted: 'Loslegen',
delete: 'Löschen',
today: 'Heute'
today: 'Heute',
back: 'Zurück',
backToExperts: 'Zurück zur Expertenliste',
courseInfo: 'Kursinfo',
expertBackground: 'Expertenhintergrund',
profCertification: 'Professionelle Zertifizierung',
practiceHours: 'Praxisstunden',
supervisionCount: 'Supervision pro Jahr',
outOf: 'von',
schedule: 'Zeitplan',
signUp: 'Jetzt anmelden',
noData: 'Keine Daten',
notFound: 'Nicht gefunden',
errors: {
invalidEmail: 'Die E-Mail-Adresse ist ungültig',
emptyEmail: 'Bitte geben Sie Ihre E-Mail ein',
emptyPass: 'Bitte geben Sie Ihr Passwort ein',
confirmPass: 'Bitte bestätigen Sie Ihr Passwort',
notMatchPass: 'Die neuen Passwörter stimmen nicht überein',
emptyCancelReason: 'Bitte gib den Grund ein',
approvingSession: 'Fehler beim Genehmigen der Sitzung',
finishingSession: 'Fehler beim Beenden der Sitzung',
emptyComment: 'Bitte geben Sie Ihren Kommentar ein',
},
}

View File

@ -11,12 +11,16 @@ export default {
menu: {
'bb-client': 'Start grow with BB',
'bb-expert': 'Become BB Expert',
home: 'Home',
blog: 'Blog&News'
},
registration: 'Registration',
enter: 'Enter',
enterAccount: 'Enter account',
account: 'My Account',
logout: 'Log out',
decline: 'Decline',
send: 'Send',
deleteAcc: 'Delete account',
footer: {
faq: 'FAQ',
@ -25,8 +29,29 @@ export default {
session: {
upcoming: 'Upcoming Sessions',
requested: 'Sessions Requested',
recent: 'Recent Sessions'
recent: 'Recent Sessions',
cancelReason: 'Enter a reason for cancelling the session',
reasonPlaceholder: 'Describe the reason for the rejection',
decline: 'Decline session',
confirm: 'Confirm session',
join: 'Join session',
start: 'Start session',
finish: 'Finish session',
comments: 'Comments',
myComments: 'My comments',
addComment: 'Add new',
commentPlaceholder: 'Your comment',
},
room: {
upcoming: 'Upcoming Rooms',
requested: 'Rooms Requested',
recent: 'Recent Rooms',
newRoom: 'New Room'
},
agreementText: 'I have read and agree with the terms of the User Agreement,',
userAgreement: 'User Agreement',
privacyPolicy: 'Privacy Policy',
readMore: 'Read more',
photoDesc: 'Add a real photo, as a person\'s face is always more credible.',
dayStart: 'Day start',
topic: 'Topic',
@ -37,6 +62,12 @@ export default {
oldPass: 'Old Password',
newPass: 'New Password',
confirmPass: 'Confirm Password',
forgotPass: 'Forgot password',
resetPassText: 'A link to reset your password has been sent to your email',
or: 'or',
facebook: 'Facebook account',
apple: 'Apple account',
google: 'Google account',
becomeExpert: '',
insertInfo: 'Insert your personal information to start your journey as a BBuddy Expert',
changeUserData: 'Your info can either be added or amended at anytime',
@ -49,11 +80,36 @@ export default {
sortPriceDesc: 'By price descending',
details: 'Details',
sessionLang: 'Session Language',
direction: 'Direction',
fromTo: 'from $ to $',
apply: 'Apply',
save: 'Save',
changePass: 'Change password',
resetPass: 'Reset password',
getStarted: 'Get started',
delete: 'Delete',
today: 'Today'
today: 'Today',
back: 'Back',
backToExperts: 'Back to experts list',
courseInfo: 'Course Info',
expertBackground: 'Expert Background',
profCertification: 'Professional Certification',
practiceHours: 'Practice hours',
supervisionCount: 'Supervision per year',
outOf: 'out of',
schedule: 'Schedule',
signUp: 'Sign up now',
noData: 'No data',
notFound: 'Not found',
errors: {
invalidEmail: 'The email address is not valid',
emptyEmail: 'Please enter your E-mail',
emptyPass: 'Please enter your password',
confirmPass: 'Please confirm your password',
notMatchPass: 'The new passwords you entered do not match',
emptyCancelReason: 'Please enter the reason',
approvingSession: 'Error approving session',
finishingSession: 'Error finishing session',
emptyComment: 'Please enter your comment',
},
}

View File

@ -11,12 +11,16 @@ export default {
menu: {
'bb-client': 'Empieza a crecer con BB',
'bb-expert': 'Conviértete en un experto en BB',
home: 'Inicio',
blog: 'Blog y noticias'
},
registration: 'Registro',
enter: 'Entrar',
enterAccount: 'Introducir cuenta',
account: 'Mi cuenta',
logout: 'Cerrar sesión',
decline: 'Rechazar',
send: 'Enviar',
deleteAcc: 'Eliminar cuenta',
footer: {
faq: 'Preguntas frecuentes',
@ -25,8 +29,29 @@ export default {
session: {
upcoming: 'Próximas sesiones',
requested: 'Sesiones solicitadas',
recent: 'Sesiones recientes'
recent: 'Sesiones recientes',
cancelReason: 'Introduce el motivo por el que has cancelado la sesión',
reasonPlaceholder: 'Describe el motivo del rechazo',
decline: 'Rechazar sesión',
confirm: 'Confirmar sesión',
join: 'Unirse a la sesión',
start: 'Iniciar sesión',
finish: 'Finalizar la sesión',
comments: 'Comentarios',
myComments: 'Mis comentarios',
addComment: 'Añadir nuevo comentario',
commentPlaceholder: 'Tu comentario',
},
room: {
upcoming: 'Próximas salas',
requested: 'Salas solicitadas',
recent: 'Salas recientes',
newRoom: 'Nueva sala'
},
agreementText: 'He leído y acepto las condiciones del Acuerdo de usuario,',
userAgreement: 'Acuerdo de usuario',
privacyPolicy: 'Política de privacidad',
readMore: 'Seguir leyendo',
photoDesc: 'Añade una foto real, ya que la cara de una persona siempre es más creíble.',
dayStart: 'Inicio del día',
topic: 'Tema',
@ -37,6 +62,12 @@ export default {
oldPass: 'Contraseña antigua',
newPass: 'Nueva contraseña',
confirmPass: 'Confirmar contraseña',
forgotPass: 'Se te ha olvidado la contraseña',
resetPassText: 'Se ha enviado un enlace para restablecer la contraseña a tu correo electrónico',
or: 'o',
facebook: 'Cuenta de Facebook',
apple: 'Cuenta de Apple',
google: 'Cuenta de Google',
becomeExpert: '',
insertInfo: 'Introduce tu información personal para comenzar tu viaje como experto en BBuddy',
changeUserData: 'Tus datos pueden añadirse o modificarse en cualquier momento',
@ -49,11 +80,36 @@ export default {
sortPriceDesc: 'Por precio descendiente',
details: 'Detalles',
sessionLang: 'Idioma de la sesión',
direction: 'Dirección',
fromTo: 'de $ a $',
apply: 'Solicitar',
save: 'Guardar',
changePass: 'Cambiar contraseña',
resetPass: 'Restablecer contraseña',
getStarted: 'Empieza',
delete: 'Eliminar',
today: 'Hoy día'
today: 'Hoy',
back: 'Volver',
backToExperts: 'Volver a la lista de expertos',
courseInfo: 'Información del curso',
expertBackground: 'Antecedentes del experto',
profCertification: 'Certificación profesional',
practiceHours: 'horas de práctica',
supervisionCount: 'supervisiones anuales',
outOf: 'de',
schedule: 'Horario',
signUp: 'Regístrate ahora',
noData: 'Sin datos',
notFound: 'No encontrado',
errors: {
invalidEmail: 'La dirección de correo electrónico no es válida',
emptyEmail: 'Introduce tu correo electrónico',
emptyPass: 'Introduce tu contraseña',
confirmPass: 'Confirma tu contraseña',
notMatchPass: 'Las nuevas contraseñas que has introducido no coinciden',
emptyCancelReason: 'Introduce el motivo',
approvingSession: 'Error al aprobar la sesión',
finishingSession: 'Error al finalizar la sesión',
emptyComment: 'Introduce tu comentario',
},
}

View File

@ -11,12 +11,16 @@ export default {
menu: {
'bb-client': 'Commencez à vous développer avec BB',
'bb-expert': 'Devenez Expert BB',
home: 'Accueil',
blog: 'Blog et actus'
},
registration: 'Inscription',
enter: 'Saisir',
enterAccount: 'Saisir le compte',
account: 'Mon compte',
logout: 'Déconnexion',
decline: 'Refuser',
send: 'Envoyer',
deleteAcc: 'Supprimer le compte',
footer: {
faq: 'FAQ',
@ -25,8 +29,29 @@ export default {
session: {
upcoming: 'Prochaines sessions',
requested: 'Sessions demandées',
recent: 'Sessions récentes'
recent: 'Sessions récentes',
cancelReason: 'Saisissez une raison pour l\'annulation de la session',
reasonPlaceholder: 'Décrivez la raison du refus',
decline: 'Refuser la session',
confirm: 'Confirmer la session',
join: 'Rejoindre la session',
start: 'Commencer la session',
finish: 'Terminer la session',
comments: 'Commentaires',
myComments: 'Mes commentaires',
addComment: 'Ajouter un nouveau commentaire',
commentPlaceholder: 'Votre commentaire',
},
room: {
upcoming: 'Salles futures',
requested: 'Salles demandées',
recent: 'Salles récentes',
newRoom: 'Nouvelle salle'
},
agreementText: 'J\'ai lu et j\'accepte les dispositions de l\'Accord Utilisateur et de la',
userAgreement: '',
privacyPolicy: 'Politique de Confidentialité',
readMore: 'En savoir plus',
photoDesc: 'Ajoutez une photo réelle, le visage d\'une personne est toujours plus crédible.',
dayStart: 'Début de la journée',
topic: 'Sujet',
@ -37,6 +62,12 @@ export default {
oldPass: 'Ancien mot de passe',
newPass: 'Nouveau mot de passe',
confirmPass: 'Confirmer le mot de passe',
forgotPass: 'Mot de passe oublié',
resetPassText: 'Un lien pour réinitialiser votre mot de passe a été envoyé à votre adresse e-mail',
or: 'ou',
facebook: 'Compte Facebook',
apple: 'Compte Apple',
google: 'Compte Google',
becomeExpert: '',
insertInfo: 'Insérez vos informations personnelles pour commencer votre voyage en tant qu\'expert BBuddy',
changeUserData: 'Vos informations peuvent être ajoutées ou modifiées à tout moment',
@ -49,11 +80,36 @@ export default {
sortPriceDesc: 'Par prix décroissant',
details: 'Détails',
sessionLang: 'Langue de la session',
direction: 'Direction',
fromTo: 'de $ à $',
apply: 'Appliquer',
save: 'Sauvegarder',
changePass: 'Modifier le mot de passe',
resetPass: 'Réinitialiser le mot de passe',
getStarted: 'Commencer',
delete: 'Supprimer',
today: 'Ce jour'
today: 'Aujourd\'hui',
back: 'Retour',
backToExperts: 'Retour à la liste d\'experts',
courseInfo: 'Infos sur le cours',
expertBackground: 'Antécédents de l\'expert',
profCertification: 'Certification professionnelle',
practiceHours: 'heures de pratique',
supervisionCount: 'Supervision par an',
outOf: 'sur',
schedule: 'Programme',
signUp: 'Inscrivez-vous maintenant',
noData: 'Aucune donnée',
notFound: 'Non trouvé',
errors: {
invalidEmail: 'L\'adresse e-mail n\'est pas valide',
emptyEmail: 'Veuillez saisir votre e-mail',
emptyPass: 'Veuillez saisir votre mot de passe',
confirmPass: 'Veuillez confirmer votre mot de passe',
notMatchPass: 'Les nouveaux mots de passe que vous avez saisis ne sont pas identiques',
emptyCancelReason: 'Veuillez saisir la raison',
approvingSession: 'Erreur lors de l\'approbation de la session',
finishingSession: 'Erreur lors de la fin de la session',
emptyComment: 'Veuillez saisir votre commentaire',
},
}

View File

@ -11,12 +11,16 @@ export default {
menu: {
'bb-client': 'Inizia a crescere con BB',
'bb-expert': 'Diventa esperto BB',
home: 'Home',
blog: 'Blog&Notizie'
},
registration: 'Registrazione',
enter: 'Inserisci',
enterAccount: 'Inserisci account',
account: 'Il mio account',
logout: 'Disconnetti',
decline: 'Rifiuta',
send: 'Invia',
deleteAcc: 'Elimina account',
footer: {
faq: 'Domande frequenti',
@ -25,8 +29,29 @@ export default {
session: {
upcoming: 'Prossime sessioni',
requested: 'Sessioni richieste',
recent: 'Sessioni recenti'
recent: 'Sessioni recenti',
cancelReason: 'Inserisci un motivo per l\'annullamento della sessione',
reasonPlaceholder: 'Descrivi il motivo del rifiuto',
decline: 'Rifiuta sessione',
confirm: 'Conferma sessione',
join: 'Partecipa alla sessione',
start: 'Avvia sessione',
finish: 'Termina sessione',
comments: 'Commenti',
myComments: 'I miei commenti',
addComment: 'Aggiungi nuovo commento',
commentPlaceholder: 'Il tuo commento',
},
room: {
upcoming: 'Prossime sale',
requested: 'Sale richieste',
recent: 'Sale recenti',
newRoom: 'Nuova sala'
},
agreementText: 'Ho letto e accetto i termini dell\'Accordo con l\'utente,',
userAgreement: '',
privacyPolicy: 'Informativa sulla privacy',
readMore: 'Leggi di più',
photoDesc: 'Aggiungi una foto vera: il volto di una persona è sempre più credibile.',
dayStart: 'Inizio del giorno',
topic: 'Argomento',
@ -37,6 +62,12 @@ export default {
oldPass: 'Vecchia password',
newPass: 'Nuova password',
confirmPass: 'Conferma password',
forgotPass: 'Hai dimenticato la password',
resetPassText: 'Un link per reimpostare la password è stato inviato al tuo indirizzo e-mail',
or: 'o',
facebook: 'Account Facebook',
apple: 'Account Apple',
google: 'Account Google',
becomeExpert: '',
insertInfo: 'Inserisci i tuoi dati personali per iniziare il tuo viaggio come esperto BBuddy',
changeUserData: 'I tuoi dati possono essere aggiunti o modificati in qualsiasi momento',
@ -49,11 +80,36 @@ export default {
sortPriceDesc: 'Per prezzo decrescente',
details: 'Dettagli',
sessionLang: 'Lingua sessione',
direction: 'Direzione',
fromTo: 'da $ a $',
apply: 'Applica',
save: 'Salva',
changePass: 'Cambia password',
resetPass: 'Reimposta password',
getStarted: 'Inizia',
delete: 'Elimina',
today: 'Oggi'
today: 'Oggi',
back: 'Indietro',
backToExperts: 'Torna all\'elenco degli esperti',
courseInfo: 'Informazioni sul corso',
expertBackground: 'Background esperto',
profCertification: 'Certificazione professionale',
practiceHours: 'ore di pratica',
supervisionCount: 'supervisioni per anno',
outOf: 'su',
schedule: 'Programma',
signUp: 'Iscriviti ora',
noData: 'Nessun dato',
notFound: 'Non trovato',
errors: {
invalidEmail: 'L\'indirizzo e-mail non è valido',
emptyEmail: 'Inserisci l\'e-mail',
emptyPass: 'Inserisci la password',
confirmPass: 'Conferma la password',
notMatchPass: 'Le nuove password inserite non corrispondono',
emptyCancelReason: 'Inserisci il motivo',
approvingSession: 'Errore nell\'approvazione della sessione',
finishingSession: 'Errore durante la chiusura della sessione',
emptyComment: 'Inserisci il tuo commento',
},
}

View File

@ -11,12 +11,16 @@ export default {
menu: {
'bb-client': 'Начните свой рост с BB',
'bb-expert': 'Станьте экспертом BB',
home: 'Главная',
blog: 'Блог и новости'
},
registration: 'Регистрация',
enter: 'Войти',
enterAccount: 'Войти в аккаунт',
account: 'Учетная запись',
logout: 'Выйти',
decline: 'Отклонить',
send: 'Отправить',
deleteAcc: 'Удалить учетную запись',
footer: {
faq: 'Частые вопросы',
@ -25,8 +29,29 @@ export default {
session: {
upcoming: 'Предстоящие сессии',
requested: 'Запрошенные сессии',
recent: 'Недавние сессии'
recent: 'Недавние сессии',
cancelReason: 'Введите причину отмены сессии',
reasonPlaceholder: 'Опишите причину отказа',
decline: 'Отклонить сессию',
confirm: 'Подтвердить сессию',
join: 'Присоединиться к сессии',
start: 'Начать сессию',
finish: 'Завершить сессию',
comments: 'Комментарии',
myComments: 'Мои комментарии',
addComment: 'Добавить новый',
commentPlaceholder: 'Ваш комментарий',
},
room: {
upcoming: 'Предстоящие комнаты',
requested: 'Запрошенные комнаты',
recent: 'Недавние комнаты',
newRoom: 'Новая комната'
},
agreementText: 'Я прочитал и согласен с условиями Пользовательского соглашения,',
userAgreement: 'Пользовательского соглашения',
privacyPolicy: 'Политикой конфиденциальности',
readMore: 'Читать дальше',
photoDesc: 'Добавьте реальную фотографию, ведь лицо человека всегда вызывает больше доверия.',
dayStart: 'День начала',
topic: 'Тема',
@ -37,6 +62,12 @@ export default {
oldPass: 'Старый пароль',
newPass: 'Новый пароль',
confirmPass: 'Подтвердите пароль',
forgotPass: 'Забыли пароль',
resetPassText: 'Ссылка для сброса пароля была отправлена на ваш E-mail',
or: 'или',
facebook: 'Аккаунт Facebook',
apple: 'Аккаунт Apple',
google: 'Аккаунт Google',
becomeExpert: '',
insertInfo: 'Введите личные данные и начните свой путь эксперта BBuddy',
changeUserData: 'Добавить и изменить информацию о себе можно в любое время',
@ -49,11 +80,36 @@ export default {
sortPriceDesc: 'Цена по убыванию',
details: 'Информация',
sessionLang: 'Язык сессии',
direction: 'Направление',
fromTo: 'от $ до $',
apply: 'Применить',
save: 'Сохранить',
changePass: 'Изменить пароль',
resetPass: 'Сбросить пароль',
getStarted: 'Начать работу',
delete: 'Удалить',
today: 'Сегодня'
today: 'Сегодня',
back: 'Назад',
backToExperts: 'Вернуться к списку экспертов',
courseInfo: 'Информация о курсе',
expertBackground: 'Профессиональный опыт эксперта',
profCertification: 'Профессиональная сертификация',
practiceHours: 'часов практики',
supervisionCount: 'часов супервизии в год',
outOf: 'из',
schedule: 'Расписание',
signUp: 'Записаться сейчас',
noData: 'Нет данных',
notFound: 'Не найдено',
errors: {
invalidEmail: 'Адрес электронной почты недействителен',
emptyEmail: 'Пожалуйста, введите ваш E-mail',
emptyPass: 'Пожалуйста, введите ваш пароль',
confirmPass: 'Пожалуйста, подтвердите ваш пароль',
notMatchPass: 'Введенные новые пароли не совпадают',
emptyCancelReason: 'Пожалуйста, введите причину',
approvingSession: 'Ошибка при подтверждении сессии',
finishingSession: 'Ошибка при завершении сессии',
emptyComment: 'Пожалуйста, введите ваш комментарий',
},
}

View File

@ -70,11 +70,11 @@ a {
line-height: normal;
@media (min-width: 576px) {
@include rem(30);
@include rem(28);
}
@media (min-width: 768px) {
@include rem(42);
@include rem(40);
}
}
@ -309,6 +309,14 @@ a {
margin-bottom: 10px;
}
.title-h4 {
color: #003B46;
font-size: 1rem;
line-height: 1.5rem;
font-weight: bold;
margin-bottom: 10px;
}
.title-h3 {
color: #003B46;
font-size: 18px;
@ -561,6 +569,10 @@ a {
font-style: normal;
font-weight: 400;
line-height: 160%;
&__auto {
width: auto;
}
}
.btn-video {
@ -762,6 +774,8 @@ a {
padding: 16px;
flex-flow: wrap;
display: flex;
margin-bottom: 42px;
top: 24px;
&__avatar {
width: 80px;
@ -815,8 +829,8 @@ a {
color: $white;
@include rem(13);
font-style: normal;
font-weight: 500;
line-height: 123.077%;
font-weight: 300;
line-height: 120%;
display: flex;
flex-flow: column;
gap: 8px;
@ -831,6 +845,7 @@ a {
display: flex;
gap: 8px;
flex-flow: wrap;
align-items: center;
& > span {
display: block;
@ -853,7 +868,7 @@ a {
}
@media (min-width: 992px) {
padding: 38px 24px 38px 24px;
padding: 24px;
flex-flow: nowrap;
justify-content: space-between;
@ -861,7 +876,7 @@ a {
width: 220px;
height: 220px;
position: absolute;
top: 24px;
top: -18px;
left: 24px;
}
@ -903,7 +918,7 @@ a {
}
&__info {
@include rem(18);
@include rem(15);
flex-flow: nowrap;
gap: 16px;
i {
@ -922,6 +937,17 @@ a {
}
}
.expert-info {
display: flex;
gap: 16px;
align-items: center;
padding-top: 24px;
.skills__list {
align-self: initial;
}
}
.base-text {
color: #66A5AD;
@include rem(13);
@ -964,7 +990,7 @@ a {
flex-flow: wrap;
.breadcrumb-item {
color: #6FB98F;
color: #003B46;
@include rem(18);
font-style: normal;
font-weight: 500;
@ -985,14 +1011,6 @@ a {
}
}
}
@media (min-width: 768px) {
margin-bottom: 24px;
.breadcrumb-item {
@include rem(24);
}
}
}

View File

@ -57,6 +57,21 @@
}
}
.form-fieldset {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
.ant-form-item {
margin: 0 !important;
}
}
.form-actions {
display: flex;
gap: 16px;
}
input {
&.base-input {
height: 54px;

View File

@ -6,6 +6,14 @@
max-height: 570px;
position: relative;
.b-main-desc {
min-height: 440px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
}
@media (min-width: 576px) {
max-height: 600px;
}
@ -110,16 +118,12 @@
text-align: center;
margin-bottom: 16px;
padding-top: 8px;
@media (min-width: 768px) {
padding-top: 24px;
}
position: relative;
z-index: 1;
@media (min-width: 992px) {
max-width: 690px;
text-align: left;
padding-top: 70px;
margin-bottom: 24px;
}
}
@ -148,11 +152,11 @@
line-height: 133.333%;
@media (min-width: 576px) {
@include rem(16);
@include rem(15);
}
@media (min-width: 768px) {
@include rem(24);
@include rem(18);
}
@media (max-width: 1249px) {
@ -166,13 +170,14 @@
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 24px;
justify-content: center;
position: relative;
margin: auto;
@media (min-width: 992px) {
gap: 24px;
justify-content: flex-start;
margin: 0;
}
@media (min-width: 1200px) {
@ -321,16 +326,17 @@
.main-articles {
position: relative;
background: #DFF5FB;
padding-bottom: 4px;
padding-bottom: 10px;
margin-bottom: 94px;
&:before {
content: "";
position: absolute;
background-image: url(/images/wave-top.svg);
background-position: center;
height: 86px;
height: 80px;
width: 100%;
top: -86px;
top: -80px;
overflow: hidden;
background-size: 893px 87px;

View File

@ -7,12 +7,8 @@
margin-bottom: 16px;
}
.expert-card {
}
.title-h2 {
margin-bottom: 16px;
padding-top: 16px;
}
.title-h3 {
@ -29,6 +25,9 @@
flex-flow: column;
gap: 8px;
align-items: center;
padding-bottom: 16px;
border-bottom: 1px solid #C4DFE6;
margin-bottom: 24px;
&__text {
color: #6FB98F;
@ -80,14 +79,6 @@
margin-bottom: 24px;
}
.title-h2 {
padding-top: 24px;
}
.expert-card {
margin-bottom: 32px;
}
.offers-list {
margin-bottom: 72px;
}
@ -95,7 +86,6 @@
}
.b-news {
&__header {
position: relative;
padding-top: 24px;
@ -749,6 +739,11 @@
&__item {
border-bottom: 1px solid #C4DFE6;
width: 100%;
padding: 8px 0;
&:first-child {
padding: 0 0 8px;
}
&:last-child {
border-bottom: none;
@ -783,13 +778,11 @@
display: flex;
align-items: center;
justify-content: space-between;
height: 49px;
gap: 8px;
color: #003B46 !important;
@include rem(18);
@include rem(15);
font-style: normal;
font-weight: 600;
line-height: 133.333%;
line-height: 160%;
text-decoration: none;
padding-right: 32px;
position: relative;
@ -809,7 +802,7 @@
&.active {
color: #66A5AD !important;
color: #003B46 !important;
padding-right: 0;
&:before {
@ -831,16 +824,16 @@
&__item {
cursor: pointer;
height: 48px;
padding-bottom: 16px;
height: 40px;
padding: 8px 0;
position: relative;
display: flex;
gap: 10px;
justify-content: center;
color: #66A5AD;
@include rem(24);
@include rem(18);
font-style: normal;
font-weight: 300;
font-weight: 500;
line-height: 133.333%;
align-items: center;
width: calc(33.33333333% - 8px);
@ -865,12 +858,12 @@
position: absolute;
bottom: 0;
width: 100%;
height: 8px;
height: 4px;
border-radius: 8px;
}
&.active {
color: #6FB98F;
color: #2C7873;
&:before{
background: #2C7873;
}
@ -1113,6 +1106,31 @@
}
}
.b-work {
display: flex;
gap: 16px;
align-items: center;
&__text {
color: #2C7873;
@include rem(16);
font-style: normal;
font-weight: 600;
line-height: 100%;
}
&__description {
display: flex;
flex-direction: column;
gap: 16px;
align-items: flex-start;
}
.btn-apply {
width: auto;
}
}
.image-info {
display: flex;
justify-content: center;

View File

@ -6,6 +6,17 @@
height: 54px !important;
box-shadow: 0px 2px 4px 0px rgba(102, 165, 173, 0.32) !important;
&_yellow {
background: #FFBD00 !important;
border-color: #FFBD00 !important;
color: #003B46 !important;
font-size: 15px !important;
border-radius: 8px !important;
height: 54px !important;
box-shadow: none !important;
padding: 4px 24px !important;
}
&.danger {
background: #D93E5C !important;
box-shadow: none !important;
@ -30,6 +41,11 @@
border-radius: 8px !important;
height: 54px !important;
&.danger {
border-color: #D93E5C !important;
color: #D93E5C !important;
}
span {
margin-inline-end: 0 !important;
line-height: 15px !important;
@ -38,12 +54,12 @@
&__logout {
width: 100%;
height: 49px !important;
height: 24px !important;
color: #D93E5C !important;
font-style: normal;
font-weight: 600 !important;
padding: 0 !important;
font-size: 1.125rem !important;
font-size: 15px !important;
justify-content: flex-start !important;
}
}

View File

@ -32,7 +32,8 @@
&:focus, &:hover {
&::after {
box-shadow: 0 0 0 12px rgba(102, 165, 173, .2) !important;
outline: none !important;
box-shadow: 0 0 0 8px rgba(102, 165, 173, .2) !important;
}
}
}