Update event page
This commit is contained in:
parent
2d32a1b036
commit
9ac969ec78
|
|
@ -66,8 +66,8 @@ const App = () => {
|
||||||
<Route path="/" element={<Pages.Home />} />
|
<Route path="/" element={<Pages.Home />} />
|
||||||
<Route path="/how-to" element={<Pages.Help />} />
|
<Route path="/how-to" element={<Pages.Help />} />
|
||||||
<Route path="/privacy" element={<Pages.Privacy />} />
|
<Route path="/privacy" element={<Pages.Privacy />} />
|
||||||
{/* <Route path="/create" element={<Pages.Create />} />
|
<Route path="/create" element={<Pages.Create />} />
|
||||||
<Route path="/:id" element={<Pages.Event />} /> */}
|
<Route path="/:id" element={<Pages.Event />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react'
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form'
|
||||||
import { useTranslation, Trans } from 'react-i18next';
|
import { useTranslation, Trans } from 'react-i18next'
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs'
|
||||||
import utc from 'dayjs/plugin/utc';
|
import utc from 'dayjs/plugin/utc'
|
||||||
import timezone from 'dayjs/plugin/timezone';
|
import timezone from 'dayjs/plugin/timezone'
|
||||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TextField,
|
TextField,
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
Error,
|
Error,
|
||||||
Recents,
|
Recents,
|
||||||
Footer,
|
Footer,
|
||||||
} from 'components';
|
} from '/src/components'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
StyledMain,
|
StyledMain,
|
||||||
|
|
@ -27,80 +27,80 @@ import {
|
||||||
P,
|
P,
|
||||||
OfflineMessage,
|
OfflineMessage,
|
||||||
ShareInfo,
|
ShareInfo,
|
||||||
} from './createStyle';
|
} from './Create.styles'
|
||||||
|
|
||||||
import api from 'services';
|
import api from '/src/services'
|
||||||
import { useRecentsStore } from 'stores';
|
import { useRecentsStore } from '/src/stores'
|
||||||
|
|
||||||
import timezones from 'res/timezones.json';
|
import timezones from '/src/res/timezones.json'
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat);
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
const Create = ({ offline }) => {
|
const Create = ({ offline }) => {
|
||||||
const { register, handleSubmit, setValue } = useForm({
|
const { register, handleSubmit, setValue } = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null)
|
||||||
const [createdEvent, setCreatedEvent] = useState(null);
|
const [createdEvent, setCreatedEvent] = useState(null)
|
||||||
const [copied, setCopied] = useState(null);
|
const [copied, setCopied] = useState(null)
|
||||||
const [showFooter, setShowFooter] = useState(true);
|
const [showFooter, setShowFooter] = useState(true)
|
||||||
|
|
||||||
const { push } = useHistory();
|
const navigate = useNavigate()
|
||||||
const { t } = useTranslation(['common', 'home', 'event']);
|
const { t } = useTranslation(['common', 'home', 'event'])
|
||||||
|
|
||||||
const addRecent = useRecentsStore(state => state.addRecent);
|
const addRecent = useRecentsStore(state => state.addRecent)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (window.self === window.top) {
|
if (window.self === window.top) {
|
||||||
push('/');
|
navigate('/')
|
||||||
}
|
}
|
||||||
document.title = 'Create a Crab Fit';
|
document.title = 'Create a Crab Fit'
|
||||||
|
|
||||||
if (window.parent) {
|
if (window.parent) {
|
||||||
window.parent.postMessage('crabfit-create', '*');
|
window.parent.postMessage('crabfit-create', '*')
|
||||||
window.addEventListener('message', e => {
|
window.addEventListener('message', e => {
|
||||||
if (e.data === 'safari-extension') {
|
if (e.data === 'safari-extension') {
|
||||||
setShowFooter(false);
|
setShowFooter(false)
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
once: true
|
once: true
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}, [push]);
|
}, [navigate])
|
||||||
|
|
||||||
const onSubmit = async data => {
|
const onSubmit = async data => {
|
||||||
setIsLoading(true);
|
setIsLoading(true)
|
||||||
setError(null);
|
setError(null)
|
||||||
try {
|
try {
|
||||||
const { start, end } = JSON.parse(data.times);
|
const { start, end } = JSON.parse(data.times)
|
||||||
const dates = JSON.parse(data.dates);
|
const dates = JSON.parse(data.dates)
|
||||||
|
|
||||||
if (dates.length === 0) {
|
if (dates.length === 0) {
|
||||||
return setError(t('home:form.errors.no_dates'));
|
return setError(t('home:form.errors.no_dates'))
|
||||||
}
|
}
|
||||||
const isSpecificDates = typeof dates[0] === 'string' && dates[0].length === 8;
|
const isSpecificDates = typeof dates[0] === 'string' && dates[0].length === 8
|
||||||
if (start === end) {
|
if (start === end) {
|
||||||
return setError(t('home:form.errors.same_times'));
|
return setError(t('home:form.errors.same_times'))
|
||||||
}
|
}
|
||||||
|
|
||||||
let times = dates.reduce((times, date) => {
|
const times = dates.reduce((times, date) => {
|
||||||
let day = [];
|
const day = []
|
||||||
for (let i = start; i < (start > end ? 24 : end); i++) {
|
for (let i = start; i < (start > end ? 24 : end); i++) {
|
||||||
if (isSpecificDates) {
|
if (isSpecificDates) {
|
||||||
day.push(
|
day.push(
|
||||||
dayjs.tz(date, 'DDMMYYYY', data.timezone)
|
dayjs.tz(date, 'DDMMYYYY', data.timezone)
|
||||||
.hour(i).minute(0).utc().format('HHmm-DDMMYYYY')
|
.hour(i).minute(0).utc().format('HHmm-DDMMYYYY')
|
||||||
);
|
)
|
||||||
} else {
|
} else {
|
||||||
day.push(
|
day.push(
|
||||||
dayjs().tz(data.timezone)
|
dayjs().tz(data.timezone)
|
||||||
.day(date).hour(i).minute(0).utc().format('HHmm-d')
|
.day(date).hour(i).minute(0).utc().format('HHmm-d')
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (start > end) {
|
if (start > end) {
|
||||||
|
|
@ -108,21 +108,21 @@ const Create = ({ offline }) => {
|
||||||
if (isSpecificDates) {
|
if (isSpecificDates) {
|
||||||
day.push(
|
day.push(
|
||||||
dayjs.tz(date, 'DDMMYYYY', data.timezone)
|
dayjs.tz(date, 'DDMMYYYY', data.timezone)
|
||||||
.hour(i).minute(0).utc().format('HHmm-DDMMYYYY')
|
.hour(i).minute(0).utc().format('HHmm-DDMMYYYY')
|
||||||
);
|
)
|
||||||
} else {
|
} else {
|
||||||
day.push(
|
day.push(
|
||||||
dayjs().tz(data.timezone)
|
dayjs().tz(data.timezone)
|
||||||
.day(date).hour(i).minute(0).utc().format('HHmm-d')
|
.day(date).hour(i).minute(0).utc().format('HHmm-d')
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [...times, ...day];
|
return [...times, ...day]
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
if (times.length === 0) {
|
if (times.length === 0) {
|
||||||
return setError(t('home:form.errors.no_time'));
|
return setError(t('home:form.errors.no_time'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await api.post('/event', {
|
const response = await api.post('/event', {
|
||||||
|
|
@ -131,23 +131,23 @@ const Create = ({ offline }) => {
|
||||||
times: times,
|
times: times,
|
||||||
timezone: data.timezone,
|
timezone: data.timezone,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
setCreatedEvent(response.data);
|
setCreatedEvent(response.data)
|
||||||
addRecent({
|
addRecent({
|
||||||
id: response.data.id,
|
id: response.data.id,
|
||||||
created: response.data.created,
|
created: response.data.created,
|
||||||
name: response.data.name,
|
name: response.data.name,
|
||||||
});
|
})
|
||||||
gtag('event', 'create_event', {
|
gtag('event', 'create_event', {
|
||||||
'event_category': 'create',
|
'event_category': 'create',
|
||||||
});
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(t('home:form.errors.unknown'));
|
setError(t('home:form.errors.unknown'))
|
||||||
console.error(e);
|
console.error(e)
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -162,16 +162,16 @@ const Create = ({ offline }) => {
|
||||||
<h2>{createdEvent?.name}</h2>
|
<h2>{createdEvent?.name}</h2>
|
||||||
<ShareInfo
|
<ShareInfo
|
||||||
onClick={() => navigator.clipboard?.writeText(`https://crab.fit/${createdEvent.id}`)
|
onClick={() => navigator.clipboard?.writeText(`https://crab.fit/${createdEvent.id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setCopied(t('event:nav.copied'));
|
setCopied(t('event:nav.copied'))
|
||||||
setTimeout(() => setCopied(null), 1000);
|
setTimeout(() => setCopied(null), 1000)
|
||||||
gtag('event', 'copy_link', {
|
gtag('event', 'copy_link', {
|
||||||
'event_category': 'event',
|
'event_category': 'event',
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((e) => console.error('Failed to copy', e))
|
})
|
||||||
|
.catch(e => console.error('Failed to copy', e))
|
||||||
}
|
}
|
||||||
title={!!navigator.clipboard ? t('event:nav.title') : ''}
|
title={navigator.clipboard ? t('event:nav.title') : ''}
|
||||||
>{copied ?? `https://crab.fit/${createdEvent?.id}`}</ShareInfo>
|
>{copied ?? `https://crab.fit/${createdEvent?.id}`}</ShareInfo>
|
||||||
<ShareInfo>
|
<ShareInfo>
|
||||||
{/* eslint-disable-next-line */}
|
{/* eslint-disable-next-line */}
|
||||||
|
|
@ -236,7 +236,7 @@ const Create = ({ offline }) => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Create;
|
export default Create
|
||||||
|
|
@ -1,50 +1,50 @@
|
||||||
import styled from '@emotion/styled';
|
import { styled } from 'goober'
|
||||||
|
|
||||||
export const StyledMain = styled.div`
|
export const StyledMain = styled('div')`
|
||||||
width: 600px;
|
width: 600px;
|
||||||
margin: 10px auto;
|
margin: 10px auto;
|
||||||
max-width: calc(100% - 30px);
|
max-width: calc(100% - 30px);
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const CreateForm = styled.form`
|
export const CreateForm = styled('form')`
|
||||||
margin: 0 0 30px;
|
margin: 0 0 30px;
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const TitleSmall = styled.span`
|
export const TitleSmall = styled('span')`
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: 'Samurai Bob', sans-serif;
|
font-family: 'Samurai Bob', sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: ${props => props.theme.primaryDark};
|
color: var(--secondary);
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const TitleLarge = styled.h1`
|
export const TitleLarge = styled('h1')`
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: ${props => props.theme.primary};
|
color: var(--primary);
|
||||||
font-family: 'Molot', sans-serif;
|
font-family: 'Molot', sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
text-shadow: 0 3px 0 ${props => props.theme.primaryDark};
|
text-shadow: 0 3px 0 var(--secondary);
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const P = styled.p`
|
export const P = styled('p')`
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 1.6em;
|
line-height: 1.6em;
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const OfflineMessage = styled.div`
|
export const OfflineMessage = styled('div')`
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 50px 0 20px;
|
margin: 50px 0 20px;
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const ShareInfo = styled.p`
|
export const ShareInfo = styled('p')`
|
||||||
margin: 6px 0;
|
margin: 6px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
|
@ -54,7 +54,7 @@ export const ShareInfo = styled.p`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: ${props.theme.primaryDark};
|
color: var(--secondary);
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
`;
|
`
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form'
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react'
|
||||||
import { useTranslation, Trans } from 'react-i18next';
|
import { useTranslation, Trans } from 'react-i18next'
|
||||||
|
import { useParams } from 'react-router-dom'
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs'
|
||||||
import utc from 'dayjs/plugin/utc';
|
import utc from 'dayjs/plugin/utc'
|
||||||
import timezone from 'dayjs/plugin/timezone';
|
import timezone from 'dayjs/plugin/timezone'
|
||||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Footer,
|
Footer,
|
||||||
|
|
@ -17,9 +18,9 @@ import {
|
||||||
AvailabilityEditor,
|
AvailabilityEditor,
|
||||||
Error,
|
Error,
|
||||||
Logo,
|
Logo,
|
||||||
} from 'components';
|
} from '/src/components'
|
||||||
|
|
||||||
import { StyledMain } from '../Home/homeStyle';
|
import { StyledMain } from '../Home/Home.styles'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
EventName,
|
EventName,
|
||||||
|
|
@ -30,232 +31,227 @@ import {
|
||||||
ShareInfo,
|
ShareInfo,
|
||||||
Tabs,
|
Tabs,
|
||||||
Tab,
|
Tab,
|
||||||
} from './eventStyle';
|
} from './Event.styles'
|
||||||
|
|
||||||
import api from 'services';
|
import api from '/src/services'
|
||||||
import { useSettingsStore, useRecentsStore, useLocaleUpdateStore } from 'stores';
|
import { useSettingsStore, useRecentsStore, useLocaleUpdateStore } from '/src/stores'
|
||||||
|
|
||||||
import timezones from 'res/timezones.json';
|
import timezones from '/src/res/timezones.json'
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat);
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
const Event = (props) => {
|
const Event = () => {
|
||||||
const timeFormat = useSettingsStore(state => state.timeFormat);
|
const timeFormat = useSettingsStore(state => state.timeFormat)
|
||||||
const weekStart = useSettingsStore(state => state.weekStart);
|
const weekStart = useSettingsStore(state => state.weekStart)
|
||||||
|
|
||||||
const addRecent = useRecentsStore(state => state.addRecent);
|
const addRecent = useRecentsStore(state => state.addRecent)
|
||||||
const removeRecent = useRecentsStore(state => state.removeRecent);
|
const removeRecent = useRecentsStore(state => state.removeRecent)
|
||||||
const locale = useLocaleUpdateStore(state => state.locale);
|
const locale = useLocaleUpdateStore(state => state.locale)
|
||||||
|
|
||||||
const { t } = useTranslation(['common', 'event']);
|
const { t } = useTranslation(['common', 'event'])
|
||||||
|
|
||||||
const { register, handleSubmit, setFocus, reset } = useForm();
|
const { register, handleSubmit, setFocus, reset } = useForm()
|
||||||
const { id } = props.match.params;
|
const { id } = useParams()
|
||||||
const { offline } = props;
|
const [timezone, setTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone)
|
||||||
const [timezone, setTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone);
|
const [user, setUser] = useState(null)
|
||||||
const [user, setUser] = useState(null);
|
const [password, setPassword] = useState(null)
|
||||||
const [password, setPassword] = useState(null);
|
const [tab, setTab] = useState(user ? 'you' : 'group')
|
||||||
const [tab, setTab] = useState(user ? 'you' : 'group');
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoginLoading, setIsLoginLoading] = useState(false)
|
||||||
const [isLoginLoading, setIsLoginLoading] = useState(false);
|
const [error, setError] = useState(null)
|
||||||
const [error, setError] = useState(null);
|
const [event, setEvent] = useState(null)
|
||||||
const [event, setEvent] = useState(null);
|
const [people, setPeople] = useState([])
|
||||||
const [people, setPeople] = useState([]);
|
|
||||||
|
|
||||||
const [times, setTimes] = useState([]);
|
const [times, setTimes] = useState([])
|
||||||
const [timeLabels, setTimeLabels] = useState([]);
|
const [timeLabels, setTimeLabels] = useState([])
|
||||||
const [dates, setDates] = useState([]);
|
const [dates, setDates] = useState([])
|
||||||
const [min, setMin] = useState(0);
|
const [min, setMin] = useState(0)
|
||||||
const [max, setMax] = useState(0);
|
const [max, setMax] = useState(0)
|
||||||
|
|
||||||
const [copied, setCopied] = useState(null);
|
const [copied, setCopied] = useState(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchEvent = async () => {
|
const fetchEvent = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`/event/${id}`);
|
const response = await api.get(`/event/${id}`)
|
||||||
|
|
||||||
setEvent(response.data);
|
setEvent(response.data)
|
||||||
addRecent({
|
addRecent({
|
||||||
id: response.data.id,
|
id: response.data.id,
|
||||||
created: response.data.created,
|
created: response.data.created,
|
||||||
name: response.data.name,
|
name: response.data.name,
|
||||||
});
|
})
|
||||||
document.title = `${response.data.name} | Crab Fit`;
|
document.title = `${response.data.name} | Crab Fit`
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e)
|
||||||
if (e.status === 404) {
|
if (e.status === 404) {
|
||||||
removeRecent(id);
|
removeRecent(id)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
fetchEvent();
|
fetchEvent()
|
||||||
}, [id, addRecent, removeRecent]);
|
}, [id, addRecent, removeRecent])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchPeople = async () => {
|
const fetchPeople = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`/event/${id}/people`);
|
const response = await api.get(`/event/${id}/people`)
|
||||||
const adjustedPeople = response.data.people.map(person => ({
|
const adjustedPeople = response.data.people.map(person => ({
|
||||||
...person,
|
...person,
|
||||||
availability: (!!person.availability.length && person.availability[0].length === 13)
|
availability: (!!person.availability.length && person.availability[0].length === 13)
|
||||||
? person.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY'))
|
? person.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY'))
|
||||||
: person.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')),
|
: person.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')),
|
||||||
}));
|
}))
|
||||||
setPeople(adjustedPeople);
|
setPeople(adjustedPeople)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tab === 'group') {
|
if (tab === 'group') {
|
||||||
fetchPeople();
|
fetchPeople()
|
||||||
}
|
}
|
||||||
}, [tab, id, timezone]);
|
}, [tab, id, timezone])
|
||||||
|
|
||||||
// Convert to timezone and expand minute segments
|
// Convert to timezone and expand minute segments
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (event) {
|
if (event) {
|
||||||
const isSpecificDates = event.times[0].length === 13;
|
const isSpecificDates = event.times[0].length === 13
|
||||||
setTimes(event.times.reduce(
|
setTimes(event.times.reduce(
|
||||||
(allTimes, time) => {
|
(allTimes, time) => {
|
||||||
const date = isSpecificDates ?
|
const date = isSpecificDates ?
|
||||||
dayjs(time, 'HHmm-DDMMYYYY').utc(true).tz(timezone)
|
dayjs(time, 'HHmm-DDMMYYYY').utc(true).tz(timezone)
|
||||||
: dayjs(time, 'HHmm').day(time.substring(5)).utc(true).tz(timezone);
|
: dayjs(time, 'HHmm').day(time.substring(5)).utc(true).tz(timezone)
|
||||||
const format = isSpecificDates ? 'HHmm-DDMMYYYY' : 'HHmm-d';
|
const format = isSpecificDates ? 'HHmm-DDMMYYYY' : 'HHmm-d'
|
||||||
return [
|
return [
|
||||||
...allTimes,
|
...allTimes,
|
||||||
date.minute(0).format(format),
|
date.minute(0).format(format),
|
||||||
date.minute(15).format(format),
|
date.minute(15).format(format),
|
||||||
date.minute(30).format(format),
|
date.minute(30).format(format),
|
||||||
date.minute(45).format(format),
|
date.minute(45).format(format),
|
||||||
];
|
]
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
).sort((a, b) => {
|
).sort((a, b) => {
|
||||||
if (isSpecificDates) {
|
if (isSpecificDates) {
|
||||||
return dayjs(a, 'HHmm-DDMMYYYY').diff(dayjs(b, 'HHmm-DDMMYYYY'));
|
return dayjs(a, 'HHmm-DDMMYYYY').diff(dayjs(b, 'HHmm-DDMMYYYY'))
|
||||||
} else {
|
} else {
|
||||||
return dayjs(a, 'HHmm').day((parseInt(a.substring(5))-weekStart % 7 + 7) % 7)
|
return dayjs(a, 'HHmm').day((parseInt(a.substring(5))-weekStart % 7 + 7) % 7)
|
||||||
.diff(dayjs(b, 'HHmm').day((parseInt(b.substring(5))-weekStart % 7 + 7) % 7));
|
.diff(dayjs(b, 'HHmm').day((parseInt(b.substring(5))-weekStart % 7 + 7) % 7))
|
||||||
}
|
}
|
||||||
}));
|
}))
|
||||||
}
|
}
|
||||||
}, [event, timezone, weekStart]);
|
}, [event, timezone, weekStart])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!!times.length && !!people.length) {
|
if (!!times.length && !!people.length) {
|
||||||
setMin(times.reduce((min, time) => {
|
setMin(times.reduce((min, time) => {
|
||||||
let total = people.reduce(
|
const total = people.reduce(
|
||||||
(total, person) => person.availability.includes(time) ? total+1 : total,
|
(total, person) => person.availability.includes(time) ? total+1 : total,
|
||||||
0
|
0
|
||||||
);
|
)
|
||||||
return total < min ? total : min;
|
return total < min ? total : min
|
||||||
},
|
}, Infinity))
|
||||||
Infinity
|
|
||||||
));
|
|
||||||
setMax(times.reduce((max, time) => {
|
setMax(times.reduce((max, time) => {
|
||||||
let total = people.reduce(
|
const total = people.reduce(
|
||||||
(total, person) => person.availability.includes(time) ? total+1 : total,
|
(total, person) => person.availability.includes(time) ? total+1 : total,
|
||||||
0
|
0
|
||||||
);
|
)
|
||||||
return total > max ? total : max;
|
return total > max ? total : max
|
||||||
},
|
}, -Infinity))
|
||||||
-Infinity
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}, [times, people]);
|
}, [times, people])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!!times.length) {
|
if (times.length) {
|
||||||
setTimeLabels(times.reduce((labels, datetime) => {
|
setTimeLabels(times.reduce((labels, datetime) => {
|
||||||
const time = datetime.substring(0, 4);
|
const time = datetime.substring(0, 4)
|
||||||
if (labels.includes(time)) return labels;
|
if (labels.includes(time)) return labels
|
||||||
return [...labels, time];
|
return [...labels, time]
|
||||||
}, [])
|
}, [])
|
||||||
.sort((a, b) => parseInt(a) - parseInt(b))
|
.sort((a, b) => parseInt(a) - parseInt(b))
|
||||||
.reduce((labels, time, i, allTimes) => {
|
.reduce((labels, time, i, allTimes) => {
|
||||||
if (time.substring(2) === '30') return [...labels, { label: '', time }];
|
if (time.substring(2) === '30') return [...labels, { label: '', time }]
|
||||||
if (allTimes.length - 1 === i) return [
|
if (allTimes.length - 1 === i) return [
|
||||||
...labels,
|
...labels,
|
||||||
{ label: '', time },
|
{ label: '', time },
|
||||||
{ label: dayjs(time, 'HHmm').add(1, 'hour').format(timeFormat === '12h' ? 'h A' : 'HH'), time: null }
|
{ label: dayjs(time, 'HHmm').add(1, 'hour').format(timeFormat === '12h' ? 'h A' : 'HH'), time: null }
|
||||||
];
|
]
|
||||||
if (allTimes.length - 1 > i && parseInt(allTimes[i+1].substring(0, 2))-1 > parseInt(time.substring(0, 2))) return [
|
if (allTimes.length - 1 > i && parseInt(allTimes[i+1].substring(0, 2))-1 > parseInt(time.substring(0, 2))) return [
|
||||||
...labels,
|
...labels,
|
||||||
{ label: '', time },
|
{ label: '', time },
|
||||||
{ label: dayjs(time, 'HHmm').add(1, 'hour').format(timeFormat === '12h' ? 'h A' : 'HH'), time: 'space' },
|
{ label: dayjs(time, 'HHmm').add(1, 'hour').format(timeFormat === '12h' ? 'h A' : 'HH'), time: 'space' },
|
||||||
{ label: '', time: 'space' },
|
{ label: '', time: 'space' },
|
||||||
{ label: '', time: 'space' },
|
{ label: '', time: 'space' },
|
||||||
];
|
]
|
||||||
if (time.substring(2) !== '00') return [...labels, { label: '', time }];
|
if (time.substring(2) !== '00') return [...labels, { label: '', time }]
|
||||||
return [...labels, { label: dayjs(time, 'HHmm').format(timeFormat === '12h' ? 'h A' : 'HH'), time }];
|
return [...labels, { label: dayjs(time, 'HHmm').format(timeFormat === '12h' ? 'h A' : 'HH'), time }]
|
||||||
}, []));
|
}, []))
|
||||||
|
|
||||||
setDates(times.reduce((allDates, time) => {
|
setDates(times.reduce((allDates, time) => {
|
||||||
if (time.substring(2, 4) !== '00') return allDates;
|
if (time.substring(2, 4) !== '00') return allDates
|
||||||
const date = time.substring(5);
|
const date = time.substring(5)
|
||||||
if (allDates.includes(date)) return allDates;
|
if (allDates.includes(date)) return allDates
|
||||||
return [...allDates, date];
|
return [...allDates, date]
|
||||||
}, []));
|
}, []))
|
||||||
}
|
}
|
||||||
}, [times, timeFormat, locale]);
|
}, [times, timeFormat, locale])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchUser = async () => {
|
const fetchUser = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await api.post(`/event/${id}/people/${user.name}`, { person: { password } });
|
const response = await api.post(`/event/${id}/people/${user.name}`, { person: { password } })
|
||||||
const adjustedUser = {
|
const adjustedUser = {
|
||||||
...response.data,
|
...response.data,
|
||||||
availability: (!!response.data.availability.length && response.data.availability[0].length === 13)
|
availability: (!!response.data.availability.length && response.data.availability[0].length === 13)
|
||||||
? response.data.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY'))
|
? response.data.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY'))
|
||||||
: response.data.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')),
|
: response.data.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')),
|
||||||
};
|
}
|
||||||
setUser(adjustedUser);
|
setUser(adjustedUser)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
fetchUser();
|
fetchUser()
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [timezone]);
|
}, [timezone]);
|
||||||
|
|
||||||
const onSubmit = async data => {
|
const onSubmit = async data => {
|
||||||
if (!data.name || data.name.length === 0) {
|
if (!data.name || data.name.length === 0) {
|
||||||
setFocus('name');
|
setFocus('name')
|
||||||
return setError(t('event:form.errors.name_required'));
|
return setError(t('event:form.errors.name_required'))
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsLoginLoading(true);
|
setIsLoginLoading(true)
|
||||||
setError(null);
|
setError(null)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await api.post(`/event/${id}/people/${data.name}`, {
|
const response = await api.post(`/event/${id}/people/${data.name}`, {
|
||||||
person: {
|
person: {
|
||||||
password: data.password,
|
password: data.password,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
setPassword(data.password);
|
setPassword(data.password)
|
||||||
const adjustedUser = {
|
const adjustedUser = {
|
||||||
...response.data,
|
...response.data,
|
||||||
availability: (!!response.data.availability.length && response.data.availability[0].length === 13)
|
availability: (!!response.data.availability.length && response.data.availability[0].length === 13)
|
||||||
? response.data.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY'))
|
? response.data.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY'))
|
||||||
: response.data.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')),
|
: response.data.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')),
|
||||||
};
|
}
|
||||||
setUser(adjustedUser);
|
setUser(adjustedUser)
|
||||||
setTab('you');
|
setTab('you')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.status === 401) {
|
if (e.status === 401) {
|
||||||
setError(t('event:form.errors.password_incorrect'));
|
setError(t('event:form.errors.password_incorrect'))
|
||||||
} else if (e.status === 404) {
|
} else if (e.status === 404) {
|
||||||
// Create user
|
// Create user
|
||||||
try {
|
try {
|
||||||
|
|
@ -264,25 +260,25 @@ const Event = (props) => {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
password: data.password,
|
password: data.password,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
setPassword(data.password);
|
setPassword(data.password)
|
||||||
setUser({
|
setUser({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
availability: [],
|
availability: [],
|
||||||
});
|
})
|
||||||
setTab('you');
|
setTab('you')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(t('event:form.errors.unknown'));
|
setError(t('event:form.errors.unknown'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoginLoading(false);
|
setIsLoginLoading(false)
|
||||||
gtag('event', 'login', {
|
gtag('event', 'login', {
|
||||||
'event_category': 'event',
|
'event_category': 'event',
|
||||||
});
|
})
|
||||||
reset();
|
reset()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -291,39 +287,32 @@ const Event = (props) => {
|
||||||
|
|
||||||
{(!!event || isLoading) ? (
|
{(!!event || isLoading) ? (
|
||||||
<>
|
<>
|
||||||
<EventName isLoading={isLoading}>{event?.name}</EventName>
|
<EventName $isLoading={isLoading}>{event?.name}</EventName>
|
||||||
<EventDate isLoading={isLoading} locale={locale} title={event?.created && dayjs.unix(event?.created).format('D MMMM, YYYY')}>{event?.created && t('common:created', { date: dayjs.unix(event?.created).fromNow() })}</EventDate>
|
<EventDate $isLoading={isLoading} locale={locale} title={event?.created && dayjs.unix(event?.created).format('D MMMM, YYYY')}>{event?.created && t('common:created', { date: dayjs.unix(event?.created).fromNow() })}</EventDate>
|
||||||
<ShareInfo
|
<ShareInfo
|
||||||
onClick={() => navigator.clipboard?.writeText(`https://crab.fit/${id}`)
|
onClick={() => navigator.clipboard?.writeText(`https://crab.fit/${id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setCopied(t('event:nav.copied'));
|
setCopied(t('event:nav.copied'))
|
||||||
setTimeout(() => setCopied(null), 1000);
|
setTimeout(() => setCopied(null), 1000)
|
||||||
gtag('event', 'copy_link', {
|
gtag('event', 'copy_link', {
|
||||||
'event_category': 'event',
|
'event_category': 'event',
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((e) => console.error('Failed to copy', e))
|
})
|
||||||
|
.catch(e => console.error('Failed to copy', e))
|
||||||
}
|
}
|
||||||
title={!!navigator.clipboard ? t('event:nav.title') : ''}
|
title={navigator.clipboard ? t('event:nav.title') : ''}
|
||||||
>{copied ?? `https://crab.fit/${id}`}</ShareInfo>
|
>{copied ?? `https://crab.fit/${id}`}</ShareInfo>
|
||||||
<ShareInfo isLoading={isLoading} className="instructions">
|
<ShareInfo $isLoading={isLoading} className="instructions">
|
||||||
{!!event?.name &&
|
{!!event?.name &&
|
||||||
<Trans i18nKey="event:nav.shareinfo">Copy the link to this page, or share via <a onClick={() => gtag('event', 'send_email', { 'event_category': 'event' })} href={`mailto:?subject=${encodeURIComponent(t('event:nav.email_subject', { event_name: event?.name }))}&body=${encodeURIComponent(`${t('event:nav.email_body')} https://crab.fit/${id}`)}`}>email</a>.</Trans>
|
<Trans i18nKey="event:nav.shareinfo">Copy the link to this page, or share via <a onClick={() => gtag('event', 'send_email', { 'event_category': 'event' })} href={`mailto:?subject=${encodeURIComponent(t('event:nav.email_subject', { event_name: event?.name }))}&body=${encodeURIComponent(`${t('event:nav.email_body')} https://crab.fit/${id}`)}`}>email</a>.</Trans>
|
||||||
}
|
}
|
||||||
</ShareInfo>
|
</ShareInfo>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
offline ? (
|
<div style={{ margin: '100px 0' }}>
|
||||||
<div style={{ margin: '100px 0' }}>
|
<EventName>{t('event:error.title')}</EventName>
|
||||||
<EventName>{t('event:offline.title')}</EventName>
|
<ShareInfo>{t('event:error.body')}</ShareInfo>
|
||||||
<ShareInfo><Trans i18nKey="event:offline.body" /></ShareInfo>
|
</div>
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div style={{ margin: '100px 0' }}>
|
|
||||||
<EventName>{t('event:error.title')}</EventName>
|
|
||||||
<ShareInfo>{t('event:error.body')}</ShareInfo>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
</StyledMain>
|
</StyledMain>
|
||||||
|
|
||||||
|
|
@ -335,9 +324,9 @@ const Event = (props) => {
|
||||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', margin: '20px 0', flexWrap: 'wrap', gap: '10px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', margin: '20px 0', flexWrap: 'wrap', gap: '10px' }}>
|
||||||
<h2 style={{ margin: 0 }}>{t('event:form.signed_in', { name: user.name })}</h2>
|
<h2 style={{ margin: 0 }}>{t('event:form.signed_in', { name: user.name })}</h2>
|
||||||
<Button small onClick={() => {
|
<Button small onClick={() => {
|
||||||
setTab('group');
|
setTab('group')
|
||||||
setUser(null);
|
setUser(null)
|
||||||
setPassword(null);
|
setPassword(null)
|
||||||
}}>{t('event:form.logout_button')}</Button>
|
}}>{t('event:form.logout_button')}</Button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -363,7 +352,7 @@ const Event = (props) => {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
isLoading={isLoginLoading}
|
$isLoading={isLoginLoading}
|
||||||
disabled={isLoginLoading || isLoading}
|
disabled={isLoginLoading || isLoading}
|
||||||
>{t('event:form.button')}</Button>
|
>{t('event:form.button')}</Button>
|
||||||
</LoginForm>
|
</LoginForm>
|
||||||
|
|
@ -383,8 +372,8 @@ const Event = (props) => {
|
||||||
/>
|
/>
|
||||||
{/* eslint-disable-next-line */}
|
{/* eslint-disable-next-line */}
|
||||||
{event?.timezone && event.timezone !== timezone && <p><Trans i18nKey="event:form.created_in_timezone">This event was created in the timezone <strong>{{timezone: event.timezone}}</strong>. <a href="#" onClick={e => {
|
{event?.timezone && event.timezone !== timezone && <p><Trans i18nKey="event:form.created_in_timezone">This event was created in the timezone <strong>{{timezone: event.timezone}}</strong>. <a href="#" onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
setTimezone(event.timezone);
|
setTimezone(event.timezone)
|
||||||
}}>Click here</a> to use it.</Trans></p>}
|
}}>Click here</a> to use it.</Trans></p>}
|
||||||
{((
|
{((
|
||||||
Intl.DateTimeFormat().resolvedOptions().timeZone !== timezone
|
Intl.DateTimeFormat().resolvedOptions().timeZone !== timezone
|
||||||
|
|
@ -395,8 +384,8 @@ const Event = (props) => {
|
||||||
)) && (
|
)) && (
|
||||||
/* eslint-disable-next-line */
|
/* eslint-disable-next-line */
|
||||||
<p><Trans i18nKey="event:form.local_timezone">Your local timezone is detected to be <strong>{{timezone: Intl.DateTimeFormat().resolvedOptions().timeZone}}</strong>. <a href="#" onClick={e => {
|
<p><Trans i18nKey="event:form.local_timezone">Your local timezone is detected to be <strong>{{timezone: Intl.DateTimeFormat().resolvedOptions().timeZone}}</strong>. <a href="#" onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
setTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone);
|
setTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone)
|
||||||
}}>Click here</a> to use it.</Trans></p>
|
}}>Click here</a> to use it.</Trans></p>
|
||||||
)}
|
)}
|
||||||
</StyledMain>
|
</StyledMain>
|
||||||
|
|
@ -407,11 +396,11 @@ const Event = (props) => {
|
||||||
<Tab
|
<Tab
|
||||||
href="#you"
|
href="#you"
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
if (user) {
|
if (user) {
|
||||||
setTab('you');
|
setTab('you')
|
||||||
} else {
|
} else {
|
||||||
setFocus('name');
|
setFocus('name')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
selected={tab === 'you'}
|
selected={tab === 'you'}
|
||||||
|
|
@ -421,8 +410,8 @@ const Event = (props) => {
|
||||||
<Tab
|
<Tab
|
||||||
href="#group"
|
href="#group"
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
setTab('group');
|
setTab('group')
|
||||||
}}
|
}}
|
||||||
selected={tab === 'group'}
|
selected={tab === 'group'}
|
||||||
>{t('event:tabs.group')}</Tab>
|
>{t('event:tabs.group')}</Tab>
|
||||||
|
|
@ -451,21 +440,21 @@ const Event = (props) => {
|
||||||
isSpecificDates={!!dates.length && dates[0].length === 8}
|
isSpecificDates={!!dates.length && dates[0].length === 8}
|
||||||
value={user.availability}
|
value={user.availability}
|
||||||
onChange={async availability => {
|
onChange={async availability => {
|
||||||
const oldAvailability = [...user.availability];
|
const oldAvailability = [...user.availability]
|
||||||
const utcAvailability = (!!availability.length && availability[0].length === 13)
|
const utcAvailability = (!!availability.length && availability[0].length === 13)
|
||||||
? availability.map(date => dayjs.tz(date, 'HHmm-DDMMYYYY', timezone).utc().format('HHmm-DDMMYYYY'))
|
? availability.map(date => dayjs.tz(date, 'HHmm-DDMMYYYY', timezone).utc().format('HHmm-DDMMYYYY'))
|
||||||
: availability.map(date => dayjs.tz(date, 'HHmm', timezone).day(date.substring(5)).utc().format('HHmm-d'));
|
: availability.map(date => dayjs.tz(date, 'HHmm', timezone).day(date.substring(5)).utc().format('HHmm-d'))
|
||||||
setUser({ ...user, availability });
|
setUser({ ...user, availability })
|
||||||
try {
|
try {
|
||||||
await api.patch(`/event/${id}/people/${user.name}`, {
|
await api.patch(`/event/${id}/people/${user.name}`, {
|
||||||
person: {
|
person: {
|
||||||
password,
|
password,
|
||||||
availability: utcAvailability,
|
availability: utcAvailability,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e)
|
||||||
setUser({ ...user, oldAvailability });
|
setUser({ ...user, oldAvailability })
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -476,7 +465,7 @@ const Event = (props) => {
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Event;
|
export default Event
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
import styled from '@emotion/styled';
|
import { styled } from 'goober'
|
||||||
|
|
||||||
export const EventName = styled.h1`
|
export const EventName = styled('h1')`
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
margin: 20px 0 5px;
|
margin: 20px 0 5px;
|
||||||
|
|
||||||
${props => props.isLoading && `
|
${props => props.$isLoading && `
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
background-color: ${props.theme.loading};
|
background-color: var(--loading);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const EventDate = styled.span`
|
export const EventDate = styled('span')`
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
@ -27,14 +27,14 @@ export const EventDate = styled.span`
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: .01em;
|
letter-spacing: .01em;
|
||||||
|
|
||||||
${props => props.isLoading && `
|
${props => props.$isLoading && `
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
background-color: ${props.theme.loading};
|
background-color: var(--loading);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
|
@ -44,9 +44,9 @@ export const EventDate = styled.span`
|
||||||
content: ' - ' attr(title);
|
content: ' - ' attr(title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const LoginForm = styled.form`
|
export const LoginForm = styled('form')`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr auto;
|
grid-template-columns: 1fr 1fr auto;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
|
@ -62,36 +62,36 @@ export const LoginForm = styled.form`
|
||||||
--btn-width: 100%;
|
--btn-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const LoginSection = styled.section`
|
export const LoginSection = styled('section')`
|
||||||
background-color: ${props => props.theme.primaryBackground};
|
background-color: var(--surface);
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const Info = styled.p`
|
export const Info = styled('p')`
|
||||||
margin: 18px 0;
|
margin: 18px 0;
|
||||||
opacity: .6;
|
opacity: .6;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const ShareInfo = styled.p`
|
export const ShareInfo = styled('p')`
|
||||||
margin: 6px 0;
|
margin: 6px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
|
||||||
${props => props.isLoading && `
|
${props => props.$isLoading && `
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
background-color: ${props.theme.loading};
|
background-color: var(--loading);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
|
@ -100,7 +100,7 @@ export const ShareInfo = styled.p`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: ${props.theme.mode === 'light' ? props.theme.primaryDark : props.theme.primaryLight};
|
color: var(--secondary);
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
|
||||||
|
|
@ -109,40 +109,40 @@ export const ShareInfo = styled.p`
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const Tabs = styled.div`
|
export const Tabs = styled('div')`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 30px 0 20px;
|
margin: 30px 0 20px;
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
|
|
||||||
export const Tab = styled.a`
|
export const Tab = styled('a')`
|
||||||
user-select: none;
|
user-select: none;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: block;
|
display: block;
|
||||||
color: ${props => props.theme.text};
|
color: var(--text);
|
||||||
padding: 8px 18px;
|
padding: 8px 18px;
|
||||||
background-color: ${props => props.theme.primaryBackground};
|
background-color: var(--surface);
|
||||||
border: 1px solid ${props => props.theme.primary};
|
border: 1px solid var(--primary);
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
border-top-left-radius: 5px;
|
border-top-left-radius: 5px;
|
||||||
border-top-right-radius: 5px;
|
border-top-right-radius: 5px;
|
||||||
|
|
||||||
${props => props.selected && `
|
${props => props.$selected && `
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
background-color: ${props.theme.primary};
|
background-color: var(--primary);
|
||||||
border-color: ${props.theme.primary};
|
border-color: var(--primary);
|
||||||
`}
|
`}
|
||||||
|
|
||||||
${props => props.disabled && `
|
${props => props.disabled && `
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
`}
|
`}
|
||||||
`;
|
`
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { lazy } from 'react'
|
import { lazy } from 'react'
|
||||||
|
|
||||||
export const Home = lazy(() => import('./Home/Home'))
|
export const Home = lazy(() => import('./Home/Home'))
|
||||||
//export const Event = lazy(() => import('./Event/Event'))
|
export const Event = lazy(() => import('./Event/Event'))
|
||||||
//export const Create = lazy(() => import('./Create/Create'))
|
export const Create = lazy(() => import('./Create/Create'))
|
||||||
export const Help = lazy(() => import('./Help/Help'))
|
export const Help = lazy(() => import('./Help/Help'))
|
||||||
export const Privacy = lazy(() => import('./Privacy/Privacy'))
|
export const Privacy = lazy(() => import('./Privacy/Privacy'))
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,38 @@
|
||||||
/* eslint-disable no-restricted-globals */
|
/* eslint-disable no-restricted-globals */
|
||||||
|
|
||||||
import { clientsClaim, skipWaiting } from 'workbox-core';
|
import { clientsClaim, skipWaiting } from 'workbox-core'
|
||||||
import { ExpirationPlugin } from 'workbox-expiration';
|
import { ExpirationPlugin } from 'workbox-expiration'
|
||||||
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
|
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching'
|
||||||
import { registerRoute } from 'workbox-routing';
|
import { registerRoute } from 'workbox-routing'
|
||||||
import { StaleWhileRevalidate, NetworkFirst } from 'workbox-strategies';
|
import { StaleWhileRevalidate, NetworkFirst } from 'workbox-strategies'
|
||||||
|
|
||||||
skipWaiting();
|
skipWaiting()
|
||||||
clientsClaim();
|
clientsClaim()
|
||||||
|
|
||||||
// Injection point
|
// Injection point
|
||||||
precacheAndRoute(self.__WB_MANIFEST);
|
precacheAndRoute(self.__WB_MANIFEST)
|
||||||
|
|
||||||
const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
|
const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$')
|
||||||
registerRoute(
|
registerRoute(
|
||||||
// Return false to exempt requests from being fulfilled by index.html.
|
// Return false to exempt requests from being fulfilled by index.html.
|
||||||
({ request, url }) => {
|
({ request, url }) => {
|
||||||
// If this isn't a navigation, skip.
|
// If this isn't a navigation, skip.
|
||||||
if (request.mode !== 'navigate') {
|
if (request.mode !== 'navigate') {
|
||||||
return false;
|
return false
|
||||||
} // If this is a URL that starts with /_, skip.
|
} // If this is a URL that starts with /_, skip.
|
||||||
|
|
||||||
if (url.pathname.startsWith('/_')) {
|
if (url.pathname.startsWith('/_')) {
|
||||||
return false;
|
return false
|
||||||
} // If this looks like a URL for a resource, because it contains // a file extension, skip.
|
} // If this looks like a URL for a resource, because it contains // a file extension, skip.
|
||||||
|
|
||||||
if (url.pathname.match(fileExtensionRegexp)) {
|
if (url.pathname.match(fileExtensionRegexp)) {
|
||||||
return false;
|
return false
|
||||||
} // Return true to signal that we want to use the handler.
|
} // Return true to signal that we want to use the handler.
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
},
|
},
|
||||||
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
|
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
|
||||||
);
|
)
|
||||||
|
|
||||||
registerRoute(
|
registerRoute(
|
||||||
// Add in any other file extensions or routing criteria as needed.
|
// Add in any other file extensions or routing criteria as needed.
|
||||||
|
|
@ -54,7 +54,7 @@ registerRoute(
|
||||||
new ExpirationPlugin({ maxEntries: 50 }),
|
new ExpirationPlugin({ maxEntries: 50 }),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
registerRoute(
|
registerRoute(
|
||||||
// Add in any other file extensions or routing criteria as needed.
|
// Add in any other file extensions or routing criteria as needed.
|
||||||
|
|
@ -62,4 +62,4 @@ registerRoute(
|
||||||
new NetworkFirst({
|
new NetworkFirst({
|
||||||
cacheName: 'i18n',
|
cacheName: 'i18n',
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue