RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.tsx

Summary

Maintainability
D
1 day
Test Coverage
import type { SelectOption } from '@rocket.chat/fuselage';
import { InputBox, Field, MultiSelect, FieldGroup, Box, Select, FieldLabel, FieldRow, Callout } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
import React, { useMemo } from 'react';
import { useFormContext, Controller, useFieldArray } from 'react-hook-form';

import { useTimezoneNameList } from '../../../hooks/useTimezoneNameList';
import { BusinessHoursMultiple } from '../additionalForms';
import { defaultWorkHours, DAYS_OF_WEEK } from './mapBusinessHoursForm';

type mappedDayTime = {
    day: string;
    start: {
        time: string;
    };
    finish: {
        time: string;
    };
    open: boolean;
};

export type BusinessHoursFormData = {
    name: string;
    timezoneName: string;
    daysOpen: string[];
    daysTime: mappedDayTime[];
    departmentsToApplyBusinessHour: string;
    active: boolean;
    departments: {
        value: string;
        label: string;
    }[];
};

// TODO: replace `Select` in favor `SelectFiltered`
// TODO: add time validation for start and finish not be equal on UI
// TODO: add time validation for start not be higher than finish on UI
const BusinessHoursForm = ({ type }: { type?: 'default' | 'custom' }) => {
    const t = useTranslation();
    const timeZones = useTimezoneNameList();
    const timeZonesOptions: SelectOption[] = useMemo(() => timeZones.map((name) => [name, t(name as TranslationKey)]), [t, timeZones]);
    const daysOptions: SelectOption[] = useMemo(() => DAYS_OF_WEEK.map((day) => [day, t(day as TranslationKey)]), [t]);

    const { watch, control } = useFormContext<BusinessHoursFormData>();
    const { daysTime } = watch();
    const { fields: daysTimeFields, replace } = useFieldArray({ control, name: 'daysTime' });

    const timezoneField = useUniqueId();
    const daysOpenField = useUniqueId();
    const daysTimeField = useUniqueId();

    const handleChangeDaysTime = (values: string[]) => {
        const newValues = values
            .map((item) => daysTime.find(({ day }) => day === item) || defaultWorkHours(true).find(({ day }) => day === item))
            .filter((item): item is mappedDayTime => Boolean(item));
        replace(newValues);
    };

    return (
        <FieldGroup>
            {type === 'custom' && <BusinessHoursMultiple />}
            <Field>
                <FieldLabel htmlFor={timezoneField}>{t('Timezone')}</FieldLabel>
                <FieldRow>
                    <Controller
                        name='timezoneName'
                        control={control}
                        render={({ field }) => <Select id={timezoneField} {...field} options={timeZonesOptions} />}
                    />
                </FieldRow>
                <Callout title={t('Daylight_savings_time')} type='info' mbs='x8'>
                    {t('Business_hours_will_update_automatically')}
                </Callout>
            </Field>
            <Field>
                <FieldLabel htmlFor={daysOpenField}>{t('Open_days_of_the_week')}</FieldLabel>
                <FieldRow>
                    <Controller
                        name='daysOpen'
                        control={control}
                        render={({ field: { onChange, value, name, onBlur } }) => (
                            <MultiSelect
                                id={daysOpenField}
                                onBlur={onBlur}
                                name={name}
                                onChange={(values) => {
                                    handleChangeDaysTime(values);
                                    onChange(values);
                                }}
                                options={daysOptions}
                                value={value}
                                placeholder={t('Select_an_option')}
                                w='full'
                            />
                        )}
                    />
                </FieldRow>
            </Field>
            {daysTimeFields.map((dayTime, index) => (
                <Field key={dayTime.id}>
                    <FieldLabel>{t(dayTime.day as TranslationKey)}</FieldLabel>
                    <FieldRow>
                        <Box display='flex' flexDirection='column' flexGrow={1} mie={2}>
                            <FieldLabel htmlFor={`${daysTimeField + index}-start`}>{t('Open')}</FieldLabel>
                            <Controller
                                name={`daysTime.${index}.start.time`}
                                render={({ field }) => <InputBox id={`${daysTimeField + index}-start`} type='time' {...field} />}
                            />
                        </Box>
                        <Box display='flex' flexDirection='column' flexGrow={1} mis={2}>
                            <FieldLabel htmlFor={`${daysTimeField + index}-finish`}>{t('Close')}</FieldLabel>
                            <Controller
                                name={`daysTime.${index}.finish.time`}
                                render={({ field }) => <InputBox id={`${daysTimeField + index}-finish`} type='time' {...field} />}
                            />
                        </Box>
                    </FieldRow>
                </Field>
            ))}
        </FieldGroup>
    );
};

export default BusinessHoursForm;