feat: update views, styles, actions
This commit is contained in:
parent
59de68d611
commit
d5808e96db
|
@ -1,6 +1,5 @@
|
||||||
import { apiRequest } from './helpers';
|
import { apiRequest } from './helpers';
|
||||||
import { apiClient } from '../lib/apiClient';
|
import { GeneralFilter, ExpertsData, ExpertDetails, ExpertScheduler, ExpertSchedulerSession, SignupSessionData } from '../types/experts';
|
||||||
import {GeneralFilter, ExpertsData, ExpertDetails, ExpertScheduler, ExpertSchedulerSession} from '../types/experts';
|
|
||||||
|
|
||||||
export const getExpertsList = (locale: string, filter?: GeneralFilter): Promise<ExpertsData> => apiRequest({
|
export const getExpertsList = (locale: string, filter?: GeneralFilter): Promise<ExpertsData> => apiRequest({
|
||||||
url: '/home/coachsearch1',
|
url: '/home/coachsearch1',
|
||||||
|
@ -16,32 +15,17 @@ export const getExpertById = (id: string, locale: string): Promise<ExpertDetails
|
||||||
locale
|
locale
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getSchedulerByExpertId = async (expertId: string, locale: string, jwt: string) => {
|
export const getSchedulerByExpertId = (id: string, locale: string): Promise<ExpertScheduler> => apiRequest({
|
||||||
const response = await apiClient.post(
|
url: '/home/sessionsignupdata',
|
||||||
'/home/sessionsignupdata',
|
method: 'post',
|
||||||
{ id: expertId },
|
data: { id },
|
||||||
{
|
locale
|
||||||
headers: {
|
});
|
||||||
'X-User-Language': locale,
|
|
||||||
Authorization: `Bearer ${jwt}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return response.data as ExpertScheduler || null;
|
export const getSchedulerSession = (data: SignupSessionData, locale: string, token: string): Promise<ExpertSchedulerSession> => apiRequest({
|
||||||
};
|
url: '/home/sessionsignupsubmit',
|
||||||
|
method: 'post',
|
||||||
export const getSchedulerSession = async (data: { coachId: number, tagId: number, startAtUtc: string, clientComment: string }, locale: string, jwt: string) => {
|
data,
|
||||||
const response = await apiClient.post(
|
locale,
|
||||||
'/home/sessionsignupsubmit',
|
token
|
||||||
data,
|
});
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'X-User-Language': locale,
|
|
||||||
Authorization: `Bearer ${jwt}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return response.data as ExpertSchedulerSession || null;
|
|
||||||
};
|
|
||||||
|
|
|
@ -6,13 +6,11 @@ import { getExpertById, getExpertsList } from '../../../../actions/experts';
|
||||||
import {
|
import {
|
||||||
ExpertCard,
|
ExpertCard,
|
||||||
ExpertCertificate,
|
ExpertCertificate,
|
||||||
ExpertInformation,
|
|
||||||
ExpertPractice
|
ExpertPractice
|
||||||
} from '../../../../components/Experts/ExpertDetails';
|
} from '../../../../components/Experts/ExpertDetails';
|
||||||
import { Details } from '../../../../types/education';
|
import { Details } from '../../../../types/education';
|
||||||
import { BackButton } from '../../../../components/view/BackButton';
|
import { BackButton } from '../../../../components/view/BackButton';
|
||||||
import { i18nText } from '../../../../i18nKeys';
|
import { i18nText } from '../../../../i18nKeys';
|
||||||
import {SchedulerModal} from "../../../../components/Modals/SchedulerModal";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Bbuddy - Experts item',
|
title: 'Bbuddy - Experts item',
|
||||||
|
@ -84,7 +82,6 @@ export default async function ExpertItem({ params: { expertId = '', locale } }:
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
<ExpertCard expert={expert} locale={locale} expertId={expertId}/>
|
<ExpertCard expert={expert} locale={locale} expertId={expertId}/>
|
||||||
<ExpertInformation expert={expert} locale={locale} />
|
|
||||||
|
|
||||||
<h2 className="title-h2">{i18nText('expertBackground', locale)}</h2>
|
<h2 className="title-h2">{i18nText('expertBackground', locale)}</h2>
|
||||||
<p className="base-text">
|
<p className="base-text">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import {Alert, message} from 'antd';
|
import { Alert, message } from 'antd';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { i18nText } from '../../i18nKeys';
|
import { i18nText } from '../../i18nKeys';
|
||||||
import { ExpertData, PayInfo, ProfileData } from '../../types/profile';
|
import { ExpertData, PayInfo, ProfileData } from '../../types/profile';
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, {FC, useEffect, useState} from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { Tag, Image as AntdImage, Space } from 'antd';
|
import { Tag, Image as AntdImage, Space, Button } from 'antd';
|
||||||
import { ZoomInOutlined, ZoomOutOutlined, StarFilled } from '@ant-design/icons';
|
import { ZoomInOutlined, ZoomOutOutlined, StarFilled } from '@ant-design/icons';
|
||||||
import { ExpertScheduler } from '../../types/experts';
|
import { ExpertScheduler } from '../../types/experts';
|
||||||
import { ExpertDetails, Practice, ThemeGroup } from '../../types/experts';
|
import { ExpertDetails, Practice, ThemeGroup } from '../../types/experts';
|
||||||
|
@ -15,7 +15,7 @@ import {getSchedulerByExpertId} from "../../actions/experts";
|
||||||
import {useLocalStorage} from "../../hooks/useLocalStorage";
|
import {useLocalStorage} from "../../hooks/useLocalStorage";
|
||||||
import {AUTH_TOKEN_KEY} from "../../constants/common";
|
import {AUTH_TOKEN_KEY} from "../../constants/common";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {SchedulerModal} from "../Modals/SchedulerModal";
|
import {ScheduleModal} from "../Modals/ScheduleModal";
|
||||||
|
|
||||||
type ExpertDetailsProps = {
|
type ExpertDetailsProps = {
|
||||||
expert: ExpertDetails;
|
expert: ExpertDetails;
|
||||||
|
@ -33,65 +33,47 @@ export const ExpertCard: FC<ExpertDetailsProps> = ({ expert, locale, expertId })
|
||||||
const { publicCoachDetails } = expert || {};
|
const { publicCoachDetails } = expert || {};
|
||||||
const [showSchedulerModal, setShowSchedulerModal] = useState<boolean>(false);
|
const [showSchedulerModal, setShowSchedulerModal] = useState<boolean>(false);
|
||||||
const [mode, setMode] = useState<'data' | 'time' | 'pay' | 'finish'>('data');
|
const [mode, setMode] = useState<'data' | 'time' | 'pay' | 'finish'>('data');
|
||||||
const { publicCoachDetails: { tags = [], sessionCost = 0, sessionDuration = 0 } } = expert || {};
|
|
||||||
|
|
||||||
const onSchedulerHandle = async () => {
|
|
||||||
console.log('sessionCost', sessionCost);
|
|
||||||
setMode('data');
|
|
||||||
setShowSchedulerModal(true)
|
|
||||||
// отмаппим.
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="expert-card">
|
|
||||||
<div className="expert-card__wrap">
|
|
||||||
<div className="expert-card__avatar">
|
|
||||||
<Image src={publicCoachDetails?.faceImageUrl || '/images/person.png'} width={216} height={216} alt="" />
|
|
||||||
</div>
|
|
||||||
<div className="expert-card__inner">
|
|
||||||
<h1 className="expert-card__title">{`${publicCoachDetails?.name} ${publicCoachDetails?.surname || ''}`}</h1>
|
|
||||||
<div className="expert-card__info">
|
|
||||||
<span>{`${publicCoachDetails?.practiceHours} ${i18nText('practiceHours', locale)}`}</span>
|
|
||||||
<i>|</i>
|
|
||||||
<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 (${i18nText('outOf', locale)} 345)`}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="expert-card__wrap-btn">
|
|
||||||
<a href="#" className="btn-apply" onClick={onSchedulerHandle}>
|
|
||||||
<img src="/images/calendar-outline.svg" className="" alt="" />
|
|
||||||
{i18nText('schedule', locale)}
|
|
||||||
</a>
|
|
||||||
{/*
|
|
||||||
<a href="#" className="btn-video">
|
|
||||||
<img src="/images/videocam-outline.svg" className="" alt=""/>
|
|
||||||
Video
|
|
||||||
</a>
|
|
||||||
*/}
|
|
||||||
</div>
|
|
||||||
<SchedulerModal
|
|
||||||
open={showSchedulerModal}
|
|
||||||
handleCancel={() => setShowSchedulerModal(false)}
|
|
||||||
updateMode={setMode}
|
|
||||||
mode={mode}
|
|
||||||
expertId={expertId as string}
|
|
||||||
locale={locale as string}
|
|
||||||
sessionCost={sessionCost}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ExpertInformation: FC<ExpertDetailsProps> = ({ expert, locale }) => {
|
|
||||||
const { publicCoachDetails: { tags = [], sessionCost = 0, sessionDuration = 0, coachLanguages = [] } } = expert || {};
|
const { publicCoachDetails: { tags = [], sessionCost = 0, sessionDuration = 0, coachLanguages = [] } } = expert || {};
|
||||||
const isRus = locale === Locale.ru;
|
const isRus = locale === Locale.ru;
|
||||||
|
|
||||||
|
const onSchedulerHandle = () => {
|
||||||
|
setMode('data');
|
||||||
|
setShowSchedulerModal(true)
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="expert-card">
|
||||||
|
<div className="expert-card__wrap">
|
||||||
|
<div className="expert-card__avatar">
|
||||||
|
<Image src={publicCoachDetails?.faceImageUrl || '/images/person.png'} width={216} height={216} alt="" />
|
||||||
|
</div>
|
||||||
|
<div className="expert-card__inner">
|
||||||
|
<h1 className="expert-card__title">{`${publicCoachDetails?.name} ${publicCoachDetails?.surname || ''}`}</h1>
|
||||||
|
<div className="expert-card__info">
|
||||||
|
<span>{`${publicCoachDetails?.practiceHours} ${i18nText('practiceHours', locale)}`}</span>
|
||||||
|
<i>|</i>
|
||||||
|
<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 (${i18nText('outOf', locale)} 345)`}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="expert-card__wrap-btn">
|
||||||
|
<Button className="btn-apply" onClick={onSchedulerHandle}>
|
||||||
|
<img src="/images/calendar-outline.svg" className="" alt="" />
|
||||||
|
{i18nText('schedule', locale)}
|
||||||
|
</Button>
|
||||||
|
{/*
|
||||||
|
<a href="#" className="btn-video">
|
||||||
|
<img src="/images/videocam-outline.svg" className="" alt=""/>
|
||||||
|
Video
|
||||||
|
</a>
|
||||||
|
*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="expert-info">
|
<div className="expert-info">
|
||||||
{/* <h2 className="title-h2">{}</h2> */}
|
{/* <h2 className="title-h2">{}</h2> */}
|
||||||
<div className="skills__list">
|
<div className="skills__list">
|
||||||
|
@ -117,11 +99,20 @@ export const ExpertInformation: FC<ExpertDetailsProps> = ({ expert, locale }) =>
|
||||||
{tags?.map((skill) => <Tag key={skill?.id} className="skills__list__item">{skill?.name}</Tag>)}
|
{tags?.map((skill) => <Tag key={skill?.id} className="skills__list__item">{skill?.name}</Tag>)}
|
||||||
</div>
|
</div>
|
||||||
<div className="wrap-btn-prise">
|
<div className="wrap-btn-prise">
|
||||||
<FilledYellowButton onClick={() => console.log('schedule')}>{i18nText('signUp', locale)}</FilledYellowButton>
|
<FilledYellowButton onClick={onSchedulerHandle}>{i18nText('signUp', locale)}</FilledYellowButton>
|
||||||
<div className="wrap-btn-prise__text">
|
<div className="wrap-btn-prise__text">
|
||||||
{`${sessionCost}€`} <span>/ {`${sessionDuration}${isRus ? 'мин' : 'min'}`}</span>
|
{`${sessionCost}€`} <span>/ {`${sessionDuration}${isRus ? 'мин' : 'min'}`}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ScheduleModal
|
||||||
|
open={showSchedulerModal}
|
||||||
|
handleCancel={() => setShowSchedulerModal(false)}
|
||||||
|
updateMode={setMode}
|
||||||
|
mode={mode}
|
||||||
|
expertId={expertId as string}
|
||||||
|
locale={locale as string}
|
||||||
|
sessionCost={sessionCost}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { FC, useEffect, useState } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Modal, Menu, Calendar, Radio, Button, Input, message } from 'antd';
|
||||||
|
import type { CalendarProps, RadioChangeEvent, MenuProps } from 'antd';
|
||||||
|
import { ArrowLeftOutlined } from '@ant-design/icons';
|
||||||
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
|
import locale_ru from 'antd/lib/calendar/locale/ru_RU';
|
||||||
|
import locale_en from 'antd/lib/calendar/locale/en_GB';
|
||||||
|
import locale_de from 'antd/lib/calendar/locale/de_DE';
|
||||||
|
import locale_it from 'antd/lib/calendar/locale/it_IT';
|
||||||
|
import locale_es from 'antd/lib/calendar/locale/es_ES';
|
||||||
|
import locale_fr from 'antd/lib/calendar/locale/fr_FR';
|
||||||
|
import { RegisterContent, ResetContent, FinishContent, EnterContent } from './authModalContent';
|
||||||
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
|
import 'dayjs/locale/ru';
|
||||||
|
import 'dayjs/locale/en';
|
||||||
|
import 'dayjs/locale/de';
|
||||||
|
import 'dayjs/locale/it';
|
||||||
|
import 'dayjs/locale/fr';
|
||||||
|
import 'dayjs/locale/es';
|
||||||
|
import { ExpertScheduler, SignupSessionData } from "../../types/experts";
|
||||||
|
import { Tag } from "../../types/tags";
|
||||||
|
import { useLocalStorage } from "../../hooks/useLocalStorage";
|
||||||
|
import { AUTH_TOKEN_KEY } from "../../constants/common";
|
||||||
|
import { getSchedulerByExpertId, getSchedulerSession } from "../../actions/experts";
|
||||||
|
import { ElementsForm } from "../stripe/ElementsForm";
|
||||||
|
import { i18nText } from '../../i18nKeys';
|
||||||
|
import { CustomSelect } from '../../components/view/CustomSelect';
|
||||||
|
|
||||||
|
type ScheduleModalProps = {
|
||||||
|
open: boolean;
|
||||||
|
handleCancel: () => void;
|
||||||
|
mode: 'data' | 'time' | 'pay' | 'finish';
|
||||||
|
updateMode: (mode: 'data' | 'time' | 'pay' | 'finish') => void;
|
||||||
|
sessionCost: number;
|
||||||
|
expertId: string;
|
||||||
|
locale: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type MenuItem = Required<MenuProps>['items'][number];
|
||||||
|
|
||||||
|
const getLocale = (locale: string) => {
|
||||||
|
if (locale) {
|
||||||
|
switch (locale) {
|
||||||
|
case 'ru':
|
||||||
|
return locale_ru;
|
||||||
|
case 'de':
|
||||||
|
return locale_de;
|
||||||
|
case 'fr':
|
||||||
|
return locale_fr;
|
||||||
|
case 'it':
|
||||||
|
return locale_it;
|
||||||
|
case 'es':
|
||||||
|
return locale_es;
|
||||||
|
default:
|
||||||
|
return locale_en;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return locale_en;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCalendarMenu = (start: Dayjs): MenuItem[] => Array.from({ length: 3 })
|
||||||
|
.map((_: unknown, index: number) => {
|
||||||
|
const date = index ? start.add(index, 'M') : start.clone();
|
||||||
|
return {
|
||||||
|
label: <span className="b-calendar-month">{date.format('MMMM')}</span>,
|
||||||
|
key: date.format('YYYY-MM-DD')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ScheduleModal: FC<ScheduleModalProps> = ({
|
||||||
|
open,
|
||||||
|
handleCancel,
|
||||||
|
mode,
|
||||||
|
updateMode,
|
||||||
|
sessionCost,
|
||||||
|
locale,
|
||||||
|
expertId,
|
||||||
|
}) => {
|
||||||
|
const [selectDate, setSelectDate] = useState<Dayjs>(dayjs());
|
||||||
|
const [dates, setDates] = useState<any>();
|
||||||
|
const [tags, setTags] = useState<Tag[] | undefined>();
|
||||||
|
const [sessionData, setSesssionData] = useState<SignupSessionData>({ coachId: +expertId });
|
||||||
|
const [sessionId, setSessionId] = useState<number>(-1);
|
||||||
|
const [rawScheduler, setRawScheduler] = useState<ExpertScheduler | null>(null);
|
||||||
|
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
||||||
|
const [isPayLoading, setIsPayLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
|
dayjs.locale(locale);
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
if (open) {
|
||||||
|
getSchedulerByExpertId(expertId as string, locale as string)
|
||||||
|
.then((data) => {
|
||||||
|
setRawScheduler(data);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const map = {} as any
|
||||||
|
rawScheduler?.availableSlots.forEach((el) => {
|
||||||
|
const key = dayjs(el.startTime).format('YYYY-MM-DD');
|
||||||
|
if (!map[key]){
|
||||||
|
map[key] = []
|
||||||
|
}
|
||||||
|
map[key].push(el);
|
||||||
|
})
|
||||||
|
setDates(map);
|
||||||
|
setTags(rawScheduler?.tags)
|
||||||
|
}, [rawScheduler]);
|
||||||
|
|
||||||
|
const onPanelChange = (value: Dayjs) => setSelectDate(value);
|
||||||
|
|
||||||
|
const onDateChange: CalendarProps<Dayjs>['onSelect'] = (value, selectInfo) => {
|
||||||
|
if (selectInfo.source === 'date') {
|
||||||
|
setSelectDate(value);
|
||||||
|
updateMode('time');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const disabledDate = (currentDate: Dayjs) => !dates || !dates[currentDate.format('YYYY-MM-DD')];
|
||||||
|
|
||||||
|
const onChangeTimeSlot = (e: RadioChangeEvent) => setSesssionData({ ...sessionData, startAtUtc: e.target.value.startTime });
|
||||||
|
|
||||||
|
const onChangeTag = (tagId: number) => setSesssionData({ ...sessionData, tagId });
|
||||||
|
|
||||||
|
const singupSession = () => {
|
||||||
|
console.log(sessionData);
|
||||||
|
if (sessionData?.startAtUtc && sessionData?.tagId) {
|
||||||
|
if (jwt) {
|
||||||
|
setIsPayLoading(true);
|
||||||
|
getSchedulerSession(sessionData, locale, jwt)
|
||||||
|
.then((session) => {
|
||||||
|
console.log(session);
|
||||||
|
// тут должна быть проверка все ли с регистрацией сессии
|
||||||
|
setSessionId(+session?.sessionId);
|
||||||
|
updateMode('pay');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
message.error('Не удалось провести оплату')
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsPayLoading(false);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cellRender: CalendarProps<Dayjs>['fullCellRender'] = (date, info) => {
|
||||||
|
const isWeekend = date.day() === 6 || date.day() === 0;
|
||||||
|
return React.cloneElement(info.originNode, {
|
||||||
|
...info.originNode.props,
|
||||||
|
className: classNames('b-calendar-cell', {
|
||||||
|
['b-calendar-cell__select']: selectDate.isSame(date, 'date'),
|
||||||
|
['b-calendar-cell__today']: date.isSame(dayjs(), 'date'),
|
||||||
|
['b-calendar-cell__weekend']: isWeekend,
|
||||||
|
}),
|
||||||
|
children: (
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
{date.get('date')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="b-modal"
|
||||||
|
open={open}
|
||||||
|
title={undefined}
|
||||||
|
onOk={undefined}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
footer={false}
|
||||||
|
width={498}
|
||||||
|
closeIcon={<CloseOutlined style={{ fontSize: 20, color: '#000' }}/>}
|
||||||
|
>
|
||||||
|
{mode === 'data' && (
|
||||||
|
<Calendar
|
||||||
|
className="b-calendar"
|
||||||
|
fullscreen={false}
|
||||||
|
onPanelChange={onPanelChange}
|
||||||
|
fullCellRender={cellRender}
|
||||||
|
onSelect={onDateChange}
|
||||||
|
value={selectDate}
|
||||||
|
disabledDate={disabledDate}
|
||||||
|
locale={getLocale(locale)}
|
||||||
|
validRange={[selectDate.startOf('M'), selectDate.endOf('M')]}
|
||||||
|
headerRender={({ onChange }) => {
|
||||||
|
const start = dayjs().startOf('M');
|
||||||
|
const [activeMonth, setActiveMonth] = useState<string>(start.format('YYYY-MM-DD'));
|
||||||
|
|
||||||
|
const onClick: MenuProps['onClick'] = (e) => {
|
||||||
|
setActiveMonth(e.key);
|
||||||
|
onChange(dayjs(e.key));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
className="b-calendar-header"
|
||||||
|
onClick={onClick}
|
||||||
|
selectedKeys={[activeMonth]}
|
||||||
|
mode="horizontal"
|
||||||
|
items={getCalendarMenu(start)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{mode === 'time' && (
|
||||||
|
<div className="b-schedule-time">
|
||||||
|
<div className="b-schedule-time-header">
|
||||||
|
<Button
|
||||||
|
className="b-button-link-big"
|
||||||
|
type="link"
|
||||||
|
onClick={() => updateMode('data')}
|
||||||
|
icon={<ArrowLeftOutlined />}
|
||||||
|
iconPosition="start"
|
||||||
|
>
|
||||||
|
{selectDate.locale(locale).format('DD MMMM YYYY')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="b-schedule-select-tag">
|
||||||
|
{tags && (
|
||||||
|
<CustomSelect
|
||||||
|
label={i18nText('selectTopic', locale)}
|
||||||
|
value={sessionData?.tagId}
|
||||||
|
options={tags?.map(({ id, name }) => ({ value: id, label: name }))}
|
||||||
|
onChange={onChangeTag}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="b-schedule-radio-list">
|
||||||
|
<Radio.Group name="radiogroupSlots" onChange={onChangeTimeSlot}>
|
||||||
|
{dates[selectDate.format('YYYY-MM-DD')].map((el) => {
|
||||||
|
return (<Radio key={dayjs(el.startTime).format()} value={el}>{dayjs(el.startTime).format('HH:mm')} - {dayjs(el.endTime).format('HH:mm')}</Radio>)
|
||||||
|
})}
|
||||||
|
</Radio.Group>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Input.TextArea
|
||||||
|
className="b-textarea"
|
||||||
|
rows={1}
|
||||||
|
value={sessionData?.clientComment}
|
||||||
|
placeholder={i18nText('sessionWishes', locale)}
|
||||||
|
onChange={(e) => setSesssionData({ ...sessionData, clientComment: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className="btn-apply"
|
||||||
|
onClick={singupSession}
|
||||||
|
loading={isPayLoading}
|
||||||
|
>
|
||||||
|
{i18nText('pay', locale)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{mode === 'pay' && (
|
||||||
|
<ElementsForm amount={sessionCost}/>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,290 +0,0 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import React, {Dispatch, FC, SetStateAction, useEffect, useState} from 'react';
|
|
||||||
import { usePathname } from 'next/navigation';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import {Modal, Form, Calendar, Radio } from 'antd';
|
|
||||||
import type { CalendarProps, RadioChangeEvent } from 'antd';
|
|
||||||
import { CloseOutlined } from '@ant-design/icons';
|
|
||||||
import { RegisterContent, ResetContent, FinishContent, EnterContent } from './authModalContent';
|
|
||||||
import dayjs, { Dayjs } from 'dayjs';
|
|
||||||
import {ExpertDetails, ExpertScheduler, Tags} from "../../types/experts";
|
|
||||||
import { createStyles } from 'antd-style';
|
|
||||||
import {useLocalStorage} from "../../hooks/useLocalStorage";
|
|
||||||
import {AUTH_TOKEN_KEY} from "../../constants/common";
|
|
||||||
import {getSchedulerByExpertId, getSchedulerSession} from "../../actions/experts";
|
|
||||||
import {ElementsForm} from "../stripe/ElementsForm";
|
|
||||||
|
|
||||||
type SchedulerModalProps = {
|
|
||||||
open: boolean;
|
|
||||||
handleCancel: () => void;
|
|
||||||
mode: 'data' | 'time' | 'pay' | 'finish';
|
|
||||||
updateMode: (mode: 'data' | 'time' | 'pay' | 'finish') => void;
|
|
||||||
sessionCost: number;
|
|
||||||
expertId: string;
|
|
||||||
locale: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyle = createStyles(({ token, css, cx }) => {
|
|
||||||
const lunar = css`
|
|
||||||
color: ${token.colorTextTertiary};
|
|
||||||
font-size: ${token.fontSizeSM}px;
|
|
||||||
`;
|
|
||||||
return {
|
|
||||||
wrapper: css`
|
|
||||||
width: 450px;
|
|
||||||
border: 1px solid ${token.colorBorderSecondary};
|
|
||||||
border-radius: ${token.borderRadiusOuter};
|
|
||||||
padding: 5px;
|
|
||||||
`,
|
|
||||||
dateCell: css`
|
|
||||||
position: relative;
|
|
||||||
&:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto;
|
|
||||||
max-width: 40px;
|
|
||||||
max-height: 40px;
|
|
||||||
background: transparent;
|
|
||||||
transition: background 300ms;
|
|
||||||
border-radius: ${token.borderRadiusOuter}px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
&:hover:before {
|
|
||||||
background: rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
today: css`
|
|
||||||
&:before {
|
|
||||||
border: 1px solid ${token.colorPrimary};
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
text: css`
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
`,
|
|
||||||
lunar,
|
|
||||||
current: css`
|
|
||||||
color: ${token.colorTextLightSolid};
|
|
||||||
&:before {
|
|
||||||
background: ${token.colorPrimary};
|
|
||||||
}
|
|
||||||
&:hover:before {
|
|
||||||
background: ${token.colorPrimary};
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
.${cx(lunar)} {
|
|
||||||
color: ${token.colorTextLightSolid};
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
monthCell: css`
|
|
||||||
width: 120px;
|
|
||||||
color: ${token.colorTextBase};
|
|
||||||
border-radius: ${token.borderRadiusOuter}px;
|
|
||||||
padding: 5px 0;
|
|
||||||
&:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
monthCellCurrent: css`
|
|
||||||
color: ${token.colorTextLightSolid};
|
|
||||||
background: ${token.colorPrimary};
|
|
||||||
&:hover {
|
|
||||||
background: ${token.colorPrimary};
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
weekend: css`
|
|
||||||
color: ${token.colorError};
|
|
||||||
&.gray {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const SchedulerModal: FC<SchedulerModalProps> = ({
|
|
||||||
open,
|
|
||||||
handleCancel,
|
|
||||||
mode,
|
|
||||||
updateMode,
|
|
||||||
sessionCost,
|
|
||||||
locale,
|
|
||||||
expertId,
|
|
||||||
}) => {
|
|
||||||
const { styles } = useStyle({ test: true });
|
|
||||||
const [selectDate, setSelectDate] = React.useState<Dayjs>(dayjs());
|
|
||||||
const [dates, setDates] = React.useState<any>();
|
|
||||||
const [tags, setTags] = React.useState<Tags[]>([]);
|
|
||||||
const [tag, setTag] = React.useState<number>(-1);
|
|
||||||
const [slot, setSlot] = React.useState<string>('');
|
|
||||||
const [sessionId, setSessionId] = React.useState<number>(-1);
|
|
||||||
const [rawScheduler, setRawScheduler] = useState<ExpertScheduler | null>(null);
|
|
||||||
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
|
||||||
|
|
||||||
useEffect( ()=> {
|
|
||||||
async function loadScheduler(){
|
|
||||||
const rawScheduler = await getSchedulerByExpertId(expertId as string, locale as string, jwt)
|
|
||||||
setRawScheduler(rawScheduler)
|
|
||||||
}
|
|
||||||
if (open) {
|
|
||||||
loadScheduler()
|
|
||||||
}
|
|
||||||
}, [open])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const map = {} as any
|
|
||||||
rawScheduler?.availableSlots.forEach((el)=>{
|
|
||||||
const key = dayjs(el.startTime).format('YYYY-MM-DD');
|
|
||||||
if (!map[key]){
|
|
||||||
map[key] = []
|
|
||||||
}
|
|
||||||
map[key].push(el)
|
|
||||||
|
|
||||||
})
|
|
||||||
console.log(rawScheduler, map)
|
|
||||||
setDates(map)
|
|
||||||
setTags(rawScheduler?.tags)
|
|
||||||
}, [rawScheduler]);
|
|
||||||
|
|
||||||
const onPanelChange = (value: Dayjs, mode: CalendarProps<Dayjs>['mode']) => {
|
|
||||||
console.log(value.format('YYYY-MM-DD'), mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDateChange: CalendarProps<Dayjs>['onSelect'] = (value, selectInfo) => {
|
|
||||||
if (selectInfo.source === 'date') {
|
|
||||||
setSelectDate(value);
|
|
||||||
updateMode('time')
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const disabledDate = (currentDate: Dayjs) => {
|
|
||||||
return !dates || !dates[currentDate.format('YYYY-MM-DD')]
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTimeslot = (e: RadioChangeEvent) => {
|
|
||||||
setSlot(e.target.value.startTime)
|
|
||||||
console.log('radio checked', e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTag = (e: RadioChangeEvent) => {
|
|
||||||
setTag(e.target.value)
|
|
||||||
console.log('tag radio checked', e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSingupSession = async () => {
|
|
||||||
const data = {coachId: expertId, tagId: tag, startAtUtc: slot, clientComment:''}
|
|
||||||
console.log(data)
|
|
||||||
const session = await getSchedulerSession({coachId: expertId, tagId: tag, startAtUtc: slot, clientComment:''}, locale, jwt)
|
|
||||||
console.log(session);
|
|
||||||
// тут должна быть проверка все ли с регистрацией сессии
|
|
||||||
setSessionId(session?.sessionId)
|
|
||||||
updateMode('pay')
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentDay = dayjs()
|
|
||||||
|
|
||||||
const cellRender: CalendarProps<Dayjs>['fullCellRender'] = (date, info) => {
|
|
||||||
const isWeekend = date.day() === 6 || date.day() === 0;
|
|
||||||
return React.cloneElement(info.originNode, {
|
|
||||||
...info.originNode.props,
|
|
||||||
className: classNames(styles.dateCell, {
|
|
||||||
[styles.current]: selectDate.isSame(date, 'date'),
|
|
||||||
[styles.today]: date.isSame(dayjs(), 'date'),
|
|
||||||
}),
|
|
||||||
children: (
|
|
||||||
<div className={styles.text}>
|
|
||||||
<span
|
|
||||||
className={classNames({
|
|
||||||
[styles.weekend]: isWeekend,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{date.get('date')}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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>
|
|
||||||
{tags && (
|
|
||||||
<Radio.Group name="radiogroupTags" onChange={handleTag}>
|
|
||||||
{tags?.map((tag)=>(
|
|
||||||
<Radio key={tag.id} value={tag.id}>{tag.name}</Radio>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</Radio.Group>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
{mode === 'data' && (
|
|
||||||
<Calendar
|
|
||||||
fullscreen={false}
|
|
||||||
onPanelChange={onPanelChange}
|
|
||||||
fullCellRender={cellRender}
|
|
||||||
onSelect={onDateChange}
|
|
||||||
disabledDate={disabledDate}
|
|
||||||
headerRender={({ value, type, onChange, onTypeChange }) => {
|
|
||||||
const start = 0;
|
|
||||||
const end = 12;
|
|
||||||
const monthOptions = [];
|
|
||||||
|
|
||||||
let current = currentDay.clone();
|
|
||||||
const localeData = value.locale();
|
|
||||||
const months = [];
|
|
||||||
|
|
||||||
for(let i=0; i<6; i++){
|
|
||||||
const m = current.clone()
|
|
||||||
months.push(m);
|
|
||||||
current = current.add(1,'month')
|
|
||||||
}
|
|
||||||
return (<>
|
|
||||||
{months.map((m, i)=>(
|
|
||||||
<button key={'SchedulerMonth'+i} onClick={()=> onChange(m)}>
|
|
||||||
{m.month()}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</>)
|
|
||||||
}}
|
|
||||||
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{mode === 'time' && (
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
<button onClick={()=>{updateMode('data')}}>back</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Radio.Group name="radiogroupSlots" onChange={handleTimeslot}>
|
|
||||||
{dates[selectDate.format('YYYY-MM-DD')].map( (el) => {
|
|
||||||
return (<Radio key={dayjs(el.startTime).format()} value={el}>{dayjs(el.startTime).format('hh-mm')} - {dayjs(el.endTime).format('hh-mm')}</Radio>)
|
|
||||||
})}
|
|
||||||
</Radio.Group>
|
|
||||||
<button onClick={handleSingupSession}>Записаться</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{mode === 'pay' && (
|
|
||||||
<ElementsForm amount={sessionCost}/>
|
|
||||||
)}
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -42,7 +42,7 @@ export default {
|
||||||
addComment: 'Neuen Kommentar hinzufügen',
|
addComment: 'Neuen Kommentar hinzufügen',
|
||||||
commentPlaceholder: 'Ihr Kommentar',
|
commentPlaceholder: 'Ihr Kommentar',
|
||||||
clientComments: 'Kundenkommentare',
|
clientComments: 'Kundenkommentare',
|
||||||
coachComments: 'Trainerkommentare'
|
coachComments: 'Expertenkommentare'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Zukünftige Räume',
|
upcoming: 'Zukünftige Räume',
|
||||||
|
@ -110,9 +110,9 @@ export default {
|
||||||
seminars: 'Seminare',
|
seminars: 'Seminare',
|
||||||
courses: 'Kurse',
|
courses: 'Kurse',
|
||||||
mba: 'MBA-Information',
|
mba: 'MBA-Information',
|
||||||
aboutCoach: 'Über Coach',
|
aboutCoach: 'Über den Experten',
|
||||||
education: 'Bildung',
|
education: 'Bildung',
|
||||||
coaching: 'Coaching',
|
coaching: 'Expertenprofil',
|
||||||
experiences: 'Praktische Erfahrung',
|
experiences: 'Praktische Erfahrung',
|
||||||
payInfo: 'Zahlungsdaten',
|
payInfo: 'Zahlungsdaten',
|
||||||
sessionDuration: 'Sitzungsdauer',
|
sessionDuration: 'Sitzungsdauer',
|
||||||
|
@ -146,6 +146,8 @@ export default {
|
||||||
saturday: 'Sa',
|
saturday: 'Sa',
|
||||||
addNew: 'Neu hinzufügen',
|
addNew: 'Neu hinzufügen',
|
||||||
mExperiences: 'Führungserfahrung',
|
mExperiences: 'Führungserfahrung',
|
||||||
|
pay: 'Pay',
|
||||||
|
sessionWishes: 'Write your wishes about the session',
|
||||||
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',
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default {
|
||||||
addComment: 'Add new',
|
addComment: 'Add new',
|
||||||
commentPlaceholder: 'Your comment',
|
commentPlaceholder: 'Your comment',
|
||||||
clientComments: 'Client Comments',
|
clientComments: 'Client Comments',
|
||||||
coachComments: 'Coach Comments'
|
coachComments: 'Expert Comments'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Upcoming Rooms',
|
upcoming: 'Upcoming Rooms',
|
||||||
|
@ -109,10 +109,10 @@ export default {
|
||||||
seminars: 'Seminars',
|
seminars: 'Seminars',
|
||||||
courses: 'Courses',
|
courses: 'Courses',
|
||||||
mba: 'MBA Information',
|
mba: 'MBA Information',
|
||||||
aboutCoach: 'About Coach',
|
aboutCoach: 'About Expert',
|
||||||
skillsInfo: 'Skills Info',
|
skillsInfo: 'Skills Info',
|
||||||
education: 'Education',
|
education: 'Education',
|
||||||
coaching: 'Coaching',
|
coaching: 'Expert profile',
|
||||||
experiences: 'Practical experience',
|
experiences: 'Practical experience',
|
||||||
payInfo: 'Payment Info',
|
payInfo: 'Payment Info',
|
||||||
sessionDuration: 'Session duration',
|
sessionDuration: 'Session duration',
|
||||||
|
@ -146,6 +146,8 @@ export default {
|
||||||
saturday: 'Sa',
|
saturday: 'Sa',
|
||||||
addNew: 'Add New',
|
addNew: 'Add New',
|
||||||
mExperiences: 'Managerial Experience',
|
mExperiences: 'Managerial Experience',
|
||||||
|
pay: 'Pay',
|
||||||
|
sessionWishes: 'Write your wishes about the session',
|
||||||
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',
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default {
|
||||||
addComment: 'Añadir nuevo comentario',
|
addComment: 'Añadir nuevo comentario',
|
||||||
commentPlaceholder: 'Tu comentario',
|
commentPlaceholder: 'Tu comentario',
|
||||||
clientComments: 'Comentarios del cliente',
|
clientComments: 'Comentarios del cliente',
|
||||||
coachComments: 'Comentarios del entrenador'
|
coachComments: 'Comentarios del experto'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Próximas salas',
|
upcoming: 'Próximas salas',
|
||||||
|
@ -110,9 +110,9 @@ export default {
|
||||||
seminars: 'Seminarios',
|
seminars: 'Seminarios',
|
||||||
courses: 'Cursos',
|
courses: 'Cursos',
|
||||||
mba: 'Información sobre máster en ADE (MBA)',
|
mba: 'Información sobre máster en ADE (MBA)',
|
||||||
aboutCoach: 'Sobre el coach',
|
aboutCoach: 'Acerca del experto',
|
||||||
education: 'Educación',
|
education: 'Educación',
|
||||||
coaching: 'Coaching',
|
coaching: 'Perfil del experto',
|
||||||
experiences: 'Experiencia práctica',
|
experiences: 'Experiencia práctica',
|
||||||
payInfo: 'Información de pago',
|
payInfo: 'Información de pago',
|
||||||
sessionDuration: 'Duración de la sesión',
|
sessionDuration: 'Duración de la sesión',
|
||||||
|
@ -146,6 +146,8 @@ export default {
|
||||||
saturday: 'S',
|
saturday: 'S',
|
||||||
addNew: 'Añadir nuevo',
|
addNew: 'Añadir nuevo',
|
||||||
mExperiences: 'Experiencia de dirección',
|
mExperiences: 'Experiencia de dirección',
|
||||||
|
pay: 'Pay',
|
||||||
|
sessionWishes: 'Write your wishes about the session',
|
||||||
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',
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default {
|
||||||
addComment: 'Ajouter un nouveau commentaire',
|
addComment: 'Ajouter un nouveau commentaire',
|
||||||
commentPlaceholder: 'Votre commentaire',
|
commentPlaceholder: 'Votre commentaire',
|
||||||
clientComments: 'Commentaires du client',
|
clientComments: 'Commentaires du client',
|
||||||
coachComments: 'Commentaires du coach'
|
coachComments: 'Commentaires de l\'expert'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Salles futures',
|
upcoming: 'Salles futures',
|
||||||
|
@ -110,9 +110,9 @@ export default {
|
||||||
seminars: 'Séminaires',
|
seminars: 'Séminaires',
|
||||||
courses: 'Cours',
|
courses: 'Cours',
|
||||||
mba: 'Infos Maîtrise en gestion',
|
mba: 'Infos Maîtrise en gestion',
|
||||||
aboutCoach: 'À propos du coach',
|
aboutCoach: 'À propos de l\'expert',
|
||||||
education: 'Éducation',
|
education: 'Éducation',
|
||||||
coaching: 'Coaching',
|
coaching: 'Profil de l\'expert',
|
||||||
experiences: 'Expérience pratique',
|
experiences: 'Expérience pratique',
|
||||||
payInfo: 'Infos sur le paiement',
|
payInfo: 'Infos sur le paiement',
|
||||||
sessionDuration: 'Durée de la session',
|
sessionDuration: 'Durée de la session',
|
||||||
|
@ -146,6 +146,8 @@ export default {
|
||||||
saturday: 'Sa',
|
saturday: 'Sa',
|
||||||
addNew: 'Ajouter un nouveau',
|
addNew: 'Ajouter un nouveau',
|
||||||
mExperiences: 'Expérience en gestion',
|
mExperiences: 'Expérience en gestion',
|
||||||
|
pay: 'Pay',
|
||||||
|
sessionWishes: 'Write your wishes about the session',
|
||||||
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',
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default {
|
||||||
addComment: 'Aggiungi nuovo commento',
|
addComment: 'Aggiungi nuovo commento',
|
||||||
commentPlaceholder: 'Il tuo commento',
|
commentPlaceholder: 'Il tuo commento',
|
||||||
clientComments: 'Commenti del cliente',
|
clientComments: 'Commenti del cliente',
|
||||||
coachComments: 'Commenti dell\'allenatore'
|
coachComments: 'Commenti dell\'esperto'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Prossime sale',
|
upcoming: 'Prossime sale',
|
||||||
|
@ -110,9 +110,9 @@ export default {
|
||||||
seminars: 'Seminari',
|
seminars: 'Seminari',
|
||||||
courses: 'Corsi',
|
courses: 'Corsi',
|
||||||
mba: 'Info sull\'MBA',
|
mba: 'Info sull\'MBA',
|
||||||
aboutCoach: 'Informazioni sul coach',
|
aboutCoach: 'Informazioni sull\'esperto',
|
||||||
education: 'Istruzione',
|
education: 'Istruzione',
|
||||||
coaching: 'Coaching',
|
coaching: 'Profilo dell\'esperto',
|
||||||
experiences: 'Esperienza pratica',
|
experiences: 'Esperienza pratica',
|
||||||
payInfo: 'Info pagamento',
|
payInfo: 'Info pagamento',
|
||||||
sessionDuration: 'Durata della sessione',
|
sessionDuration: 'Durata della sessione',
|
||||||
|
@ -146,6 +146,8 @@ export default {
|
||||||
saturday: 'Sa',
|
saturday: 'Sa',
|
||||||
addNew: 'Aggiungi nuovo',
|
addNew: 'Aggiungi nuovo',
|
||||||
mExperiences: 'Esperienza manageriale',
|
mExperiences: 'Esperienza manageriale',
|
||||||
|
pay: 'Pay',
|
||||||
|
sessionWishes: 'Write your wishes about the session',
|
||||||
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',
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default {
|
||||||
addComment: 'Добавить новый',
|
addComment: 'Добавить новый',
|
||||||
commentPlaceholder: 'Ваш комментарий',
|
commentPlaceholder: 'Ваш комментарий',
|
||||||
clientComments: 'Комментарии клиента',
|
clientComments: 'Комментарии клиента',
|
||||||
coachComments: 'Комментарии коуча'
|
coachComments: 'Комментарии эксперта'
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
upcoming: 'Предстоящие комнаты',
|
upcoming: 'Предстоящие комнаты',
|
||||||
|
@ -111,9 +111,9 @@ export default {
|
||||||
courses: 'Курсы',
|
courses: 'Курсы',
|
||||||
mba: 'Информация о MBA',
|
mba: 'Информация о MBA',
|
||||||
experiences: 'Практический опыт',
|
experiences: 'Практический опыт',
|
||||||
aboutCoach: 'О коуче',
|
aboutCoach: 'Информация об эксперте',
|
||||||
education: 'Образование',
|
education: 'Образование',
|
||||||
coaching: 'Коучинг',
|
coaching: 'Профиль эксперта',
|
||||||
payInfo: 'Платежная информация',
|
payInfo: 'Платежная информация',
|
||||||
sessionDuration: 'Продолжительность сессии',
|
sessionDuration: 'Продолжительность сессии',
|
||||||
experienceHours: 'Общее количество часов практического опыта',
|
experienceHours: 'Общее количество часов практического опыта',
|
||||||
|
@ -146,6 +146,8 @@ export default {
|
||||||
saturday: 'Сб',
|
saturday: 'Сб',
|
||||||
addNew: 'Добавить',
|
addNew: 'Добавить',
|
||||||
mExperiences: 'Управленческий опыт',
|
mExperiences: 'Управленческий опыт',
|
||||||
|
pay: 'Pay',
|
||||||
|
sessionWishes: 'Write your wishes about the session',
|
||||||
errors: {
|
errors: {
|
||||||
invalidEmail: 'Адрес электронной почты недействителен',
|
invalidEmail: 'Адрес электронной почты недействителен',
|
||||||
emptyEmail: 'Пожалуйста, введите ваш E-mail',
|
emptyEmail: 'Пожалуйста, введите ваш E-mail',
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
.b-calendar {
|
||||||
|
padding: 44px 40px !important;
|
||||||
|
|
||||||
|
&-month {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-header {
|
||||||
|
justify-content: center;
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-cell {
|
||||||
|
span {
|
||||||
|
color: #66A5AD;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__weekend {
|
||||||
|
span {
|
||||||
|
color: #FFBD00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-body {
|
||||||
|
margin-bottom: -42px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-panel {
|
||||||
|
border-top: none !important;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-cell {
|
||||||
|
opacity: 0 !important;
|
||||||
|
|
||||||
|
&-disabled {
|
||||||
|
&::before {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: rgba(0, 0, 0, 0.25) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-picker-cell-in-view {
|
||||||
|
opacity: 1 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
vertical-align: middle !important;
|
||||||
|
height: 40px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
color: #66A5AD !important;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
.b-schedule {
|
||||||
|
&-time {
|
||||||
|
padding: 44px 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
.b-button-link-big {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 32px;
|
||||||
|
color: #6FB98F !important;
|
||||||
|
font-family: var(--font-comfortaa);
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-radio-list {
|
||||||
|
.ant-radio-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,3 +9,5 @@
|
||||||
@import "_practice.scss";
|
@import "_practice.scss";
|
||||||
@import "_collapse.scss";
|
@import "_collapse.scss";
|
||||||
@import "_timepicker.scss";
|
@import "_timepicker.scss";
|
||||||
|
@import "_calendar.scss";
|
||||||
|
@import "_schedule.scss";
|
||||||
|
|
|
@ -71,28 +71,23 @@ export type ExpertDetails = {
|
||||||
associationLevels?: AssociationLevel[];
|
associationLevels?: AssociationLevel[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Tags = {
|
|
||||||
id: number,
|
|
||||||
groupId: number,
|
|
||||||
name: string,
|
|
||||||
couchCount: number,
|
|
||||||
group: {
|
|
||||||
id: number,
|
|
||||||
name: string,
|
|
||||||
tags: string[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Slot = {
|
export type Slot = {
|
||||||
startTime: string;
|
startTime: string;
|
||||||
endTime: string;
|
endTime: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExpertScheduler = {
|
export type ExpertScheduler = {
|
||||||
tags: Tags[],
|
tags: Tag[],
|
||||||
availableSlots: Slot[];
|
availableSlots: Slot[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExpertSchedulerSession = {
|
export type ExpertSchedulerSession = {
|
||||||
sessionId: string
|
sessionId: string
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export type SignupSessionData = {
|
||||||
|
coachId: number,
|
||||||
|
tagId?: number,
|
||||||
|
startAtUtc?: string,
|
||||||
|
clientComment?: string
|
||||||
|
};
|
Loading…
Reference in New Issue