215 lines
8.7 KiB
TypeScript
215 lines
8.7 KiB
TypeScript
'use client';
|
||
|
||
import React, { FC, useEffect, useState } from 'react';
|
||
import { Modal, Button, message } from 'antd';
|
||
import { CloseOutlined, DeleteOutlined } from '@ant-design/icons';
|
||
import dayjs from 'dayjs';
|
||
import { i18nText } from '../../i18nKeys';
|
||
import { AUTH_TOKEN_KEY } from '../../constants/common';
|
||
import { UTC_LIST } from '../../constants/time';
|
||
import { MapWorkingTime, ScheduleDTO } from '../../types/schedule';
|
||
import {
|
||
WEEK_DAY,
|
||
formattedSchedule,
|
||
getNewTime,
|
||
getTimeZoneOffset,
|
||
getTimeString,
|
||
formattedTimeByOffset, formattedWorkList
|
||
} from '../../utils/time';
|
||
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
||
import { setSchedule } from '../../actions/profile';
|
||
import { CustomSelect } from '../view/CustomSelect';
|
||
import { CustomTimePicker } from '../view/CustomTimePicker';
|
||
import { LinkButton } from '../view/LinkButton';
|
||
import { OutlinedButton } from '../view/OutlinedButton';
|
||
|
||
type EditExpertScheduleModalProps = {
|
||
open: boolean;
|
||
handleCancel: () => void;
|
||
locale: string;
|
||
data?: ScheduleDTO;
|
||
refresh: () => void;
|
||
};
|
||
|
||
const DEFAULT_WORK: MapWorkingTime = { startDay: '' };
|
||
|
||
export const EditExpertScheduleModal: FC<EditExpertScheduleModalProps> = ({
|
||
open,
|
||
handleCancel,
|
||
locale,
|
||
data,
|
||
refresh,
|
||
}) => {
|
||
const defaultTimeZone = dayjs().format('Z');
|
||
const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, '');
|
||
const [timeZone, setTimeZone] = useState<string>(defaultTimeZone);
|
||
const [workList, setWorkList] = useState<MapWorkingTime[]>([DEFAULT_WORK]);
|
||
const [loading, setLoading] = useState<boolean>(false);
|
||
|
||
useEffect(() => {
|
||
if (open && data?.workingTimes && data.workingTimes.length > 0) {
|
||
setWorkList(formattedSchedule(data.workingTimes, timeZone));
|
||
}
|
||
}, [open]);
|
||
|
||
const onSave = () => {
|
||
const workingTimes = formattedWorkList(workList, timeZone);
|
||
|
||
setLoading(true);
|
||
setSchedule(locale, jwt, { workingTimes })
|
||
.then(() => {
|
||
handleCancel();
|
||
refresh();
|
||
})
|
||
.catch(() => {
|
||
message.error('Не удалось сохранить расписание');
|
||
})
|
||
.finally(() => {
|
||
setLoading(false);
|
||
})
|
||
};
|
||
|
||
const addWorkingHours = () => {
|
||
setWorkList([
|
||
...workList,
|
||
DEFAULT_WORK
|
||
]);
|
||
};
|
||
|
||
const deleteWorkingHours = (index: number) => {
|
||
setWorkList(workList.filter((work, i) => i !== index));
|
||
};
|
||
|
||
const onChangeWeekDay = (val: string, index: number) => {
|
||
setWorkList(workList.map((work, i) => {
|
||
if (i === index) {
|
||
return {
|
||
...work,
|
||
startDay: val
|
||
}
|
||
}
|
||
|
||
return work;
|
||
}));
|
||
};
|
||
|
||
const onChangeTime = (time: string, index: number, start?: boolean) => {
|
||
setWorkList(workList.map((work, i) => {
|
||
if (i === index) {
|
||
const timeMin = getNewTime(time);
|
||
let res;
|
||
|
||
if (start) {
|
||
res = {
|
||
startTimeMin: timeMin
|
||
}
|
||
} else {
|
||
res = {
|
||
endTimeMin: timeMin
|
||
}
|
||
}
|
||
|
||
return {
|
||
...work,
|
||
...res
|
||
}
|
||
}
|
||
|
||
return work;
|
||
}));
|
||
};
|
||
|
||
const onChangeTimeZone = (newTimeZone: string) => {
|
||
const offset = getTimeZoneOffset(timeZone, newTimeZone);
|
||
setTimeZone(newTimeZone);
|
||
setWorkList(workList.map((work) => formattedTimeByOffset(work, offset)));
|
||
}
|
||
|
||
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('schedule', locale)}</div>
|
||
<div className="b-modal__expert__inner" style={{ paddingRight: 12 }}>
|
||
<div style={{ paddingRight: 0, paddingBottom: 1 }}>
|
||
<div className="schedule">
|
||
<div className="schedule__inner">
|
||
<div className="timezone">
|
||
<div className="timezone__title">{`${i18nText('yourTimezone', locale)}: ${defaultTimeZone}`}</div>
|
||
<div className="timezone__utc">
|
||
<CustomSelect
|
||
label="UTC"
|
||
value={timeZone}
|
||
options={UTC_LIST.map((value) => ({ value, label: value }))}
|
||
onChange={(val) => onChangeTimeZone(val)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<h3 className="title-h3">{i18nText('workTime', locale)}</h3>
|
||
<div className="schedule__wrap">
|
||
{workList.length === 1 ? workList.map(({ startDay, startTimeMin, endTimeMin }, index) => (
|
||
<div key={`day_${index}`} className="schedule-item__single">
|
||
<CustomSelect />
|
||
<CustomSelect label={i18nText('startAt', locale)} />
|
||
<CustomSelect label={i18nText('finishAt', locale)} />
|
||
</div>
|
||
)) : null}
|
||
{workList.length > 1 ? workList.map(({ startDay, startTimeMin, endTimeMin }, index) => (
|
||
<div key={`day_${index}`} className="schedule-item">
|
||
<CustomSelect
|
||
label={i18nText('day', locale)}
|
||
value={startDay || undefined}
|
||
options={WEEK_DAY.map((value) => ({ value, label: i18nText(value, locale) }))}
|
||
onChange={(val) => onChangeWeekDay(val, index)}
|
||
/>
|
||
<CustomTimePicker
|
||
label={i18nText('startAt', locale)}
|
||
value={startTimeMin ? dayjs(getTimeString(startTimeMin), 'HH:mm') : dayjs('00:00', 'HH:mm')}
|
||
onChange={(time, timeString) => onChangeTime(timeString, index, true)}
|
||
/>
|
||
<CustomTimePicker
|
||
label={i18nText('finishAt', locale)}
|
||
value={endTimeMin ? dayjs(getTimeString(endTimeMin), 'HH:mm') : dayjs('00:00', 'HH:mm')}
|
||
onChange={(time, timeString) => onChangeTime(timeString, index)}
|
||
/>
|
||
<LinkButton
|
||
type="link"
|
||
danger
|
||
icon={<DeleteOutlined />}
|
||
onClick={() => deleteWorkingHours(index)}
|
||
/>
|
||
</div>
|
||
)) : null}
|
||
</div>
|
||
<OutlinedButton
|
||
type="link"
|
||
onClick={addWorkingHours}
|
||
>
|
||
{i18nText('addWorkingHours', locale)}
|
||
</OutlinedButton>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="b-modal__expert__button">
|
||
<Button
|
||
className="card-detail__apply"
|
||
onClick={onSave}
|
||
loading={loading}
|
||
>
|
||
{i18nText('save', locale)}
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
);
|
||
};
|