Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / applications / calendar / src / app / components / eventModal / rows / RepeatEveryRow.tsx
blob4b58ffb24fd34d7e7afa86912bbc3bc7fcda3e1c
1 import { c, msgid } from 'ttag';
3 import { IntegerInput, Option, SelectTwo } from '@proton/components';
4 import { FREQUENCY, FREQUENCY_INTERVALS_MAX } from '@proton/shared/lib/calendar/constants';
5 import type { WeekStartsOn } from '@proton/shared/lib/date-fns-utc/interface';
6 import type { DateTimeModel, EventModelErrors, FrequencyModel } from '@proton/shared/lib/interfaces/calendar';
7 import clsx from '@proton/utils/clsx';
9 import SelectMonthlyType from '../inputs/SelectMonthlyType';
10 import RepeatOnRow from './RepeatOnRow';
12 interface Props {
13     frequencyModel: FrequencyModel;
14     start: DateTimeModel;
15     weekStartsOn: WeekStartsOn;
16     onChange: (value: FrequencyModel) => void;
17     errors: EventModelErrors;
18     isSubmitted: boolean;
19     displayStacked?: boolean;
22 const getMaxFrequencyInterval = (frequency: FREQUENCY) => {
23     return FREQUENCY_INTERVALS_MAX[frequency];
26 const RepeatEveryRow = ({
27     frequencyModel,
28     start,
29     weekStartsOn,
30     onChange,
31     errors,
32     isSubmitted,
33     displayStacked = false,
34 }: Props) => {
35     const isMonthly = frequencyModel.frequency === FREQUENCY.MONTHLY;
36     const isWeekly = frequencyModel.frequency === FREQUENCY.WEEKLY;
37     const safeIntervalPlural = frequencyModel.interval || 1; // Can get undefined through the input
38     const intervalOptions = [
39         { text: c('Option').ngettext(msgid`Day`, `Days`, safeIntervalPlural), value: FREQUENCY.DAILY },
40         { text: c('Option').ngettext(msgid`Week`, `Weeks`, safeIntervalPlural), value: FREQUENCY.WEEKLY },
41         { text: c('Option').ngettext(msgid`Month`, `Months`, safeIntervalPlural), value: FREQUENCY.MONTHLY },
42         { text: c('Option').ngettext(msgid`Year`, `Years`, safeIntervalPlural), value: FREQUENCY.YEARLY },
43     ];
45     const handleChangeInterval = (interval: number | undefined) => {
46         if (interval !== undefined && (interval > getMaxFrequencyInterval(frequencyModel.frequency) || interval < 1)) {
47             return;
48         }
49         onChange({ ...frequencyModel, interval });
50     };
51     const handleChangeFrequency = (frequency: FREQUENCY) => {
52         const newMaxInterval = getMaxFrequencyInterval(frequency);
53         const interval = Math.min(frequencyModel.interval || 0, newMaxInterval);
54         onChange({ ...frequencyModel, frequency, interval });
55     };
57     return (
58         <div className={clsx('flex flex-column', displayStacked ? '*:min-size-auto gap-4' : 'md:flex-row')}>
59             <div className="md:flex-1">
60                 <label
61                     className={clsx(displayStacked && 'text-semibold')}
62                     htmlFor="event-custom-frequency-number"
63                     id="label-event-custom-frequency"
64                 >{c('Label').t`Repeat every`}</label>
65                 <div className="flex flex-column md:flex-row my-2">
66                     <div className="flex flex-nowrap md:flex-1">
67                         <span className="w-custom" style={{ '--w-custom': '6em' }}>
68                             <IntegerInput
69                                 id="event-custom-frequency-number"
70                                 data-testid="event-modal/custom-frequency/interval:input"
71                                 min={1}
72                                 value={frequencyModel.interval}
73                                 onChange={handleChangeInterval}
74                                 onBlur={() => {
75                                     if (!frequencyModel.interval) {
76                                         handleChangeInterval(1);
77                                     }
78                                 }}
79                                 aria-invalid={isSubmitted && !!errors.interval}
80                                 isSubmitted={isSubmitted}
81                                 title={c('Title').t`Choose how often this event repeats`}
82                                 aria-describedby="label-event-custom-frequency event-custom-frequency-select"
83                             />
84                         </span>
85                         <span className="flex-1 ml-2">
86                             <SelectTwo
87                                 id="event-custom-frequency-select"
88                                 data-testid="event-modal/custom-frequency/interval:frequency"
89                                 value={frequencyModel.frequency}
90                                 onChange={({ value }) => handleChangeFrequency(value as FREQUENCY)}
91                                 title={c('Title').t`Select event frequency interval`}
92                                 aria-describedby="label-event-custom-frequency event-custom-frequency-number event-custom-frequency-select"
93                             >
94                                 {intervalOptions.map(({ text, value }) => (
95                                     <Option key={value} value={value} title={text} />
96                                 ))}
97                             </SelectTwo>
98                         </span>
99                     </div>
100                     {isMonthly && (
101                         <div className="md:flex-1 ml-0 mt-2 md:ml-2 md:mt-0">
102                             <SelectMonthlyType
103                                 id="event-custom-monthly-select"
104                                 value={frequencyModel.monthly.type}
105                                 date={start.date}
106                                 onChange={(type) => onChange({ ...frequencyModel, monthly: { type } })}
107                                 title={c('Title').t`Select a day in the month`}
108                             />
109                         </div>
110                     )}
111                 </div>
112             </div>
113             {isWeekly && (
114                 <RepeatOnRow
115                     frequencyModel={frequencyModel}
116                     start={start}
117                     weekStartsOn={weekStartsOn}
118                     onChange={onChange}
119                     displayStacked={displayStacked}
120                 />
121             )}
122         </div>
123     );
126 export default RepeatEveryRow;