Update home page

This commit is contained in:
Ben Grant 2022-08-16 15:07:13 +10:00
parent a67aee24dc
commit 2d32a1b036
18 changed files with 158 additions and 179 deletions

View file

@ -63,9 +63,9 @@ const App = () => {
<Settings /> <Settings />
<Routes> <Routes>
{/* <Route path="/" element={<Pages.Home />} /> */} <Route path="/" element={<Pages.Home />} />
{/* <Route path="/" element={<Pages.Help />} /> */} <Route path="/how-to" element={<Pages.Help />} />
<Route path="/" 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>

View file

@ -84,8 +84,8 @@ const AvailabilityViewer = ({
<DayLabel>{parsedDate.format('ddd')}</DayLabel> <DayLabel>{parsedDate.format('ddd')}</DayLabel>
<Times <Times
borderRight={last} $borderRight={last}
borderLeft={i === 0 || (parsedDate).diff(isSpecificDates ? dayjs(dates[i-1], 'DDMMYYYY') : dayjs().day(dates[i-1]), 'day') > 1} $borderLeft={i === 0 || (parsedDate).diff(isSpecificDates ? dayjs(dates[i-1], 'DDMMYYYY') : dayjs().day(dates[i-1]), 'day') > 1}
> >
{timeLabels.map((timeLabel, i) => { {timeLabels.map((timeLabel, i) => {
if (!timeLabel.time) return null if (!timeLabel.time) return null
@ -102,13 +102,13 @@ const AvailabilityViewer = ({
return ( return (
<Time <Time
key={i} key={i}
time={time} $time={time}
className="time" className="time"
peopleCount={focusCount !== null && focusCount !== peopleHere.length ? 0 : peopleHere.length} $peopleCount={focusCount !== null && focusCount !== peopleHere.length ? 0 : peopleHere.length}
aria-label={peopleHere.join(', ')} aria-label={peopleHere.join(', ')}
maxPeople={tempFocus !== null ? 1 : Math.min(max, filteredPeople.length)} $maxPeople={tempFocus !== null ? 1 : Math.min(max, filteredPeople.length)}
minPeople={tempFocus !== null ? 0 : Math.min(min, filteredPeople.length)} $minPeople={tempFocus !== null ? 0 : Math.min(min, filteredPeople.length)}
highlight={highlight} $highlight={highlight}
onMouseEnter={e => { onMouseEnter={e => {
const cellBox = e.currentTarget.getBoundingClientRect() const cellBox = e.currentTarget.getBoundingClientRect()
const wrapperBox = wrapper?.current?.getBoundingClientRect() ?? { x: 0, y: 0 } const wrapperBox = wrapper?.current?.getBoundingClientRect() ?? { x: 0, y: 0 }
@ -170,7 +170,7 @@ const AvailabilityViewer = ({
{people.map((person, i) => {people.map((person, i) =>
<Person <Person
key={i} key={i}
filtered={filteredPeople.includes(person.name)} $filtered={filteredPeople.includes(person.name)}
onClick={() => { onClick={() => {
setTempFocus(null) setTempFocus(null)
if (filteredPeople.includes(person.name)) { if (filteredPeople.includes(person.name)) {
@ -200,8 +200,8 @@ const AvailabilityViewer = ({
{tooltip && ( {tooltip && (
<Tooltip <Tooltip
x={tooltip.x} $x={tooltip.x}
y={tooltip.y} $y={tooltip.y}
> >
<TooltipTitle>{tooltip.available}</TooltipTitle> <TooltipTitle>{tooltip.available}</TooltipTitle>
<TooltipDate>{tooltip.date}</TooltipDate> <TooltipDate>{tooltip.date}</TooltipDate>

View file

@ -1,6 +1,7 @@
import { styled } from 'goober' import { styled } from 'goober'
import { forwardRef } from 'react'
export const Wrapper = styled('div')` export const Wrapper = styled('div', forwardRef)`
overflow-y: visible; overflow-y: visible;
margin: 20px 0; margin: 20px 0;
position: relative; position: relative;
@ -40,12 +41,12 @@ export const Times = styled('div')`
border-left: 1px solid var(--text); border-left: 1px solid var(--text);
border-right: 1px solid var(--text); border-right: 1px solid var(--text);
${props => props.borderLeft && ` ${props => props.$borderLeft && `
border-left: 2px solid var(--text); border-left: 2px solid var(--text);
border-top-left-radius: 3px; border-top-left-radius: 3px;
border-bottom-left-radius: 3px; border-bottom-left-radius: 3px;
`} `}
${props => props.borderRight && ` ${props => props.$borderRight && `
border-right: 2px solid var(--text); border-right: 2px solid var(--text);
border-top-right-radius: 3px; border-top-right-radius: 3px;
border-bottom-right-radius: 3px; border-bottom-right-radius: 3px;
@ -75,19 +76,19 @@ export const Time = styled('div')`
background-origin: border-box; background-origin: border-box;
transition: background-color .1s; transition: background-color .1s;
${props => props.time.slice(2, 4) === '00' && ` ${props => props.$time.slice(2, 4) === '00' && `
border-top: 2px solid var(--text); border-top: 2px solid var(--text);
`} `}
${props => props.time.slice(2, 4) !== '00' && ` ${props => props.$time.slice(2, 4) !== '00' && `
border-top: 2px solid transparent; border-top: 2px solid transparent;
`} `}
${props => props.time.slice(2, 4) === '30' && ` ${props => props.$time.slice(2, 4) === '30' && `
border-top: 2px dotted var(--text); border-top: 2px dotted var(--text);
`} `}
background-color: ${props => `#FF0000${Math.round((props.peopleCount/props.maxPeople)*255).toString(16)}`}; background-color: ${props => `#FF0000${Math.round((props.$peopleCount/props.$maxPeople)*255).toString(16)}`};
${props => props.highlight && props.peopleCount === props.maxPeople && props.peopleCount > 0 && ` ${props => props.$highlight && props.$peopleCount === props.$maxPeople && props.$peopleCount > 0 && `
background-image: repeating-linear-gradient( background-image: repeating-linear-gradient(
45deg, 45deg,
transparent, transparent,
@ -109,8 +110,8 @@ export const Spacer = styled('div')`
export const Tooltip = styled('div')` export const Tooltip = styled('div')`
position: absolute; position: absolute;
top: ${props => props.y}px; top: ${props => props.$y}px;
left: ${props => props.x}px; left: ${props => props.$x}px;
transform: translateX(-50%); transform: translateX(-50%);
border: 1px solid var(--text); border: 1px solid var(--text);
border-radius: 3px; border-radius: 3px;
@ -214,7 +215,7 @@ export const Person = styled('button')`
padding: 2px 8px; padding: 2px 8px;
user-select: none; user-select: none;
${props => props.filtered && ` ${props => props.$filtered && `
background: var(--primary); background: var(--primary);
color: #FFFFFF; color: #FFFFFF;
border-color: var(--primary); border-color: var(--primary);

View file

@ -10,6 +10,7 @@ const Button = ({
secondaryColor, secondaryColor,
small, small,
size, size,
isLoading,
...props ...props
}) => ( }) => (
<Pressable <Pressable
@ -21,6 +22,7 @@ const Button = ({
$secondaryColor={secondaryColor} $secondaryColor={secondaryColor}
$small={small} $small={small}
$size={size} $size={size}
$isLoading={isLoading}
{...props} {...props}
> >
{icon} {icon}

View file

@ -160,12 +160,12 @@ const CalendarField = forwardRef(({
dateRow.map((date, x) => dateRow.map((date, x) =>
<Date <Date
key={y+x} key={y+x}
otherMonth={date.month() !== month} $otherMonth={date.month() !== month}
isToday={date.isToday()} $isToday={date.isToday()}
title={`${date.date()} ${dayjs.months()[date.month()]}${date.isToday() ? ` (${t('form.dates.tooltips.today')})` : ''}`} title={`${date.date()} ${dayjs.months()[date.month()]}${date.isToday() ? ` (${t('form.dates.tooltips.today')})` : ''}`}
selected={selectedDates.includes(date.format('DDMMYYYY'))} $selected={selectedDates.includes(date.format('DDMMYYYY'))}
selecting={selectingDates.includes(date)} $selecting={selectingDates.includes(date)}
mode={mode} $mode={mode}
type="button" type="button"
onKeyPress={e => { onKeyPress={e => {
if (e.key === ' ' || e.key === 'Enter') { if (e.key === ' ' || e.key === 'Enter') {
@ -213,11 +213,11 @@ const CalendarField = forwardRef(({
{(weekStart ? [...dayjs.weekdaysShort().filter((_,i) => i !== 0), dayjs.weekdaysShort()[0]] : dayjs.weekdaysShort()).map((name, i) => {(weekStart ? [...dayjs.weekdaysShort().filter((_,i) => i !== 0), dayjs.weekdaysShort()[0]] : dayjs.weekdaysShort()).map((name, i) =>
<Date <Date
key={name} key={name}
isToday={(weekStart ? [...dayjs.weekdaysShort().filter((_,i) => i !== 0), dayjs.weekdaysShort()[0]] : dayjs.weekdaysShort())[dayjs().day()-weekStart === -1 ? 6 : dayjs().day()-weekStart] === name} $isToday={(weekStart ? [...dayjs.weekdaysShort().filter((_,i) => i !== 0), dayjs.weekdaysShort()[0]] : dayjs.weekdaysShort())[dayjs().day()-weekStart === -1 ? 6 : dayjs().day()-weekStart] === name}
title={(weekStart ? [...dayjs.weekdaysShort().filter((_,i) => i !== 0), dayjs.weekdaysShort()[0]] : dayjs.weekdaysShort())[dayjs().day()-weekStart === -1 ? 6 : dayjs().day()-weekStart] === name ? t('form.dates.tooltips.today') : ''} title={(weekStart ? [...dayjs.weekdaysShort().filter((_,i) => i !== 0), dayjs.weekdaysShort()[0]] : dayjs.weekdaysShort())[dayjs().day()-weekStart === -1 ? 6 : dayjs().day()-weekStart] === name ? t('form.dates.tooltips.today') : ''}
selected={selectedDays.includes(((i + weekStart) % 7 + 7) % 7)} $selected={selectedDays.includes(((i + weekStart) % 7 + 7) % 7)}
selecting={selectingDays.includes(((i + weekStart) % 7 + 7) % 7)} $selecting={selectingDays.includes(((i + weekStart) % 7 + 7) % 7)}
mode={mode} $mode={mode}
type="button" type="button"
onKeyPress={e => { onKeyPress={e => {
if (e.key === ' ' || e.key === 'Enter') { if (e.key === ' ' || e.key === 'Enter') {

View file

@ -86,19 +86,19 @@ export const Date = styled('button')`
user-select: none; user-select: none;
touch-action: none; touch-action: none;
${props => props.otherMonth && ` ${props => props.$otherMonth && `
color: var(--tertiary); color: var(--tertiary);
`} `}
${props => props.isToday && ` ${props => props.$isToday && `
font-weight: 900; font-weight: 900;
color: var(--secondary); color: var(--secondary);
`} `}
${props => (props.selected || (props.mode === 'add' && props.selecting)) && ` ${props => (props.$selected || (props.$mode === 'add' && props.$selecting)) && `
color: ${props.otherMonth ? 'rgba(255,255,255,.5)' : '#FFF'}; color: ${props.$otherMonth ? 'rgba(255,255,255,.5)' : '#FFF'};
background-color: var(--primary); background-color: var(--primary);
`} `}
${props => props.mode === 'remove' && props.selecting && ` ${props => props.$mode === 'remove' && props.$selecting && `
background-color: var(--surface); background-color: var(--surface);
color: ${props.isToday ? 'var(--secondary)' : (props.otherMonth ? 'var(--tertiary)' : 'inherit')}; color: ${props.$isToday ? 'var(--secondary)' : (props.$otherMonth ? 'var(--tertiary)' : 'inherit')};
`} `}
` `

View file

@ -31,8 +31,8 @@ const Legend = ({
{[...Array(max+1-min).keys()].map(i => i+min).map(i => {[...Array(max+1-min).keys()].map(i => i+min).map(i =>
<Grade <Grade
key={i} key={i}
color={`#FF0000${Math.round((i/(max))*255).toString(16)}`} $color={`#FF0000${Math.round((i/(max))*255).toString(16)}`}
highlight={highlight && i === max && max > 0} $highlight={highlight && i === max && max > 0}
onMouseOver={() => onSegmentFocus(i)} onMouseOver={() => onSegmentFocus(i)}
/> />
)} )}

View file

@ -38,9 +38,9 @@ export const Bar = styled('div')`
export const Grade = styled('div')` export const Grade = styled('div')`
flex: 1; flex: 1;
background-color: ${props => props.color}; background-color: ${props => props.$color};
${props => props.highlight && ` ${props => props.$highlight && `
background-image: repeating-linear-gradient( background-image: repeating-linear-gradient(
45deg, 45deg,
var(--primary), var(--primary),

View file

@ -14,8 +14,8 @@ const TextField = forwardRef(({
inline = false, inline = false,
...props ...props
}, ref) => ( }, ref) => (
<Wrapper inline={inline}> <Wrapper $inline={inline}>
{label && <StyledLabel htmlFor={id} inline={inline}>{label}</StyledLabel>} {label && <StyledLabel htmlFor={id} $inline={inline}>{label}</StyledLabel>}
{subLabel && <StyledSubLabel htmlFor={id}>{subLabel}</StyledSubLabel>} {subLabel && <StyledSubLabel htmlFor={id}>{subLabel}</StyledSubLabel>}
<StyledInput id={id} ref={ref} {...props} /> <StyledInput id={id} ref={ref} {...props} />
</Wrapper> </Wrapper>

View file

@ -4,7 +4,7 @@ import { forwardRef } from 'react'
export const Wrapper = styled('div')` export const Wrapper = styled('div')`
margin: 30px 0; margin: 30px 0;
${props => props.inline && ` ${props => props.$inline && `
margin: 0; margin: 0;
`} `}
` `
@ -14,7 +14,7 @@ export const StyledLabel = styled('label')`
padding-bottom: 4px; padding-bottom: 4px;
font-size: 18px; font-size: 18px;
${props => props.inline && ` ${props => props.$inline && `
font-size: 16px; font-size: 16px;
`} `}
` `

View file

@ -68,12 +68,12 @@ const TimeRangeField = forwardRef(({
/> />
<Range ref={rangeRef}> <Range ref={rangeRef}>
<Selected start={start} end={start > end ? 24 : end} /> <Selected $start={start} $end={start > end ? 24 : end} />
{start > end && <Selected start={start > end ? 0 : start} end={end} />} {start > end && <Selected $start={start > end ? 0 : start} $end={end} />}
<Handle <Handle
value={start} $value={start}
label={timeFormat === '24h' ? times[start] : dayjs().hour(times[start]).format('ha')} label={timeFormat === '24h' ? times[start] : dayjs().hour(times[start]).format('ha')}
extraPadding={end - start === 1 ? 'padding-right: 20px;' : (start - end === 1 ? 'padding-left: 20px;' : '')} $extraPadding={end - start === 1 ? 'padding-right: 20px;' : (start - end === 1 ? 'padding-left: 20px;' : '')}
onMouseDown={() => { onMouseDown={() => {
document.addEventListener('mousemove', handleMouseMove) document.addEventListener('mousemove', handleMouseMove)
isStartMoving.current = true isStartMoving.current = true
@ -105,9 +105,9 @@ const TimeRangeField = forwardRef(({
}} }}
/> />
<Handle <Handle
value={end} $value={end}
label={timeFormat === '24h' ? times[end] : dayjs().hour(times[end]).format('ha')} label={timeFormat === '24h' ? times[end] : dayjs().hour(times[end]).format('ha')}
extraPadding={end - start === 1 ? 'padding-left: 20px;' : (start - end === 1 ? 'padding-right: 20px;' : '')} $extraPadding={end - start === 1 ? 'padding-left: 20px;' : (start - end === 1 ? 'padding-right: 20px;' : '')}
onMouseDown={() => { onMouseDown={() => {
document.addEventListener('mousemove', handleMouseMove) document.addEventListener('mousemove', handleMouseMove)
isEndMoving.current = true isEndMoving.current = true

View file

@ -1,4 +1,5 @@
import { styled } from 'goober' import { styled } from 'goober'
import { forwardRef } from 'react'
export const Wrapper = styled('div')` export const Wrapper = styled('div')`
margin: 30px 0; margin: 30px 0;
@ -17,7 +18,7 @@ export const StyledSubLabel = styled('label')`
opacity: .6; opacity: .6;
` `
export const Range = styled('div')` export const Range = styled('div', forwardRef)`
user-select: none; user-select: none;
background-color: var(--surface); background-color: var(--surface);
border: 1px solid var(--primary); border: 1px solid var(--primary);
@ -35,7 +36,7 @@ export const Handle = styled('div')`
border-radius: 3px; border-radius: 3px;
position: absolute; position: absolute;
top: -10px; top: -10px;
left: calc(${props => props.value * 4.166}% - 11px); left: calc(${props => props.$value * 4.166}% - 11px);
cursor: ew-resize; cursor: ew-resize;
touch-action: none; touch-action: none;
transition: left .1s; transition: left .1s;
@ -65,15 +66,15 @@ export const Handle = styled('div')`
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
white-space: nowrap; white-space: nowrap;
${props => props.extraPadding} ${props => props.$extraPadding}
} }
` `
export const Selected = styled('div')` export const Selected = styled('div')`
position: absolute; position: absolute;
height: 100%; height: 100%;
left: ${props => props.start * 4.166}%; left: ${props => props.$start * 4.166}%;
right: calc(100% - ${props => props.end * 4.166}%); right: calc(100% - ${props => props.$end * 4.166}%);
top: 0; top: 0;
background-color: var(--primary); background-color: var(--primary);
border-radius: 2px; border-radius: 2px;

View file

@ -63,7 +63,7 @@ export const FakeTimeRange = styled('div')`
height: calc(100% + 20px); height: calc(100% + 20px);
width: 20px; width: 20px;
border: 1px solid var(--primary); border: 1px solid var(--primary);
background-color: var(--secondary); background-color: var(--tertiary);
border-radius: 3px; border-radius: 3px;
position: absolute; position: absolute;
top: -10px; top: -10px;
@ -79,7 +79,7 @@ export const FakeTimeRange = styled('div')`
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: var(--tertiary); color: var(--secondary);
} }
&:before { &:before {

View file

@ -1,12 +1,12 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react'
import { useHistory, Link } from 'react-router-dom'; import { useNavigate, Link } 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,
@ -18,7 +18,7 @@ import {
Error, Error,
Footer, Footer,
Recents, Recents,
} from 'components'; } from '/src/components'
import { import {
StyledMain, StyledMain,
@ -37,82 +37,82 @@ import {
ButtonArea, ButtonArea,
VideoWrapper, VideoWrapper,
VideoLink, VideoLink,
} from './homeStyle'; } from './Home.styles'
import api from 'services'; import api from '/src/services'
import { detect_browser } from 'utils'; import { detect_browser } from '/src/utils'
import { useTWAStore } from 'stores'; import { useTWAStore } from '/src/stores'
import logo from 'res/logo.svg'; import logo from '/src/res/logo.svg'
import video_thumb from 'res/video_thumb.jpg'; import video_thumb from '/src/res/video_thumb.jpg'
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 Home = ({ offline }) => { const Home = ({ 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 [stats, setStats] = useState({ const [stats, setStats] = useState({
eventCount: null, eventCount: null,
personCount: null, personCount: null,
version: 'loading...', version: 'loading...',
}); })
const [browser, setBrowser] = useState(undefined); const [browser, setBrowser] = useState(undefined)
const [videoPlay, setVideoPlay] = useState(false); const [videoPlay, setVideoPlay] = useState(false)
const { push } = useHistory(); const navigate = useNavigate()
const { t } = useTranslation(['common', 'home']); const { t } = useTranslation(['common', 'home'])
const isTWA = useTWAStore(state => state.TWA); const isTWA = useTWAStore(state => state.TWA)
useEffect(() => { useEffect(() => {
const fetch = async () => { const fetch = async () => {
try { try {
const response = await api.get('/stats'); const response = await api.get('/stats')
setStats(response.data); setStats(response.data)
} catch (e) { } catch (e) {
console.error(e); console.error(e)
} }
}; }
fetch(); fetch()
document.title = 'Crab Fit'; document.title = 'Crab Fit'
setBrowser(detect_browser()); setBrowser(detect_browser())
}, []); }, [])
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) {
@ -120,21 +120,21 @@ const Home = ({ 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', {
@ -143,18 +143,18 @@ const Home = ({ offline }) => {
times: times, times: times,
timezone: data.timezone, timezone: data.timezone,
}, },
}); })
push(`/${response.data.id}`); navigate(`/${response.data.id}`)
gtag('event', 'create_event', { gtag('event', 'create_event', {
'event_category': 'home', 'event_category': 'home',
}); })
} 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,7 +162,7 @@ const Home = ({ offline }) => {
<Center> <Center>
<Logo src={logo} alt="" /> <Logo src={logo} alt="" />
</Center> </Center>
<TitleSmall altChars={/^[A-Za-z ]+$/.test(t('home:create'))}>{t('home:create')}</TitleSmall> <TitleSmall $altChars={/^[A-Za-z ]+$/.test(t('home:create'))}>{t('home:create')}</TitleSmall>
<TitleLarge>CRAB FIT</TitleLarge> <TitleLarge>CRAB FIT</TitleLarge>
<Links> <Links>
<a href="#about">{t('home:nav.about')}</a> / <a href="#donate">{t('home:nav.donate')}</a> <a href="#about">{t('home:nav.about')}</a> / <a href="#donate">{t('home:nav.donate')}</a>
@ -228,11 +228,11 @@ const Home = ({ offline }) => {
<h2>{t('home:about.name')}</h2> <h2>{t('home:about.name')}</h2>
<Stats> <Stats>
<Stat> <Stat>
<StatNumber>{stats.eventCount ?? '1100+'}</StatNumber> <StatNumber>{new Intl.NumberFormat().format(stats.eventCount ?? 7000)}{!stats.eventCount && '+'}</StatNumber>
<StatLabel>{t('home:about.events')}</StatLabel> <StatLabel>{t('home:about.events')}</StatLabel>
</Stat> </Stat>
<Stat> <Stat>
<StatNumber>{stats.personCount ?? '3700+'}</StatNumber> <StatNumber>{new Intl.NumberFormat().format(stats.personCount ?? 25000)}{!stats.personCount && '+'}</StatNumber>
<StatLabel>{t('home:about.availabilities')}</StatLabel> <StatLabel>{t('home:about.availabilities')}</StatLabel>
</Stat> </Stat>
</Stats> </Stats>
@ -240,14 +240,14 @@ const Home = ({ offline }) => {
{videoPlay ? ( {videoPlay ? (
<VideoWrapper> <VideoWrapper>
<iframe width="560" height="315" src="https://www.youtube.com/embed/yXGd4VXZzcY?modestbranding=1&rel=0&autoplay=1" title={t('common:video.title')} frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> <iframe width="560" height="315" src="https://www.youtube.com/embed/yXGd4VXZzcY?modestbranding=1&rel=0&autoplay=1" title={t('common:video.title')} frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>
</VideoWrapper> </VideoWrapper>
) : ( ) : (
<VideoLink <VideoLink
href="https://www.youtube.com/watch?v=yXGd4VXZzcY" href="https://www.youtube.com/watch?v=yXGd4VXZzcY"
onClick={e => { onClick={e => {
e.preventDefault(); e.preventDefault()
setVideoPlay(true); setVideoPlay(true)
}} }}
> >
<img src={video_thumb} alt={t('common:video.button')} /> <img src={video_thumb} alt={t('common:video.button')} />
@ -274,10 +274,10 @@ const Home = ({ offline }) => {
rel="noreferrer noopener" rel="noreferrer noopener"
secondary secondary
>{{ >{{
chrome: t('home:about.chrome_extension'), chrome: t('home:about.chrome_extension'),
firefox: t('home:about.firefox_extension'), firefox: t('home:about.firefox_extension'),
safari: t('home:about.safari_extension'), safari: t('home:about.safari_extension'),
}[browser]}</Button> }[browser]}</Button>
)} )}
<Button <Button
href="https://play.google.com/store/apps/details?id=fit.crab" href="https://play.google.com/store/apps/details?id=fit.crab"
@ -298,7 +298,7 @@ const Home = ({ offline }) => {
<Footer /> <Footer />
</> </>
); )
}; }
export default Home; export default Home

View file

@ -21,7 +21,7 @@ export const TitleSmall = styled('span')`
line-height: 1em; line-height: 1em;
text-transform: uppercase; text-transform: uppercase;
${props => !props.altChars && ` ${props => !props.$altChars && `
font-family: sans-serif; font-family: sans-serif;
font-size: 2rem; font-size: 2rem;
font-weight: 600; font-weight: 600;
@ -163,10 +163,10 @@ export const VideoLink = styled('a')`
margin: 0 auto; margin: 0 auto;
transition: transform .15s; transition: transform .15s;
:hover, :focus { &:hover, &:focus {
transform: translateY(-2px); transform: translateY(-2px);
} }
:active { &:active {
transform: translateY(-1px); transform: translateY(-1px);
} }
@ -188,7 +188,7 @@ export const VideoLink = styled('a')`
text-shadow: 0 0 20px rgba(0,0,0,.8); text-shadow: 0 0 20px rgba(0,0,0,.8);
user-select: none; user-select: none;
::before { &::before {
content: ''; content: '';
display: block; display: block;
height: 2em; height: 2em;
@ -196,7 +196,7 @@ export const VideoLink = styled('a')`
background: currentColor; background: currentColor;
border-radius: 100%; border-radius: 100%;
margin: 0 auto .4em; margin: 0 auto .4em;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='${props => encodeURIComponent(props.theme.primaryDark)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-play'%3E%3Cpolygon points='5 3 19 12 5 21 5 3'%3E%3C/polygon%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='red' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-play'%3E%3Cpolygon points='5 3 19 12 5 21 5 3'%3E%3C/polygon%3E%3C/svg%3E");
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 1em; background-size: 1em;

View file

@ -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'))

View file

@ -8,30 +8,31 @@ const handleError = error => {
} }
const api = { const api = {
get: async (endpoint, data) => { get: async endpoint => {
try { try {
const response = await fetch(API_URL + endpoint) const response = await fetch(API_URL + endpoint)
return Promise.resolve(response) const json = await response.json()
return Promise.resolve(json)
} catch (error) { } catch (error) {
return handleError(error) return handleError(error)
} }
}, },
post: async (endpoint, data, options = {}) => { post: async (endpoint, data, options = {}) => {
try { try {
const response = await instance.post(endpoint, data, options); const response = await fetch(API_URL + endpoint, data, options)
return Promise.resolve(response); return Promise.resolve(response)
} catch (error) { } catch (error) {
return handleError(error); return handleError(error)
} }
}, },
patch: async (endpoint, data) => { patch: async (endpoint, data) => {
try { try {
const response = await instance.patch(endpoint, data); const response = await fetch(API_URL + endpoint, data)
return Promise.resolve(response); return Promise.resolve(response)
} catch (error) { } catch (error) {
return handleError(error); return handleError(error)
} }
}, },
}; }
export default api; export default api

View file

@ -1,26 +0,0 @@
const theme = {
light: {
mode: 'light',
background: '#FFFFFF',
text: '#000000',
primary: '#F79E00',
primaryDark: '#F48600',
primaryLight: '#F4BB60',
primaryBackground: '#FEF2DD',
error: '#D32F2F',
loading: '#DDDDDD',
},
dark: {
mode: 'dark',
background: '#111111',
text: '#DDDDDD',
primary: '#F79E00',
primaryDark: '#CC7313',
primaryLight: '#F4BB60',
primaryBackground: '#30240F',
error: '#E53935',
loading: '#444444',
},
};
export default theme;