feat: add experts profile
This commit is contained in:
parent
abf04b4c5b
commit
ff74e5ba49
|
@ -79,7 +79,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Experts": {
|
"Experts": {
|
||||||
"title": "Find an expert",
|
"title": "Einen Experten finden",
|
||||||
"filter": {
|
"filter": {
|
||||||
"price": "Price from {from}€ to {to}€",
|
"price": "Price from {from}€ to {to}€",
|
||||||
"duration": "Duration from {from}min to {to}min",
|
"duration": "Duration from {from}min to {to}min",
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Experts": {
|
"Experts": {
|
||||||
"title": "Find an expert",
|
"title": "Encontrar un experto",
|
||||||
"filter": {
|
"filter": {
|
||||||
"price": "Price from {from}€ to {to}€",
|
"price": "Price from {from}€ to {to}€",
|
||||||
"duration": "Duration from {from}min to {to}min",
|
"duration": "Duration from {from}min to {to}min",
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Experts": {
|
"Experts": {
|
||||||
"title": "Find an expert",
|
"title": "Trouver un expert",
|
||||||
"filter": {
|
"filter": {
|
||||||
"price": "Price from {from}€ to {to}€",
|
"price": "Price from {from}€ to {to}€",
|
||||||
"duration": "Duration from {from}min to {to}min",
|
"duration": "Duration from {from}min to {to}min",
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Experts": {
|
"Experts": {
|
||||||
"title": "Find an expert",
|
"title": "Trova un esperto",
|
||||||
"filter": {
|
"filter": {
|
||||||
"price": "Price from {from}€ to {to}€",
|
"price": "Price from {from}€ to {to}€",
|
||||||
"duration": "Duration from {from}min to {to}min",
|
"duration": "Duration from {from}min to {to}min",
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import { apiClient } from '../lib/apiClient';
|
import { apiClient } from '../lib/apiClient';
|
||||||
|
|
||||||
type RequiredConfigParams<D = any> = Required<Pick<AxiosRequestConfig, 'url' | 'method'>> & Pick<AxiosRequestConfig<D>, 'data'>;
|
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 type PageRequestConfig<D = any> = RequiredConfigParams<D> & Partial<Pick<AxiosRequestConfig, 'headers'>> & { locale?: string, token?: string };
|
||||||
|
|
||||||
export const apiRequest = async <T = any, K = any>(
|
export const apiRequest = async <T = any, K = any>(
|
||||||
baseParams: PageRequestConfig<T>,
|
baseParams: PageRequestConfig<T>,
|
||||||
|
@ -15,29 +15,30 @@ export const apiRequest = async <T = any, K = any>(
|
||||||
headers: {
|
headers: {
|
||||||
'X-User-Language': baseParams?.locale || 'en',
|
'X-User-Language': baseParams?.locale || 'en',
|
||||||
'X-Referrer-Channel': 'site',
|
'X-Referrer-Channel': 'site',
|
||||||
...(baseParams?.token ? { Authorization: `Bearer ${baseParams.token}` } : {})
|
...(baseParams?.token ? { Authorization: `Bearer ${baseParams.token}` } : {}),
|
||||||
|
...(baseParams.headers || {})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const response: AxiosResponse<K> = await apiClient.request<any, AxiosResponse<K>, T>(config as AxiosRequestConfig<T>);
|
const response: AxiosResponse<K> = await apiClient.request<any, AxiosResponse<K>, T>(config as AxiosRequestConfig<T>);
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const {
|
// const {
|
||||||
response: {
|
// response: {
|
||||||
status: responseCode = null,
|
// status: responseCode = null,
|
||||||
statusText = '',
|
// statusText = '',
|
||||||
data: { message = '', status: errorKey = '' } = {},
|
// data: { message = '', status: errorKey = '' } = {},
|
||||||
} = {},
|
// } = {},
|
||||||
code: statusCode = '',
|
// code: statusCode = '',
|
||||||
} = err as AxiosError;
|
// } = err as AxiosError;
|
||||||
|
//
|
||||||
throw new Error(
|
// throw new Error(
|
||||||
JSON.stringify({
|
// JSON.stringify({
|
||||||
statusCode,
|
// statusCode,
|
||||||
statusMessage: message || statusText,
|
// statusMessage: message || statusText,
|
||||||
responseCode,
|
// responseCode,
|
||||||
errorKey,
|
// errorKey,
|
||||||
}),
|
// }),
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { Profile } from '../../types/profile';
|
import { ProfileData, ProfileRequest } from '../../types/profile';
|
||||||
import { getPersonalData } from '../profile';
|
import { getPersonalData, setPersonData } from '../profile';
|
||||||
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
||||||
import { AUTH_TOKEN_KEY } from '../../constants/common';
|
import { AUTH_TOKEN_KEY } from '../../constants/common';
|
||||||
|
|
||||||
export const useProfileSettings = (locale: string) => {
|
export const useProfileSettings = (locale: string) => {
|
||||||
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
||||||
const [profileSettings, setProfileSettings] = useState<Profile | undefined>();
|
const [profileSettings, setProfileSettings] = useState<ProfileData | undefined>();
|
||||||
const [fetchLoading, setFetchLoading] = useState<boolean>(false);
|
const [fetchLoading, setFetchLoading] = useState<boolean>(false);
|
||||||
const [saveLoading, setSaveLoading] = useState<boolean>(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const fetchProfileSettings = () => {
|
||||||
if (jwt) {
|
if (jwt) {
|
||||||
getPersonalData(locale, jwt)
|
getPersonalData(locale, jwt)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
@ -25,16 +24,14 @@ export const useProfileSettings = (locale: string) => {
|
||||||
setFetchLoading(false);
|
setFetchLoading(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
const save = useCallback(() => {
|
const save = useCallback((data: ProfileRequest) => setPersonData(data, locale, jwt), []);
|
||||||
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fetchLoading,
|
fetchLoading,
|
||||||
|
fetchProfileSettings,
|
||||||
save,
|
save,
|
||||||
saveLoading,
|
|
||||||
profileSettings
|
profileSettings
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,25 @@
|
||||||
import { Profile } from '../types/profile';
|
import { PayInfo, Profile, ProfileRequest, ProfileData } from '../types/profile';
|
||||||
|
import { ExpertsTags } from '../types/tags';
|
||||||
|
import { EducationData, EducationDTO } from '../types/education';
|
||||||
|
import { PracticeData, PracticeDTO } from '../types/practice';
|
||||||
|
import { ScheduleDTO } from '../types/schedule';
|
||||||
import { apiRequest } from './helpers';
|
import { apiRequest } from './helpers';
|
||||||
|
|
||||||
export const setPersonData = (data: { login: string, password: string, role: string, languagesLinks: any[] }, locale: string, token: string): Promise<{ userData: Profile }> => apiRequest({
|
export const getUserData = (locale: string, token: string): Promise<Profile> => apiRequest({
|
||||||
|
url: '/home/userdata',
|
||||||
|
method: 'post',
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getPersonalData = (locale: string, token: string): Promise<ProfileData> => apiRequest({
|
||||||
|
url: '/home/person1',
|
||||||
|
method: 'post',
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setPersonData = (data: ProfileRequest, locale: string, token: string): Promise<{ userData: Profile }> => apiRequest({
|
||||||
url: '/home/applyperson1',
|
url: '/home/applyperson1',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data,
|
||||||
|
@ -9,9 +27,77 @@ export const setPersonData = (data: { login: string, password: string, role: str
|
||||||
token
|
token
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getPersonalData = (locale: string, token: string): Promise<Profile> => apiRequest({
|
export const getEducation = (locale: string, token: string): Promise<EducationDTO> => apiRequest({
|
||||||
url: '/home/userdata',
|
url: '/home/person2',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
locale,
|
locale,
|
||||||
token
|
token
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const setEducation = (locale: string, token: string, data: EducationData): Promise<EducationData> => apiRequest({
|
||||||
|
url: '/home/applyperson2',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getTags = (locale: string, token: string): Promise<ExpertsTags> => apiRequest({
|
||||||
|
url: '/home/person3',
|
||||||
|
method: 'post',
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setTags = (locale: string, token: string, data: ExpertsTags): Promise<ExpertsTags> => apiRequest({
|
||||||
|
url: '/home/applyperson3',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getPractice = (locale: string, token: string): Promise<PracticeDTO> => apiRequest({
|
||||||
|
url: '/home/person4',
|
||||||
|
method: 'post',
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setPractice = (locale: string, token: string, data: PracticeData): Promise<PracticeDTO> => apiRequest({
|
||||||
|
url: '/home/applyperson4',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getSchedule = (locale: string, token: string): Promise<ScheduleDTO> => apiRequest({
|
||||||
|
url: '/home/person51',
|
||||||
|
method: 'post',
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setSchedule = (locale: string, token: string, data: ScheduleDTO): Promise<ScheduleDTO> => apiRequest({
|
||||||
|
url: '/home/applyperson51',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getPayData = (locale: string, token: string): Promise<{ person6Data?: PayInfo }> => apiRequest({
|
||||||
|
url: '/home/person6',
|
||||||
|
method: 'post',
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setPayData = (locale: string, token: string, data: PayInfo): Promise<PayInfo> => apiRequest({
|
||||||
|
url: '/home/applyperson6',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
locale,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { ExpertDocument } from '../types/file';
|
||||||
|
import { apiRequest } from './helpers';
|
||||||
|
|
||||||
|
export const setUploadFile = (locale: string, token: string, data: any): Promise<ExpertDocument> => apiRequest({
|
||||||
|
url: '/home/uploadfile',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
locale,
|
||||||
|
token,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
});
|
|
@ -7,12 +7,12 @@ export default function AddOffer() {
|
||||||
<>
|
<>
|
||||||
<ol className="breadcrumb">
|
<ol className="breadcrumb">
|
||||||
<li className="breadcrumb-item">
|
<li className="breadcrumb-item">
|
||||||
<Link href={'/account/work-with-us' as any}>
|
<Link href={'/account/expert-profile' as any}>
|
||||||
Work With Us
|
Work With Us
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className="breadcrumb-item">
|
<li className="breadcrumb-item">
|
||||||
<Link href={'/account/work-with-us/coaching' as any}>
|
<Link href={'/account/expert-profile/coaching' as any}>
|
||||||
Coaching
|
Coaching
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
|
@ -7,7 +7,7 @@ export default function NewTopic() {
|
||||||
<>
|
<>
|
||||||
<ol className="breadcrumb">
|
<ol className="breadcrumb">
|
||||||
<li className="breadcrumb-item">
|
<li className="breadcrumb-item">
|
||||||
<Link href={'/account/work-with-us' as any}>
|
<Link href={'/account/expert-profile' as any}>
|
||||||
Work With Us
|
Work With Us
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
|
@ -0,0 +1,66 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { message } from 'antd';
|
||||||
|
// import { unstable_setRequestLocale } from 'next-intl/server';
|
||||||
|
import { ExpertData } from '../../../../../types/profile';
|
||||||
|
import { AUTH_TOKEN_KEY } from '../../../../../constants/common';
|
||||||
|
import { useLocalStorage } from '../../../../../hooks/useLocalStorage';
|
||||||
|
import { getEducation, getPersonalData, getTags, getPractice, getSchedule, getPayData } from '../../../../../actions/profile';
|
||||||
|
import { ExpertProfile } from '../../../../../components/ExpertProfile';
|
||||||
|
import { Loader } from '../../../../../components/view/Loader';
|
||||||
|
|
||||||
|
export default function ExpertProfilePage({ params: { locale } }: { params: { locale: string } }) {
|
||||||
|
// unstable_setRequestLocale(locale);
|
||||||
|
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [data, setData] = useState<ExpertData | undefined>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (jwt) {
|
||||||
|
setLoading(true);
|
||||||
|
Promise.all([
|
||||||
|
getPersonalData(locale, jwt),
|
||||||
|
getEducation(locale, jwt),
|
||||||
|
getTags(locale, jwt),
|
||||||
|
getPractice(locale, jwt),
|
||||||
|
getSchedule(locale, jwt),
|
||||||
|
getPayData(locale, jwt)
|
||||||
|
])
|
||||||
|
.then(([person, education, tags, practice, schedule, payData]) => {
|
||||||
|
console.log('person', person);
|
||||||
|
console.log('education', education);
|
||||||
|
console.log('tags', tags);
|
||||||
|
console.log('practice', practice);
|
||||||
|
console.log('schedule', schedule);
|
||||||
|
console.log('payData', payData);
|
||||||
|
setData({
|
||||||
|
person,
|
||||||
|
education,
|
||||||
|
tags,
|
||||||
|
practice,
|
||||||
|
schedule,
|
||||||
|
payData
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
message.error('Не удалось загрузить данные эксперта');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [jwt]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Loader isLoading={loading}>
|
||||||
|
{data && (
|
||||||
|
<ExpertProfile
|
||||||
|
locale={locale}
|
||||||
|
data={data}
|
||||||
|
updateData={setData}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Loader>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,18 +1,10 @@
|
||||||
import React, { Suspense } from 'react';
|
import React, { Suspense } from 'react';
|
||||||
import type { Metadata } from 'next';
|
|
||||||
import { unstable_setRequestLocale } from 'next-intl/server';
|
import { unstable_setRequestLocale } from 'next-intl/server';
|
||||||
import { useTranslations } from 'next-intl';
|
|
||||||
import { ProfileSettings } from '../../../../../components/Account';
|
import { ProfileSettings } from '../../../../../components/Account';
|
||||||
import { i18nText } from '../../../../../i18nKeys';
|
import { i18nText } from '../../../../../i18nKeys';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: 'Bbuddy - Account - Profile Settings',
|
|
||||||
description: 'Bbuddy desc Profile settings'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Settings({ params: { locale } }: { params: { locale: string } }) {
|
export default function Settings({ params: { locale } }: { params: { locale: string } }) {
|
||||||
unstable_setRequestLocale(locale);
|
unstable_setRequestLocale(locale);
|
||||||
const t = useTranslations('Account.Settings');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
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);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ol className="breadcrumb">
|
|
||||||
<li className="breadcrumb-item">
|
|
||||||
<Link href={'/account/work-with-us' as any}>
|
|
||||||
Work With Us
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li className="breadcrumb-item active" aria-current="page">Coaching</li>
|
|
||||||
</ol>
|
|
||||||
<div className="coaching-info">
|
|
||||||
<div className="card-profile">
|
|
||||||
<div className="card-profile__header">
|
|
||||||
<div className="card-profile__header__portrait">
|
|
||||||
<img src="/images/person.png" className="" alt="" />
|
|
||||||
</div>
|
|
||||||
<div className="card-profile__header__inner">
|
|
||||||
<div className="card-profile__header__name">
|
|
||||||
David
|
|
||||||
</div>
|
|
||||||
<div className="card-profile__header__title">
|
|
||||||
12 Practice hours
|
|
||||||
</div>
|
|
||||||
<div className="card-profile__header__title ">
|
|
||||||
15 Supervision per year
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-info__wrap-btn">
|
|
||||||
<a href="#" className="btn-edit">Edit</a>
|
|
||||||
<a href="#" className="btn-apply">Add Offer</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-section">
|
|
||||||
<h2 className="title-h2">
|
|
||||||
My Offers
|
|
||||||
</h2>
|
|
||||||
<div className="coaching-section__desc">
|
|
||||||
<div className="coaching-offer">
|
|
||||||
<div className="coaching-offer__header">
|
|
||||||
<div className="coaching-offer__title">
|
|
||||||
Senior Software Engineer
|
|
||||||
</div>
|
|
||||||
<div className="coaching-offer__wrap-btn">
|
|
||||||
<a href="#" className="link-edit">Edit</a>
|
|
||||||
<a href="#" className="link-remove">Remove</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-offer__price">
|
|
||||||
45$ <span>/ 45min</span>
|
|
||||||
</div>
|
|
||||||
<div className="skills__list">
|
|
||||||
<div className="skills__list__item">Engineering & Data</div>
|
|
||||||
<div className="skills__list__item">Engineering & Data</div>
|
|
||||||
<div className="skills__list__more">+6</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-offer__desc">
|
|
||||||
I have worked across a variety of organizations, lead teams, and delivered quality software
|
|
||||||
for 8 years. In that time I've worked as an independent consultant, at agencies as a team
|
|
||||||
lead, and as a senior engineer at Auth0. I also host a podcast
|
|
||||||
https://anchor.fm/work-in-programming where I break down how …
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-section">
|
|
||||||
<h2 className="title-h2">
|
|
||||||
About Coach
|
|
||||||
</h2>
|
|
||||||
<div 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.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="coaching-section">
|
|
||||||
<h2 className="title-h2">
|
|
||||||
Education
|
|
||||||
</h2>
|
|
||||||
<div className="coaching-section__desc">
|
|
||||||
<h3 className="title-h3">Psychologist </h3>
|
|
||||||
<div 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.
|
|
||||||
</div>
|
|
||||||
<div className="sertific">
|
|
||||||
<img src="/images/sertific.png" className="" alt="" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-section">
|
|
||||||
<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
|
|
||||||
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-section">
|
|
||||||
<h2 className="title-h2">
|
|
||||||
Trainings | Seminars | Courses
|
|
||||||
</h2>
|
|
||||||
<div className="coaching-section__desc">
|
|
||||||
<div 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.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="coaching-section">
|
|
||||||
<h2 className="title-h2">
|
|
||||||
MBA Information
|
|
||||||
</h2>
|
|
||||||
<div className="coaching-section__desc">
|
|
||||||
<div 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.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { unstable_setRequestLocale } from 'next-intl/server';
|
|
||||||
import { i18nText } from '../../../../../i18nKeys';
|
|
||||||
|
|
||||||
export default function WorkWithUs({ params: { locale } }: { params: { locale: string } }) {
|
|
||||||
unstable_setRequestLocale(locale);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ol className="breadcrumb">
|
|
||||||
<li className="breadcrumb-item active" aria-current="page">{i18nText('accountMenu.work-with-us', locale)}</li>
|
|
||||||
</ol>
|
|
||||||
<div className="b-work">
|
|
||||||
<div className="image-info">
|
|
||||||
<img className="" src="/images/info.png" alt="" />
|
|
||||||
</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>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -6,4 +6,4 @@ export default function Loading() {
|
||||||
...loading
|
...loading
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,125 +1,190 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { FC, useEffect, useState } from 'react';
|
import React, { FC, useEffect, useState } from 'react';
|
||||||
import { Form, Upload } from 'antd';
|
import { Button, Form, message, Upload } from 'antd';
|
||||||
import type { UploadFile, UploadProps } from 'antd';
|
import type { GetProp, UploadFile, UploadProps } from 'antd';
|
||||||
import ImgCrop from 'antd-img-crop';
|
import ImgCrop from 'antd-img-crop';
|
||||||
import { CameraOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { CameraOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
import { useRouter } from '../../navigation';
|
import { useRouter } from '../../navigation';
|
||||||
import { i18nText } from '../../i18nKeys';
|
import { i18nText } from '../../i18nKeys';
|
||||||
import { Profile } from '../../types/profile';
|
import { ProfileRequest } from '../../types/profile';
|
||||||
|
import { validateImage } from '../../utils/account';
|
||||||
import { useProfileSettings } from '../../actions/hooks/useProfileSettings';
|
import { useProfileSettings } from '../../actions/hooks/useProfileSettings';
|
||||||
import { CustomInput } from '../view/CustomInput';
|
import { CustomInput } from '../view/CustomInput';
|
||||||
import { OutlinedButton } from '../view/OutlinedButton';
|
import { OutlinedButton } from '../view/OutlinedButton';
|
||||||
import { FilledYellowButton } from '../view/FilledButton';
|
import { FilledYellowButton } from '../view/FilledButton';
|
||||||
import { DeleteAccountModal } from "../Modals/DeleteAccountModal";
|
import { DeleteAccountModal } from '../Modals/DeleteAccountModal';
|
||||||
|
import { Loader } from '../view/Loader';
|
||||||
|
|
||||||
type ProfileSettingsProps = {
|
type ProfileSettingsProps = {
|
||||||
locale: string;
|
locale: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
|
type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
|
||||||
|
|
||||||
export const ProfileSettings: FC<ProfileSettingsProps> = ({ locale }) => {
|
export const ProfileSettings: FC<ProfileSettingsProps> = ({ locale }) => {
|
||||||
const [form] = Form.useForm<Profile>();
|
const [form] = Form.useForm<ProfileRequest>();
|
||||||
const { profileSettings } = useProfileSettings(locale);
|
const { profileSettings, fetchProfileSettings, save, fetchLoading } = useProfileSettings(locale);
|
||||||
const [showDeleteModal, setShowDeleteModal] = useState<boolean>(false);
|
const [showDeleteModal, setShowDeleteModal] = useState<boolean>(false);
|
||||||
|
const [saveLoading, setSaveLoading] = useState<boolean>(false);
|
||||||
|
const [photo, setPhoto] = useState<UploadFile | undefined>();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchProfileSettings()
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (profileSettings) {
|
if (profileSettings) {
|
||||||
form.setFieldsValue(profileSettings);
|
form.setFieldsValue(profileSettings);
|
||||||
}
|
}
|
||||||
}, [profileSettings]);
|
}, [profileSettings]);
|
||||||
|
|
||||||
const saveProfileSettings = () => {
|
const onSaveProfile = () => {
|
||||||
form.validateFields()
|
form.validateFields()
|
||||||
.then(() => {
|
.then(({ login, surname, username }) => {
|
||||||
console.log('success')
|
const { phone, role, languagesLinks } = profileSettings;
|
||||||
|
const newProfile: ProfileRequest = {
|
||||||
|
phone,
|
||||||
|
role,
|
||||||
|
login,
|
||||||
|
surname,
|
||||||
|
username,
|
||||||
|
isPasswordKeepExisting: true,
|
||||||
|
isFaceImageKeepExisting: true,
|
||||||
|
languagesLinks: languagesLinks?.map(({ languageId }) => ({ languageId })) || []
|
||||||
|
};
|
||||||
|
|
||||||
|
// if (photo) {
|
||||||
|
// console.log(photo);
|
||||||
|
// const formData = new FormData();
|
||||||
|
// formData.append('file', photo as FileType);
|
||||||
|
//
|
||||||
|
// newProfile.faceImage = photo;
|
||||||
|
// newProfile.isFaceImageKeepExisting = false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log(newProfile);
|
||||||
|
|
||||||
|
setSaveLoading(true);
|
||||||
|
save(newProfile)
|
||||||
|
.then(() => {
|
||||||
|
fetchProfileSettings();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
message.error('Не удалось сохранить изменения');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setSaveLoading(false);
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const [fileList, setFileList] = useState<UploadFile[]>();
|
const beforeCrop = (file: UploadFile) => {
|
||||||
|
return validateImage(file, true);
|
||||||
|
}
|
||||||
|
|
||||||
const onChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
|
const beforeUpload = (file: UploadFile) => {
|
||||||
setFileList(newFileList);
|
const isValid = validateImage(file);
|
||||||
};
|
|
||||||
|
|
||||||
const onPreview = async (file: UploadFile) => {
|
if (isValid) {
|
||||||
// let src = file.url as string;
|
setPhoto(file);
|
||||||
// if (!src) {
|
}
|
||||||
// src = await new Promise((resolve) => {
|
|
||||||
// const reader = new FileReader();
|
return false;
|
||||||
// reader.readAsDataURL(file.originFileObj as FileType);
|
}
|
||||||
// reader.onload = () => resolve(reader.result as string);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// const image = new Image();
|
|
||||||
// image.src = src;
|
|
||||||
// const imgWindow = window.open(src);
|
|
||||||
// imgWindow?.document.write(image.outerHTML);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeleteAccount = () => setShowDeleteModal(true);
|
const onDeleteAccount = () => setShowDeleteModal(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form form={form} className="form-settings">
|
<Loader isLoading={fetchLoading} refresh={fetchProfileSettings}>
|
||||||
<div className="user-avatar">
|
<Form form={form} className="form-settings">
|
||||||
<div className="user-avatar__edit" style={profileSettings?.faceImageUrl ? { backgroundImage: `url(${profileSettings.faceImageUrl})` } : undefined}>
|
<div className="user-avatar">
|
||||||
<input className="" type="file" id="input-file" />
|
<div className="user-avatar__edit" style={profileSettings?.faceImageUrl ? { backgroundImage: `url(${profileSettings.faceImageUrl})` } : undefined}>
|
||||||
<label htmlFor="input-file" className="form-label" />
|
<input className="" type="file" id="input-file" />
|
||||||
|
<label htmlFor="input-file" className="form-label" />
|
||||||
|
</div>
|
||||||
|
<div className="user-avatar__text">{i18nText('photoDesc', locale)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="user-avatar__text">{i18nText('photoDesc', locale)}</div>
|
<ImgCrop
|
||||||
</div>
|
modalTitle="Редактировать"
|
||||||
{/* <ImgCrop rotationSlider>
|
modalOk="Сохранить"
|
||||||
<Upload
|
modalCancel="Отмена"
|
||||||
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
|
beforeCrop={beforeCrop}
|
||||||
fileList={fileList}
|
|
||||||
onChange={onChange}
|
|
||||||
onPreview={onPreview}
|
|
||||||
>
|
>
|
||||||
<Button icon={<CameraOutlined />}>Click to Upload</Button>
|
<Upload
|
||||||
</Upload>
|
fileList={photo ? [photo] : profileSettings?.faceImageUrl ? [
|
||||||
</ImgCrop> */}
|
{
|
||||||
<div className="form-fieldset">
|
uid: profileSettings.faceImageUrl,
|
||||||
<div className="form-field">
|
name: profileSettings.faceImageUrl,
|
||||||
<Form.Item name="username">
|
status: 'done',
|
||||||
<CustomInput placeholder={i18nText('name', locale)} />
|
url: profileSettings.faceImageUrl
|
||||||
|
}
|
||||||
|
] : undefined}
|
||||||
|
accept=".jpg,.jpeg,.png,.gif"
|
||||||
|
beforeUpload={beforeUpload}
|
||||||
|
multiple={false}
|
||||||
|
showUploadList={false}
|
||||||
|
>
|
||||||
|
{photo && <img height={100} width={100} src={URL.createObjectURL(photo)} />}
|
||||||
|
<Button icon={<CameraOutlined />}>Click to Upload</Button>
|
||||||
|
</Upload>
|
||||||
|
</ImgCrop>
|
||||||
|
<div className="form-fieldset">
|
||||||
|
<div className="form-field">
|
||||||
|
<Form.Item name="username" rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Поле не должно быть пустым'
|
||||||
|
}
|
||||||
|
]}>
|
||||||
|
<CustomInput placeholder={i18nText('name', locale)} />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<div className="form-field">
|
||||||
|
<Form.Item name="surname">
|
||||||
|
<CustomInput placeholder={i18nText('surname', locale)} />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
{/* <div className="form-field">
|
||||||
|
<Form.Item name="birthday">
|
||||||
|
<CustomInput placeholder={i18nText('birthday', locale)} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
</div> */}
|
||||||
|
<div className="form-field">
|
||||||
|
<Form.Item name="login" rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Поле не должно быть пустым'
|
||||||
|
}
|
||||||
|
]}>
|
||||||
|
<CustomInput type="email" placeholder="E-mail" />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-field">
|
<div className="form-actions">
|
||||||
<Form.Item name="surname">
|
<FilledYellowButton
|
||||||
<CustomInput placeholder={i18nText('surname', locale)} />
|
onClick={onSaveProfile}
|
||||||
</Form.Item>
|
loading={saveLoading}
|
||||||
|
>
|
||||||
|
{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>
|
</div>
|
||||||
{/* <div className="form-field">
|
<DeleteAccountModal
|
||||||
<Form.Item name="birthday">
|
open={showDeleteModal}
|
||||||
<CustomInput placeholder={i18nText('birthday', locale)} />
|
handleCancel={() => setShowDeleteModal(false)}
|
||||||
</Form.Item>
|
/>
|
||||||
</div> */}
|
</Form>
|
||||||
<div className="form-field">
|
</Loader>
|
||||||
<Form.Item name="login">
|
|
||||||
<CustomInput type="email" placeholder="E-mail" />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -283,7 +283,7 @@ export const SessionDetailsContent = ({ session, locale, activeType, startSessio
|
||||||
))}
|
))}
|
||||||
{(isCoach ? session?.clientComments : session?.coachComments)?.length > 0 && (
|
{(isCoach ? session?.clientComments : session?.coachComments)?.length > 0 && (
|
||||||
<div className="card-detail__comments_title">
|
<div className="card-detail__comments_title">
|
||||||
{isCoach ? 'Client Comments' : 'Coach Comments'}
|
{isCoach ? i18nText('session.clientComments', locale) : i18nText('session.coachComments', locale)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(isCoach ? session?.clientComments : session?.coachComments)?.map(({ id , comment }) => (
|
{(isCoach ? session?.clientComments : session?.coachComments)?.map(({ id , comment }) => (
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { i18nText } from '../../i18nKeys';
|
||||||
|
|
||||||
|
export const EmptyExpertProfile = ({ locale }: { locale: string }) => (
|
||||||
|
<>
|
||||||
|
<ol className="breadcrumb">
|
||||||
|
<li className="breadcrumb-item active" aria-current="page">{i18nText('accountMenu.expert-profile', locale)}</li>
|
||||||
|
</ol>
|
||||||
|
<div className="b-work">
|
||||||
|
<div className="image-info">
|
||||||
|
<img className="" src="/images/info.png" alt="" />
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
|
@ -0,0 +1,98 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
|
import { i18nText } from '../../i18nKeys';
|
||||||
|
import { ExpertData } from '../../types/profile';
|
||||||
|
import { AUTH_TOKEN_KEY } from '../../constants/common';
|
||||||
|
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
||||||
|
import { getTags } from '../../actions/profile';
|
||||||
|
import { Loader } from '../view/Loader';
|
||||||
|
import { LinkButton } from '../view/LinkButton';
|
||||||
|
import { ExpertTags } from './content/ExpertTags';
|
||||||
|
import { ExpertSchedule } from './content/ExpertSchedule';
|
||||||
|
import { ExpertPayData } from './content/ExpertPayData';
|
||||||
|
import { ExpertEducation } from './content/ExpertEducation';
|
||||||
|
|
||||||
|
type ExpertProfileProps = {
|
||||||
|
locale: string;
|
||||||
|
data: ExpertData;
|
||||||
|
updateData: (data: ExpertData) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExpertProfile = ({ locale, data, updateData }: ExpertProfileProps) => {
|
||||||
|
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
||||||
|
const [loading, setLoading] = useState<(keyof ExpertData)[]>([]);
|
||||||
|
|
||||||
|
const updateExpert = (key: keyof ExpertData) => {
|
||||||
|
switch (key) {
|
||||||
|
case 'tags':
|
||||||
|
setLoading([key]);
|
||||||
|
getTags(locale, jwt)
|
||||||
|
.then((tags) => {
|
||||||
|
updateData({
|
||||||
|
...data,
|
||||||
|
tags
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => message.error('Не удалось обновить направления'))
|
||||||
|
.finally(() => setLoading([]));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ol className="breadcrumb">
|
||||||
|
<li className="breadcrumb-item active" aria-current="page">{i18nText('coaching', locale)}</li>
|
||||||
|
</ol>
|
||||||
|
<div className="coaching-info">
|
||||||
|
<div className="coaching-profile">
|
||||||
|
<div className="coaching-profile__portrait">
|
||||||
|
<img src="/images/person.png" className="" alt="" />
|
||||||
|
</div>
|
||||||
|
<div className="coaching-profile__inner">
|
||||||
|
<div className="coaching-profile__name">
|
||||||
|
David
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="coaching-section__wrap">
|
||||||
|
<div className="coaching-section">
|
||||||
|
<div className="coaching-section__title">
|
||||||
|
<h2 className="title-h2">{i18nText('aboutCoach', locale)}</h2>
|
||||||
|
<h2 className="title-h2">person1 + person4</h2>
|
||||||
|
<LinkButton
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="card-profile__header__title">
|
||||||
|
{`12 ${i18nText('practiceHours', locale)}`}
|
||||||
|
</div>
|
||||||
|
<div className="card-profile__header__title ">
|
||||||
|
{`15 ${i18nText('supervisionCount', locale)}`}
|
||||||
|
</div>
|
||||||
|
<div 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.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Loader isLoading={loading.includes('tags')}>
|
||||||
|
<ExpertTags
|
||||||
|
locale={locale}
|
||||||
|
data={data?.tags}
|
||||||
|
updateExpert={updateExpert}
|
||||||
|
/>
|
||||||
|
</Loader>
|
||||||
|
<ExpertSchedule locale={locale} data={data?.schedule} />
|
||||||
|
<ExpertEducation locale={locale} data={data?.education} />
|
||||||
|
<ExpertPayData locale={locale} data={data?.payData?.person6Data} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
};
|
|
@ -0,0 +1,34 @@
|
||||||
|
export const MyOffers = () => (
|
||||||
|
<div className="coaching-section">
|
||||||
|
<h2 className="title-h2">
|
||||||
|
My Offers
|
||||||
|
</h2>
|
||||||
|
<div className="coaching-section__desc">
|
||||||
|
<div className="coaching-offer">
|
||||||
|
<div className="coaching-offer__header">
|
||||||
|
<div className="coaching-offer__title">
|
||||||
|
Senior Software Engineer
|
||||||
|
</div>
|
||||||
|
<div className="coaching-offer__wrap-btn">
|
||||||
|
<a href="#" className="link-edit">Edit</a>
|
||||||
|
<a href="#" className="link-remove">Remove</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="coaching-offer__price">
|
||||||
|
45$ <span>/ 45min</span>
|
||||||
|
</div>
|
||||||
|
<div className="skills__list">
|
||||||
|
<div className="skills__list__item">Engineering & Data</div>
|
||||||
|
<div className="skills__list__item">Engineering & Data</div>
|
||||||
|
<div className="skills__list__more">+6</div>
|
||||||
|
</div>
|
||||||
|
<div className="coaching-offer__desc">
|
||||||
|
I have worked across a variety of organizations, lead teams, and delivered quality software
|
||||||
|
for 8 years. In that time I've worked as an independent consultant, at agencies as a team
|
||||||
|
lead, and as a senior engineer at Auth0. I also host a podcast
|
||||||
|
https://anchor.fm/work-in-programming where I break down how …
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
|
import { EducationDTO } from '../../../types/education';
|
||||||
|
import { i18nText } from '../../../i18nKeys';
|
||||||
|
import { LinkButton } from '../../view/LinkButton';
|
||||||
|
|
||||||
|
type ExpertEducationProps = {
|
||||||
|
locale: string;
|
||||||
|
data?: EducationDTO;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExpertEducation = ({ locale, data }: ExpertEducationProps) => {
|
||||||
|
return (
|
||||||
|
<div className="coaching-section__wrap">
|
||||||
|
<div className="coaching-section">
|
||||||
|
<div className="coaching-section__title">
|
||||||
|
<h2 className="title-h2">{i18nText('education', locale)}</h2>
|
||||||
|
<h2 className="title-h2">person2</h2>
|
||||||
|
<LinkButton
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="coaching-section__desc">
|
||||||
|
<h3 className="title-h3">Psychologist</h3>
|
||||||
|
<div 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.
|
||||||
|
</div>
|
||||||
|
<div className="sertific">
|
||||||
|
<img src="/images/sertific.png" className="" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="coaching-section">
|
||||||
|
<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
|
||||||
|
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="coaching-section">
|
||||||
|
<h2 className="title-h2">
|
||||||
|
{`${i18nText('trainings', locale)} | ${i18nText('seminars', locale)} | ${i18nText('courses', locale)}`}
|
||||||
|
</h2>
|
||||||
|
<div className="coaching-section__desc">
|
||||||
|
<div 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.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="coaching-section">
|
||||||
|
<h2 className="title-h2">{i18nText('mba', locale)}</h2>
|
||||||
|
<div className="coaching-section__desc">
|
||||||
|
<div 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.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
|
import { i18nText } from '../../../i18nKeys';
|
||||||
|
import { PayInfo } from '../../../types/profile';
|
||||||
|
import { LinkButton } from '../../view/LinkButton';
|
||||||
|
|
||||||
|
type ExpertPayDataProps = {
|
||||||
|
locale: string;
|
||||||
|
data?: PayInfo
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExpertPayData = ({ locale, data }: ExpertPayDataProps) => {
|
||||||
|
return (
|
||||||
|
<div className="coaching-section__wrap">
|
||||||
|
<div className="coaching-section">
|
||||||
|
<div className="coaching-section__title">
|
||||||
|
<h2 className="title-h2">Card data - person6</h2>
|
||||||
|
<LinkButton
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="base-text">
|
||||||
|
Card
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
|
import { ScheduleDTO } from '../../../types/schedule';
|
||||||
|
import { i18nText } from '../../../i18nKeys';
|
||||||
|
import { LinkButton } from '../../view/LinkButton';
|
||||||
|
|
||||||
|
type ExpertScheduleProps = {
|
||||||
|
locale: string;
|
||||||
|
data?: ScheduleDTO;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExpertSchedule = ({ locale, data }: ExpertScheduleProps) => {
|
||||||
|
return (
|
||||||
|
<div className="coaching-section__wrap">
|
||||||
|
<div className="coaching-section">
|
||||||
|
<div className="coaching-section__title">
|
||||||
|
<h2 className="title-h2">Schedule - person51</h2>
|
||||||
|
<LinkButton
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="base-text">
|
||||||
|
Schedule
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,47 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Tag } from 'antd';
|
||||||
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
|
import { i18nText } from '../../../i18nKeys';
|
||||||
|
import { ExpertsTags } from '../../../types/tags';
|
||||||
|
import { ExpertData } from '../../../types/profile';
|
||||||
|
import { LinkButton } from '../../view/LinkButton';
|
||||||
|
import { EditExpertTagsModal } from '../../Modals/EditExpertTagsModal';
|
||||||
|
|
||||||
|
type ExpertTagsProps = {
|
||||||
|
locale: string;
|
||||||
|
data?: ExpertsTags;
|
||||||
|
updateExpert: (key: keyof ExpertData) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ExpertTags = ({ locale, data, updateExpert }: ExpertTagsProps) => {
|
||||||
|
const [showEdit, setShowEdit] = useState<boolean>(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="coaching-section__wrap">
|
||||||
|
<div className="coaching-section">
|
||||||
|
<div className="coaching-section__title">
|
||||||
|
<h2 className="title-h2">{i18nText('direction', locale)}</h2>
|
||||||
|
<LinkButton
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => setShowEdit(true)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="skills__list">
|
||||||
|
{data?.themesTags && data.themesTags?.length > 0 && data.themesTags
|
||||||
|
.filter(({ isActive, isSelected }) => isActive && isSelected)
|
||||||
|
.map(({ id, name }) => <Tag key={id} className="skills__list__item">{name}</Tag>)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<EditExpertTagsModal
|
||||||
|
locale={locale}
|
||||||
|
open={showEdit}
|
||||||
|
data={data}
|
||||||
|
handleCancel={() => setShowEdit(false)}
|
||||||
|
refresh={() => updateExpert('tags')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
export * from './EmptyExpertProfile';
|
||||||
|
export * from './ExpertProfile';
|
||||||
|
export * from './MyOffers';
|
|
@ -98,7 +98,7 @@ export const ExpertPractice: FC<ExpertDetailsProps> = ({ expert, locale }) => {
|
||||||
|
|
||||||
return practiceCases?.length > 0 ? (
|
return practiceCases?.length > 0 ? (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="title-h3">Successful Cases From Practice</h3>
|
<h3 className="title-h3">{i18nText('successfulCase', locale)}</h3>
|
||||||
{practiceCases?.map(({ id, description, themesGroupIds }) => {
|
{practiceCases?.map(({ id, description, themesGroupIds }) => {
|
||||||
const filtered = themesGroups?.filter(({ id }) => themesGroupIds?.includes(+id));
|
const filtered = themesGroups?.filter(({ id }) => themesGroupIds?.includes(+id));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, {FC, useCallback, useEffect, useState} from 'react';
|
||||||
|
import { Modal, Button, List, message } from 'antd';
|
||||||
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
|
import { i18nText } from '../../i18nKeys';
|
||||||
|
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
||||||
|
import { AUTH_TOKEN_KEY } from '../../constants/common';
|
||||||
|
import { ExpertsTags, Tag } from '../../types/tags';
|
||||||
|
import { CustomSwitch } from '../view/CustomSwitch';
|
||||||
|
import { setTags } from '../../actions/profile';
|
||||||
|
|
||||||
|
type EditExpertTagsModalProps = {
|
||||||
|
open: boolean;
|
||||||
|
handleCancel: () => void;
|
||||||
|
locale: string;
|
||||||
|
data?: ExpertsTags;
|
||||||
|
refresh: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EditExpertTagsModal: FC<EditExpertTagsModalProps> = ({
|
||||||
|
open,
|
||||||
|
handleCancel,
|
||||||
|
locale,
|
||||||
|
data,
|
||||||
|
refresh
|
||||||
|
}) => {
|
||||||
|
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [expertTags, setExpertTags] = useState<Tag[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setExpertTags(data?.themesTags || []);
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
const onSaveTags = () => {
|
||||||
|
setLoading(true);
|
||||||
|
setTags(locale, jwt, { themesGroups: data?.themesGroups, themesTags: expertTags })
|
||||||
|
.then(() => {
|
||||||
|
handleCancel();
|
||||||
|
refresh();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
message.error('Не удалось сохранить направления');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTag = useCallback((id: number, isSelected: boolean) => {
|
||||||
|
setExpertTags(expertTags.map((tag) => {
|
||||||
|
if (tag.id === id) {
|
||||||
|
tag.isSelected = isSelected;
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}))
|
||||||
|
}, [expertTags, setExpertTags]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="b-modal"
|
||||||
|
open={open}
|
||||||
|
title={undefined}
|
||||||
|
onOk={undefined}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
footer={false}
|
||||||
|
width={498}
|
||||||
|
closeIcon={<CloseOutlined style={{ fontSize: 20, color: '#000' }}/>}
|
||||||
|
>
|
||||||
|
<div className="b-modal__expert__content">
|
||||||
|
<div className="b-modal__expert__title">{i18nText('direction', locale)}</div>
|
||||||
|
<div className="b-modal__expert__inner">
|
||||||
|
{data?.themesGroups && data.themesGroups.filter(({ isActive }) => isActive).map(({ id, name }) => (
|
||||||
|
<div key={`group_${id}`}>
|
||||||
|
<h3 className="title-h4">{name}</h3>
|
||||||
|
{expertTags?.length > 0 ? (
|
||||||
|
<div className="b-filter__inner">
|
||||||
|
<List
|
||||||
|
itemLayout="vertical"
|
||||||
|
size="small"
|
||||||
|
dataSource={expertTags.filter(({ isActive, groupId }) => (isActive && groupId == id)) || []}
|
||||||
|
split={false}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
renderItem={({ id, name, isSelected }) => (
|
||||||
|
<List.Item key={`tag_${id}`} style={{ padding: 0 }}>
|
||||||
|
<div className="b-filter__item">
|
||||||
|
<div className="b-filter__title">{name}</div>
|
||||||
|
<CustomSwitch
|
||||||
|
defaultChecked={isSelected || false}
|
||||||
|
onChange={(checked: boolean) => updateTag(id, checked)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : <div>No tags</div>}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="b-modal__expert__button">
|
||||||
|
<Button
|
||||||
|
className="card-detail__apply"
|
||||||
|
onClick={onSaveTags}
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
{i18nText('save', locale)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
|
@ -4,9 +4,9 @@ export default {
|
||||||
notifications: 'Benachrichtigung',
|
notifications: 'Benachrichtigung',
|
||||||
support: 'Hilfe & Support',
|
support: 'Hilfe & Support',
|
||||||
information: 'Rechtliche Informationen',
|
information: 'Rechtliche Informationen',
|
||||||
settings: 'Profileinstellungen',
|
settings: 'Kontoeinstellungen',
|
||||||
messages: 'Nachrichten',
|
messages: 'Nachrichten',
|
||||||
'work-with-us': 'Arbeite mit uns'
|
'expert-profile': 'Expertenprofil'
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
'bb-client': 'Mit BB wachsen',
|
'bb-client': 'Mit BB wachsen',
|
||||||
|
@ -41,6 +41,8 @@ export default {
|
||||||
myComments: 'Meine Kommentare',
|
myComments: 'Meine Kommentare',
|
||||||
addComment: 'Neuen Kommentar hinzufügen',
|
addComment: 'Neuen Kommentar hinzufügen',
|
||||||
commentPlaceholder: 'Ihr Kommentar',
|
commentPlaceholder: 'Ihr Kommentar',
|
||||||
|
clientComments: 'Kundenkommentare',
|
||||||
|
coachComments: 'Trainerkommentare'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Zukünftige Räume',
|
upcoming: 'Zukünftige Räume',
|
||||||
|
@ -84,6 +86,7 @@ export default {
|
||||||
fromTo: 'von $ bis $',
|
fromTo: 'von $ bis $',
|
||||||
apply: 'Anwenden',
|
apply: 'Anwenden',
|
||||||
save: 'Speichern',
|
save: 'Speichern',
|
||||||
|
edit: 'Bearbeiten',
|
||||||
changePass: 'Passwort ändern',
|
changePass: 'Passwort ändern',
|
||||||
resetPass: 'Passwort zurücksetzen',
|
resetPass: 'Passwort zurücksetzen',
|
||||||
getStarted: 'Loslegen',
|
getStarted: 'Loslegen',
|
||||||
|
@ -98,9 +101,18 @@ export default {
|
||||||
supervisionCount: 'Supervision pro Jahr',
|
supervisionCount: 'Supervision pro Jahr',
|
||||||
outOf: 'von',
|
outOf: 'von',
|
||||||
schedule: 'Zeitplan',
|
schedule: 'Zeitplan',
|
||||||
|
successfulCase: 'Erfolgreiche Fälle aus der Praxis',
|
||||||
signUp: 'Jetzt anmelden',
|
signUp: 'Jetzt anmelden',
|
||||||
noData: 'Keine Daten',
|
noData: 'Keine Daten',
|
||||||
notFound: 'Nicht gefunden',
|
notFound: 'Nicht gefunden',
|
||||||
|
trainings: 'Trainings',
|
||||||
|
seminars: 'Seminare',
|
||||||
|
courses: 'Kurse',
|
||||||
|
mba: 'MBA-Information',
|
||||||
|
aboutCoach: 'Über Coach',
|
||||||
|
education: 'Bildung',
|
||||||
|
coaching: 'Coaching',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
invalidEmail: 'Die E-Mail-Adresse ist ungültig',
|
invalidEmail: 'Die E-Mail-Adresse ist ungültig',
|
||||||
emptyEmail: 'Bitte geben Sie Ihre E-Mail ein',
|
emptyEmail: 'Bitte geben Sie Ihre E-Mail ein',
|
||||||
|
|
|
@ -4,9 +4,9 @@ export default {
|
||||||
notifications: 'Notification',
|
notifications: 'Notification',
|
||||||
support: 'Help & Support',
|
support: 'Help & Support',
|
||||||
information: 'Legal Information',
|
information: 'Legal Information',
|
||||||
settings: 'Profile Settings',
|
settings: 'Account Settings',
|
||||||
messages: 'Messages',
|
messages: 'Messages',
|
||||||
'work-with-us': 'Work With Us'
|
'expert-profile': 'Expert profile'
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
'bb-client': 'Start grow with BB',
|
'bb-client': 'Start grow with BB',
|
||||||
|
@ -41,6 +41,8 @@ export default {
|
||||||
myComments: 'My comments',
|
myComments: 'My comments',
|
||||||
addComment: 'Add new',
|
addComment: 'Add new',
|
||||||
commentPlaceholder: 'Your comment',
|
commentPlaceholder: 'Your comment',
|
||||||
|
clientComments: 'Client Comments',
|
||||||
|
coachComments: 'Coach Comments'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Upcoming Rooms',
|
upcoming: 'Upcoming Rooms',
|
||||||
|
@ -84,6 +86,7 @@ export default {
|
||||||
fromTo: 'from $ to $',
|
fromTo: 'from $ to $',
|
||||||
apply: 'Apply',
|
apply: 'Apply',
|
||||||
save: 'Save',
|
save: 'Save',
|
||||||
|
edit: 'Edit',
|
||||||
changePass: 'Change password',
|
changePass: 'Change password',
|
||||||
resetPass: 'Reset password',
|
resetPass: 'Reset password',
|
||||||
getStarted: 'Get started',
|
getStarted: 'Get started',
|
||||||
|
@ -98,9 +101,17 @@ export default {
|
||||||
supervisionCount: 'Supervision per year',
|
supervisionCount: 'Supervision per year',
|
||||||
outOf: 'out of',
|
outOf: 'out of',
|
||||||
schedule: 'Schedule',
|
schedule: 'Schedule',
|
||||||
|
successfulCase: 'Successful Cases From Practice',
|
||||||
signUp: 'Sign up now',
|
signUp: 'Sign up now',
|
||||||
noData: 'No data',
|
noData: 'No data',
|
||||||
notFound: 'Not found',
|
notFound: 'Not found',
|
||||||
|
trainings: 'Trainings',
|
||||||
|
seminars: 'Seminars',
|
||||||
|
courses: 'Courses',
|
||||||
|
mba: 'MBA Information',
|
||||||
|
aboutCoach: 'About Coach',
|
||||||
|
education: 'Education',
|
||||||
|
coaching: 'Coaching',
|
||||||
errors: {
|
errors: {
|
||||||
invalidEmail: 'The email address is not valid',
|
invalidEmail: 'The email address is not valid',
|
||||||
emptyEmail: 'Please enter your E-mail',
|
emptyEmail: 'Please enter your E-mail',
|
||||||
|
|
|
@ -4,9 +4,9 @@ export default {
|
||||||
notifications: 'Notificación',
|
notifications: 'Notificación',
|
||||||
support: 'Ayuda y asistencia',
|
support: 'Ayuda y asistencia',
|
||||||
information: 'Información jurídica',
|
information: 'Información jurídica',
|
||||||
settings: 'Ajustes del perfil',
|
settings: 'Ajustes de cuenta',
|
||||||
messages: 'Mensajes',
|
messages: 'Mensajes',
|
||||||
'work-with-us': 'Trabaja con nosotros'
|
'expert-profile': 'Perfil del experto'
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
'bb-client': 'Empieza a crecer con BB',
|
'bb-client': 'Empieza a crecer con BB',
|
||||||
|
@ -41,6 +41,8 @@ export default {
|
||||||
myComments: 'Mis comentarios',
|
myComments: 'Mis comentarios',
|
||||||
addComment: 'Añadir nuevo comentario',
|
addComment: 'Añadir nuevo comentario',
|
||||||
commentPlaceholder: 'Tu comentario',
|
commentPlaceholder: 'Tu comentario',
|
||||||
|
clientComments: 'Comentarios del cliente',
|
||||||
|
coachComments: 'Comentarios del entrenador'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Próximas salas',
|
upcoming: 'Próximas salas',
|
||||||
|
@ -84,6 +86,7 @@ export default {
|
||||||
fromTo: 'de $ a $',
|
fromTo: 'de $ a $',
|
||||||
apply: 'Solicitar',
|
apply: 'Solicitar',
|
||||||
save: 'Guardar',
|
save: 'Guardar',
|
||||||
|
edit: 'Editar',
|
||||||
changePass: 'Cambiar contraseña',
|
changePass: 'Cambiar contraseña',
|
||||||
resetPass: 'Restablecer contraseña',
|
resetPass: 'Restablecer contraseña',
|
||||||
getStarted: 'Empieza',
|
getStarted: 'Empieza',
|
||||||
|
@ -94,13 +97,22 @@ export default {
|
||||||
courseInfo: 'Información del curso',
|
courseInfo: 'Información del curso',
|
||||||
expertBackground: 'Antecedentes del experto',
|
expertBackground: 'Antecedentes del experto',
|
||||||
profCertification: 'Certificación profesional',
|
profCertification: 'Certificación profesional',
|
||||||
practiceHours: 'horas de práctica',
|
practiceHours: 'Horas de práctica',
|
||||||
supervisionCount: 'supervisiones anuales',
|
supervisionCount: 'Supervisiones anuales',
|
||||||
outOf: 'de',
|
outOf: 'de',
|
||||||
schedule: 'Horario',
|
schedule: 'Horario',
|
||||||
|
successfulCase: 'Casos de éxito de la práctica',
|
||||||
signUp: 'Regístrate ahora',
|
signUp: 'Regístrate ahora',
|
||||||
noData: 'Sin datos',
|
noData: 'Sin datos',
|
||||||
notFound: 'No encontrado',
|
notFound: 'No encontrado',
|
||||||
|
trainings: 'Formación',
|
||||||
|
seminars: 'Seminarios',
|
||||||
|
courses: 'Cursos',
|
||||||
|
mba: 'Información sobre máster en ADE (MBA)',
|
||||||
|
aboutCoach: 'Sobre el coach',
|
||||||
|
education: 'Educación',
|
||||||
|
coaching: 'Coaching',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
invalidEmail: 'La dirección de correo electrónico no es válida',
|
invalidEmail: 'La dirección de correo electrónico no es válida',
|
||||||
emptyEmail: 'Introduce tu correo electrónico',
|
emptyEmail: 'Introduce tu correo electrónico',
|
||||||
|
|
|
@ -4,9 +4,9 @@ export default {
|
||||||
notifications: 'Notification',
|
notifications: 'Notification',
|
||||||
support: 'Aide et support',
|
support: 'Aide et support',
|
||||||
information: 'Informations légales',
|
information: 'Informations légales',
|
||||||
settings: 'Paramètres du profil',
|
settings: 'Paramètres du compte',
|
||||||
messages: 'Messages',
|
messages: 'Messages',
|
||||||
'work-with-us': 'Travaillez avec nous'
|
'expert-profile': 'Profil de l\'expert'
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
'bb-client': 'Commencez à vous développer avec BB',
|
'bb-client': 'Commencez à vous développer avec BB',
|
||||||
|
@ -41,6 +41,8 @@ export default {
|
||||||
myComments: 'Mes commentaires',
|
myComments: 'Mes commentaires',
|
||||||
addComment: 'Ajouter un nouveau commentaire',
|
addComment: 'Ajouter un nouveau commentaire',
|
||||||
commentPlaceholder: 'Votre commentaire',
|
commentPlaceholder: 'Votre commentaire',
|
||||||
|
clientComments: 'Commentaires du client',
|
||||||
|
coachComments: 'Commentaires du coach'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Salles futures',
|
upcoming: 'Salles futures',
|
||||||
|
@ -84,6 +86,7 @@ export default {
|
||||||
fromTo: 'de $ à $',
|
fromTo: 'de $ à $',
|
||||||
apply: 'Appliquer',
|
apply: 'Appliquer',
|
||||||
save: 'Sauvegarder',
|
save: 'Sauvegarder',
|
||||||
|
edit: 'Modifier',
|
||||||
changePass: 'Modifier le mot de passe',
|
changePass: 'Modifier le mot de passe',
|
||||||
resetPass: 'Réinitialiser le mot de passe',
|
resetPass: 'Réinitialiser le mot de passe',
|
||||||
getStarted: 'Commencer',
|
getStarted: 'Commencer',
|
||||||
|
@ -94,13 +97,22 @@ export default {
|
||||||
courseInfo: 'Infos sur le cours',
|
courseInfo: 'Infos sur le cours',
|
||||||
expertBackground: 'Antécédents de l\'expert',
|
expertBackground: 'Antécédents de l\'expert',
|
||||||
profCertification: 'Certification professionnelle',
|
profCertification: 'Certification professionnelle',
|
||||||
practiceHours: 'heures de pratique',
|
practiceHours: 'Heures de pratique',
|
||||||
supervisionCount: 'Supervision par an',
|
supervisionCount: 'Supervision par an',
|
||||||
outOf: 'sur',
|
outOf: 'sur',
|
||||||
schedule: 'Programme',
|
schedule: 'Programme',
|
||||||
|
successfulCase: 'Cas réussis de la pratique',
|
||||||
signUp: 'Inscrivez-vous maintenant',
|
signUp: 'Inscrivez-vous maintenant',
|
||||||
noData: 'Aucune donnée',
|
noData: 'Aucune donnée',
|
||||||
notFound: 'Non trouvé',
|
notFound: 'Non trouvé',
|
||||||
|
trainings: 'Formations',
|
||||||
|
seminars: 'Séminaires',
|
||||||
|
courses: 'Cours',
|
||||||
|
mba: 'Infos Maîtrise en gestion',
|
||||||
|
aboutCoach: 'À propos du coach',
|
||||||
|
education: 'Éducation',
|
||||||
|
coaching: 'Coaching',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
invalidEmail: 'L\'adresse e-mail n\'est pas valide',
|
invalidEmail: 'L\'adresse e-mail n\'est pas valide',
|
||||||
emptyEmail: 'Veuillez saisir votre e-mail',
|
emptyEmail: 'Veuillez saisir votre e-mail',
|
||||||
|
|
|
@ -4,9 +4,9 @@ export default {
|
||||||
notifications: 'Notifica',
|
notifications: 'Notifica',
|
||||||
support: 'Assistenza e supporto',
|
support: 'Assistenza e supporto',
|
||||||
information: 'Informazioni legali',
|
information: 'Informazioni legali',
|
||||||
settings: 'Impostazioni profilo',
|
settings: 'Impostazioni account',
|
||||||
messages: 'Messaggi',
|
messages: 'Messaggi',
|
||||||
'work-with-us': 'Lavora con noi'
|
'expert-profile': 'Profilo dell\'esperto'
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
'bb-client': 'Inizia a crescere con BB',
|
'bb-client': 'Inizia a crescere con BB',
|
||||||
|
@ -41,6 +41,8 @@ export default {
|
||||||
myComments: 'I miei commenti',
|
myComments: 'I miei commenti',
|
||||||
addComment: 'Aggiungi nuovo commento',
|
addComment: 'Aggiungi nuovo commento',
|
||||||
commentPlaceholder: 'Il tuo commento',
|
commentPlaceholder: 'Il tuo commento',
|
||||||
|
clientComments: 'Commenti del cliente',
|
||||||
|
coachComments: 'Commenti dell\'allenatore'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Prossime sale',
|
upcoming: 'Prossime sale',
|
||||||
|
@ -84,6 +86,7 @@ export default {
|
||||||
fromTo: 'da $ a $',
|
fromTo: 'da $ a $',
|
||||||
apply: 'Applica',
|
apply: 'Applica',
|
||||||
save: 'Salva',
|
save: 'Salva',
|
||||||
|
edit: 'Modifica',
|
||||||
changePass: 'Cambia password',
|
changePass: 'Cambia password',
|
||||||
resetPass: 'Reimposta password',
|
resetPass: 'Reimposta password',
|
||||||
getStarted: 'Inizia',
|
getStarted: 'Inizia',
|
||||||
|
@ -94,13 +97,22 @@ export default {
|
||||||
courseInfo: 'Informazioni sul corso',
|
courseInfo: 'Informazioni sul corso',
|
||||||
expertBackground: 'Background esperto',
|
expertBackground: 'Background esperto',
|
||||||
profCertification: 'Certificazione professionale',
|
profCertification: 'Certificazione professionale',
|
||||||
practiceHours: 'ore di pratica',
|
practiceHours: 'Ore di pratica',
|
||||||
supervisionCount: 'supervisioni per anno',
|
supervisionCount: 'Supervisioni per anno',
|
||||||
outOf: 'su',
|
outOf: 'su',
|
||||||
schedule: 'Programma',
|
schedule: 'Programma',
|
||||||
|
successfulCase: 'Casi di successo dalla pratica',
|
||||||
signUp: 'Iscriviti ora',
|
signUp: 'Iscriviti ora',
|
||||||
noData: 'Nessun dato',
|
noData: 'Nessun dato',
|
||||||
notFound: 'Non trovato',
|
notFound: 'Non trovato',
|
||||||
|
trainings: 'Training',
|
||||||
|
seminars: 'Seminari',
|
||||||
|
courses: 'Corsi',
|
||||||
|
mba: 'Info sull\'MBA',
|
||||||
|
aboutCoach: 'Informazioni sul coach',
|
||||||
|
education: 'Istruzione',
|
||||||
|
coaching: 'Coaching',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
invalidEmail: 'L\'indirizzo e-mail non è valido',
|
invalidEmail: 'L\'indirizzo e-mail non è valido',
|
||||||
emptyEmail: 'Inserisci l\'e-mail',
|
emptyEmail: 'Inserisci l\'e-mail',
|
||||||
|
|
|
@ -4,9 +4,9 @@ export default {
|
||||||
notifications: 'Уведомления',
|
notifications: 'Уведомления',
|
||||||
support: 'Служба поддержки',
|
support: 'Служба поддержки',
|
||||||
information: 'Юридическая информация',
|
information: 'Юридическая информация',
|
||||||
settings: 'Настройки профиля',
|
settings: 'Настройки учетной записи',
|
||||||
messages: 'Сообщения',
|
messages: 'Сообщения',
|
||||||
'work-with-us': 'Сотрудничество'
|
'expert-profile': 'Профиль эксперта'
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
'bb-client': 'Начните свой рост с BB',
|
'bb-client': 'Начните свой рост с BB',
|
||||||
|
@ -41,6 +41,8 @@ export default {
|
||||||
myComments: 'Мои комментарии',
|
myComments: 'Мои комментарии',
|
||||||
addComment: 'Добавить новый',
|
addComment: 'Добавить новый',
|
||||||
commentPlaceholder: 'Ваш комментарий',
|
commentPlaceholder: 'Ваш комментарий',
|
||||||
|
clientComments: 'Комментарии клиента',
|
||||||
|
coachComments: 'Комментарии коуча'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Предстоящие комнаты',
|
upcoming: 'Предстоящие комнаты',
|
||||||
|
@ -84,6 +86,7 @@ export default {
|
||||||
fromTo: 'от $ до $',
|
fromTo: 'от $ до $',
|
||||||
apply: 'Применить',
|
apply: 'Применить',
|
||||||
save: 'Сохранить',
|
save: 'Сохранить',
|
||||||
|
edit: 'Редактировать',
|
||||||
changePass: 'Изменить пароль',
|
changePass: 'Изменить пароль',
|
||||||
resetPass: 'Сбросить пароль',
|
resetPass: 'Сбросить пароль',
|
||||||
getStarted: 'Начать работу',
|
getStarted: 'Начать работу',
|
||||||
|
@ -94,13 +97,22 @@ export default {
|
||||||
courseInfo: 'Информация о курсе',
|
courseInfo: 'Информация о курсе',
|
||||||
expertBackground: 'Профессиональный опыт эксперта',
|
expertBackground: 'Профессиональный опыт эксперта',
|
||||||
profCertification: 'Профессиональная сертификация',
|
profCertification: 'Профессиональная сертификация',
|
||||||
practiceHours: 'часов практики',
|
practiceHours: 'Часов практики',
|
||||||
supervisionCount: 'часов супервизии в год',
|
supervisionCount: 'Часов супервизии в год',
|
||||||
outOf: 'из',
|
outOf: 'из',
|
||||||
schedule: 'Расписание',
|
schedule: 'Расписание',
|
||||||
|
successfulCase: 'Успешные случаи из практики',
|
||||||
signUp: 'Записаться сейчас',
|
signUp: 'Записаться сейчас',
|
||||||
noData: 'Нет данных',
|
noData: 'Нет данных',
|
||||||
notFound: 'Не найдено',
|
notFound: 'Не найдено',
|
||||||
|
trainings: 'Тренинги',
|
||||||
|
seminars: 'Семинары',
|
||||||
|
courses: 'Курсы',
|
||||||
|
mba: 'Информация о MBA',
|
||||||
|
aboutCoach: 'О коуче',
|
||||||
|
education: 'Образование',
|
||||||
|
coaching: 'Коучинг',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
invalidEmail: 'Адрес электронной почты недействителен',
|
invalidEmail: 'Адрес электронной почты недействителен',
|
||||||
emptyEmail: 'Пожалуйста, введите ваш E-mail',
|
emptyEmail: 'Пожалуйста, введите ваш E-mail',
|
||||||
|
|
|
@ -12,7 +12,10 @@ export const onSuccessRequestCallback = (config: InternalAxiosRequestConfig) =>
|
||||||
// if (IS_DEV && !newConfig.headers.Authorization && getAuthToken()) {
|
// if (IS_DEV && !newConfig.headers.Authorization && getAuthToken()) {
|
||||||
// newConfig.headers.Authorization = `Bearer ${getAuthToken()}`;
|
// newConfig.headers.Authorization = `Bearer ${getAuthToken()}`;
|
||||||
// }
|
// }
|
||||||
newConfig.headers['Content-Type'] = 'application/json';
|
|
||||||
|
if (!newConfig.headers['Content-Type']) {
|
||||||
|
newConfig.headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
return newConfig;
|
return newConfig;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,21 @@ body{
|
||||||
--font: var(--font-comfortaa), -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
--font: var(--font-comfortaa), -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
font-family: var(--font);
|
font-family: var(--font);
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
|
|
||||||
|
& * {
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #C4DFE6;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #2C7873;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
|
|
|
@ -32,6 +32,55 @@
|
||||||
padding: 44px 40px;
|
padding: 44px 40px;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__expert {
|
||||||
|
&__title {
|
||||||
|
color: #003B46;
|
||||||
|
@include rem(20);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 133.333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__inner {
|
||||||
|
height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-right: 20px;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 40px;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
.title-h4 {
|
||||||
|
color: #003B46;
|
||||||
|
@include rem(16);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 150%;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-modal-mask {
|
.ant-modal-mask {
|
||||||
|
|
|
@ -1140,15 +1140,13 @@
|
||||||
height: 146px;
|
height: 146px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.coaching-info {
|
.coaching-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 24px;
|
gap: 16px;
|
||||||
margin-bottom: 24px;
|
|
||||||
|
|
||||||
.card-profile {
|
.card-profile {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
|
@ -1172,9 +1170,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
flex-flow: nowrap;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
&__wrap-btn {
|
&__wrap-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
@ -1183,8 +1178,66 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coaching-profile {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
&__portrait {
|
||||||
|
width: 86px;
|
||||||
|
height: 86px;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 2px solid #FFF;
|
||||||
|
background: lightgray 50%;
|
||||||
|
box-shadow: 0 8px 16px 0 rgba(102, 165, 173, 0.32);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__inner {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
color: #003B46;
|
||||||
|
@include rem(18);
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 150%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.coaching-section {
|
.coaching-section {
|
||||||
margin-bottom: 24px;
|
&__wrap {
|
||||||
|
border-top: 1px solid #C4DFE6;
|
||||||
|
padding-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-self: center;
|
||||||
|
|
||||||
|
.b-button__link {
|
||||||
|
height: 24px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-h2 {
|
||||||
|
color: #003B46;
|
||||||
|
@include rem(18);
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.base-text {
|
.base-text {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { ExpertDocument } from './file';
|
||||||
|
|
||||||
|
export type Details = {
|
||||||
|
id: number;
|
||||||
|
userId?:number;
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
document?: ExpertDocument;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Certificate = {
|
||||||
|
id: number;
|
||||||
|
userId?: number;
|
||||||
|
associationLevelId?: number;
|
||||||
|
document?: ExpertDocument;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Experience = {
|
||||||
|
id: number,
|
||||||
|
userId?: number,
|
||||||
|
title?: string,
|
||||||
|
description?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Association = {
|
||||||
|
id: number;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AssociationLevel = Association & { associationId?: number };
|
||||||
|
|
||||||
|
export type EducationData = {
|
||||||
|
certificates?: Certificate[],
|
||||||
|
educations?: Details[],
|
||||||
|
trainings?: Details[],
|
||||||
|
mbas?: Details[],
|
||||||
|
experiences?: Experience[]
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface EducationDTO {
|
||||||
|
person2Data?: EducationData,
|
||||||
|
associations?: Association[],
|
||||||
|
associationLevels?: AssociationLevel[]
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import { Tag, ThemeGroups } from './tags';
|
import { Tag, ThemeGroups } from './tags';
|
||||||
|
import { Association, AssociationLevel, EducationData } from './education';
|
||||||
|
|
||||||
export type GeneralFilter = Filter & AdditionalFilter;
|
export type GeneralFilter = Filter & AdditionalFilter;
|
||||||
|
|
||||||
|
@ -19,34 +20,6 @@ export type AdditionalFilter = {
|
||||||
coachSort?: string;
|
coachSort?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type File = {
|
|
||||||
id: number;
|
|
||||||
fileType: string;
|
|
||||||
url: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface ExpertDocument {
|
|
||||||
fileName: string;
|
|
||||||
original?: File;
|
|
||||||
preview?: File;
|
|
||||||
fullSize?: File;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Details = {
|
|
||||||
id: number;
|
|
||||||
userId?:number;
|
|
||||||
title?: string;
|
|
||||||
description?: string;
|
|
||||||
document?: ExpertDocument;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Certificate = {
|
|
||||||
id: number;
|
|
||||||
userId?: number;
|
|
||||||
associationLevelId?: number;
|
|
||||||
document?: ExpertDocument;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Practice = {
|
export type Practice = {
|
||||||
id: number;
|
id: number;
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
@ -61,16 +34,6 @@ export type ThemeGroup = {
|
||||||
canDeleted?: boolean;
|
canDeleted?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Association = {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AssociationLevel = {
|
|
||||||
id: number;
|
|
||||||
associationId: number;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface ExpertItem {
|
export interface ExpertItem {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -98,14 +61,9 @@ export type ExpertsData = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ExpertDetails = {
|
export type ExpertDetails = {
|
||||||
publicCoachDetails: ExpertItem & {
|
publicCoachDetails: ExpertItem & EducationData & {
|
||||||
practiceHours?: number;
|
practiceHours?: number;
|
||||||
supervisionPerYearId?: number;
|
supervisionPerYearId?: number;
|
||||||
educations?: Details[];
|
|
||||||
certificates?: Certificate[];
|
|
||||||
trainings?: Details[];
|
|
||||||
mbas?: Details[];
|
|
||||||
experiences?: Details[];
|
|
||||||
practiceCases?: Practice[];
|
practiceCases?: Practice[];
|
||||||
themesGroups?: ThemeGroup[];
|
themesGroups?: ThemeGroup[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
export type File = {
|
||||||
|
id: number;
|
||||||
|
fileType: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ExpertDocument {
|
||||||
|
fileName: string;
|
||||||
|
original?: File;
|
||||||
|
preview?: File;
|
||||||
|
fullSize?: File;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { ExpertsThemesGroups } from './tags';
|
||||||
|
|
||||||
|
export type Supervision = {
|
||||||
|
id: number,
|
||||||
|
name: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PracticeCase = {
|
||||||
|
id: number,
|
||||||
|
userId?: number,
|
||||||
|
description?: string,
|
||||||
|
themesGroupIds?: number[]
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PracticeData = {
|
||||||
|
practiceHours?: number,
|
||||||
|
supervisionPerYearId?: number,
|
||||||
|
sessionDuration?: number,
|
||||||
|
sessionCost?: number,
|
||||||
|
practiceCases?: PracticeCase[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PracticeDTO {
|
||||||
|
person4Data: PracticeData & {
|
||||||
|
themesGroups?: ExpertsThemesGroups[],
|
||||||
|
supervisionPerYears?: Supervision[],
|
||||||
|
sessionCosts?: number[]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
export type Profile = {
|
import { UploadFile } from 'antd';
|
||||||
id: number;
|
import {EducationDTO} from "./education";
|
||||||
|
import {ExpertsTags} from "./tags";
|
||||||
|
import {PracticeDTO} from "./practice";
|
||||||
|
import {ScheduleDTO} from "./schedule";
|
||||||
|
|
||||||
|
export type ProfileData = {
|
||||||
username?: string;
|
username?: string;
|
||||||
surname?: string;
|
surname?: string;
|
||||||
fillProgress?: string;
|
fillProgress?: string;
|
||||||
|
@ -9,4 +14,35 @@ export type Profile = {
|
||||||
hasPassword?: boolean;
|
hasPassword?: boolean;
|
||||||
hasExternalLogin?: boolean;
|
hasExternalLogin?: boolean;
|
||||||
isTestMode?: boolean;
|
isTestMode?: boolean;
|
||||||
|
phone?: string;
|
||||||
|
languagesLinks?: { language: { id: number, code: string, nativeSpelling: string }, languageId: number }[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Profile = ProfileData & { id: number };
|
||||||
|
|
||||||
|
export type ProfileRequest = {
|
||||||
|
login?: string;
|
||||||
|
password?: string;
|
||||||
|
isPasswordKeepExisting?: boolean;
|
||||||
|
languagesLinks?: { languageId: number }[];
|
||||||
|
username?: string;
|
||||||
|
surname?: string;
|
||||||
|
faceImage?: UploadFile;
|
||||||
|
isFaceImageKeepExisting?: boolean;
|
||||||
|
phone?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PayInfo = {
|
||||||
|
beneficiaryName?: string,
|
||||||
|
iban?: string,
|
||||||
|
bicOrSwift?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ExpertData {
|
||||||
|
person?: ProfileData,
|
||||||
|
education?: EducationDTO,
|
||||||
|
tags?: ExpertsTags,
|
||||||
|
practice?: PracticeDTO,
|
||||||
|
schedule?: ScheduleDTO,
|
||||||
|
payData?: { person6Data?: PayInfo },
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
export type WorkingTime = {
|
||||||
|
startDayOfWeekUtc?: string,
|
||||||
|
startTimeUtc?: number,
|
||||||
|
endDayOfWeekUtc?: string,
|
||||||
|
endTimeUtc?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScheduleDTO {
|
||||||
|
workingTimes?: WorkingTime[]
|
||||||
|
}
|
|
@ -4,6 +4,9 @@ export type Tag = {
|
||||||
name: string
|
name: string
|
||||||
couchCount?: number;
|
couchCount?: number;
|
||||||
group?: string | null;
|
group?: string | null;
|
||||||
|
isActive?: boolean,
|
||||||
|
isSelected?: boolean,
|
||||||
|
canDeleted?: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ThemeGroups = {
|
export type ThemeGroups = {
|
||||||
|
@ -27,3 +30,15 @@ export type Language = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Languages = Language[];
|
export type Languages = Language[];
|
||||||
|
|
||||||
|
export type ExpertsThemesGroups = {
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
isActive?: boolean,
|
||||||
|
canDeleted?: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ExpertsTags {
|
||||||
|
themesGroups?: ExpertsThemesGroups[],
|
||||||
|
themesTags?: Tag[]
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { message } from 'antd';
|
||||||
|
import type { UploadFile } from 'antd';
|
||||||
import { i18nText } from '../i18nKeys';
|
import { i18nText } from '../i18nKeys';
|
||||||
|
|
||||||
const ROUTES = ['sessions', 'notifications', 'support', 'information', 'settings', 'messages', 'work-with-us'];
|
const ROUTES = ['sessions', 'notifications', 'support', 'information', 'settings', 'messages', 'expert-profile'];
|
||||||
const COUNTS: Record<string, number> = {
|
const COUNTS: Record<string, number> = {
|
||||||
sessions: 12,
|
sessions: 12,
|
||||||
notifications: 5,
|
notifications: 5,
|
||||||
|
@ -12,3 +14,17 @@ export const getMenuConfig = (locale: string) => ROUTES.map((path) => ({
|
||||||
title: i18nText(`accountMenu.${path}`, locale),
|
title: i18nText(`accountMenu.${path}`, locale),
|
||||||
count: COUNTS[path] || undefined
|
count: COUNTS[path] || undefined
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const validateImage = (file: UploadFile, showMessage?: boolean): boolean => {
|
||||||
|
const isImage = file.type === 'image/jpg' || file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif';
|
||||||
|
if (!isImage && showMessage) {
|
||||||
|
message.error('You can only upload JPG/PNG file');
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLt5M = file.size / 1024 / 1024 <= 5;
|
||||||
|
if (!isLt5M && showMessage) {
|
||||||
|
message.error('Image must smaller than 5MB');
|
||||||
|
}
|
||||||
|
|
||||||
|
return isImage && isLt5M;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue