import dayjs from 'dayjs'; import React, { useState } from 'react'; import { useDispatch } from 'react-redux'; import TextField from '@mui/material/TextField'; import { Accordion, AccordionSummary, AccordionDetails, Typography, FormControl, InputLabel, Select, MenuItem, } from '@mui/material'; import makeStyles from '@mui/styles/makeStyles'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { DropzoneArea } from 'react-mui-dropzone'; import EditItemView from './components/EditItemView'; import EditAttributesAccordion from './components/EditAttributesAccordion'; import { useTranslation } from '../common/components/LocalizationProvider'; import SettingsMenu from './components/SettingsMenu'; import { prefixString } from '../common/util/stringUtils'; import { calendarsActions } from '../store'; import { useCatch } from '../reactHelper'; const formatCalendarTime = (time) => { const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone; return `TZID=${tzid}:${time.locale('en').format('YYYYMMDDTHHmmss')}`; }; const parseRule = (rule) => { if (rule.endsWith('COUNT=1')) { return { frequency: 'ONCE' }; } const fragments = rule.split(';'); const frequency = fragments[0].substring(11); const by = fragments.length > 1 ? fragments[1].split('=')[1].split(',') : null; return { frequency, by }; }; const formatRule = (rule) => { const by = rule.by && rule.by.join(','); switch (rule.frequency) { case 'DAILY': return `RRULE:FREQ=${rule.frequency}`; case 'WEEKLY': return `RRULE:FREQ=${rule.frequency};BYDAY=${by || 'SU'}`; case 'MONTHLY': return `RRULE:FREQ=${rule.frequency};BYMONTHDAY=${by || 1}`; default: return 'RRULE:FREQ=DAILY;COUNT=1'; } }; const updateCalendar = (lines, index, element) => window.btoa(lines.map((e, i) => (i !== index ? e : element)).join('\n')); const simpleCalendar = () => window.btoa([ 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//Traccar//NONSGML Traccar//EN', 'BEGIN:VEVENT', 'UID:00000000-0000-0000-0000-000000000000', `DTSTART;${formatCalendarTime(dayjs())}`, `DTEND;${formatCalendarTime(dayjs().add(1, 'hours'))}`, 'RRULE:FREQ=DAILY', 'SUMMARY:Event', 'END:VEVENT', 'END:VCALENDAR', ].join('\n')); const useStyles = makeStyles((theme) => ({ details: { display: 'flex', flexDirection: 'column', gap: theme.spacing(2), paddingBottom: theme.spacing(3), }, })); const CalendarPage = () => { const classes = useStyles(); const dispatch = useDispatch(); const t = useTranslation(); const [item, setItem] = useState(); const decoded = item && item.data && window.atob(item.data); const simple = decoded && decoded.indexOf('//Traccar//') > 0; const lines = decoded && decoded.split('\n'); const rule = simple && parseRule(lines[7]); const handleFiles = (files) => { if (files.length > 0) { const reader = new FileReader(); reader.onload = (event) => { const { result } = event.target; setItem({ ...item, data: result.substr(result.indexOf(',') + 1) }); }; reader.readAsDataURL(files[0]); } }; const onItemSaved = useCatch(async () => { const response = await fetch('/api/calendars'); if (response.ok) { dispatch(calendarsActions.update(await response.json())); } else { throw Error(await response.text()); } }); const validate = () => item && item.name && item.data; return ( } breadcrumbs={['settingsTitle', 'sharedCalendar']} > {item && ( <> }> {t('sharedRequired')} setItem({ ...item, name: event.target.value })} label={t('sharedName')} /> {t('sharedType')} {simple ? ( <> { const time = formatCalendarTime(dayjs(e.target.value, 'YYYY-MM-DDTHH:mm')); setItem({ ...item, data: updateCalendar(lines, 5, `DTSTART;${time}`) }); }} /> { const time = formatCalendarTime(dayjs(e.target.value, 'YYYY-MM-DDTHH:mm')); setItem({ ...item, data: updateCalendar(lines, 6, `DTEND;${time}`) }); }} /> {t('calendarRecurrence')} {['WEEKLY', 'MONTHLY'].includes(rule.frequency) && ( {t('calendarDays')} )} ) : ( )} setItem({ ...item, attributes })} definitions={{}} /> )} ); }; export default CalendarPage;