A11y and donate popup
This commit is contained in:
parent
decfc2b7e6
commit
2544f3b312
|
|
@ -107,6 +107,11 @@ const App = () => {
|
|||
},
|
||||
})}
|
||||
/>
|
||||
|
||||
<Suspense fallback={<Loading />}>
|
||||
<Settings />
|
||||
</Suspense>
|
||||
|
||||
<Switch>
|
||||
<Route path="/" exact render={props => (
|
||||
<Suspense fallback={<Loading />}>
|
||||
|
|
@ -135,10 +140,6 @@ const App = () => {
|
|||
)} />
|
||||
</Switch>
|
||||
|
||||
<Suspense fallback={<Loading />}>
|
||||
<Settings />
|
||||
</Suspense>
|
||||
|
||||
{eggVisible && <Egg eggKey={eggKey} onClose={() => setEggVisible(false)} />}
|
||||
</ThemeProvider>
|
||||
</BrowserRouter>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,33 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { Button } from 'components';
|
||||
import { useTWAStore } from 'stores';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
Wrapper,
|
||||
Options,
|
||||
} from './donateStyle';
|
||||
|
||||
const PAYMENT_METHOD = 'https://play.google.com/billing';
|
||||
const SKU = 'crab_donation';
|
||||
|
||||
const Donate = ({ onDonate = null }) => {
|
||||
const Donate = () => {
|
||||
const store = useTWAStore();
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
const firstLinkRef = useRef();
|
||||
const buttonRef = useRef();
|
||||
const modalRef = useRef();
|
||||
const [isOpen, _setIsOpen] = useState(false);
|
||||
|
||||
const setIsOpen = open => {
|
||||
_setIsOpen(open);
|
||||
|
||||
if (open) {
|
||||
window.setTimeout(() => firstLinkRef.current.focus(), 150);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (store.TWA === undefined) {
|
||||
store.setTWA(document.referrer.includes('android-app://fit.crab'));
|
||||
|
|
@ -71,7 +89,7 @@ const Donate = ({ onDonate = null }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: 6, marginLeft: 12 }}>
|
||||
<Wrapper>
|
||||
<a
|
||||
onClick={event => {
|
||||
gtag('event', 'donate', { 'event_category': 'donate' });
|
||||
|
|
@ -82,14 +100,15 @@ const Donate = ({ onDonate = null }) => {
|
|||
alert(t('donate.messages.error'));
|
||||
}
|
||||
}
|
||||
} else if (onDonate !== null) {
|
||||
} else {
|
||||
event.preventDefault();
|
||||
onDonate();
|
||||
setIsOpen(true);
|
||||
}
|
||||
}}
|
||||
href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD&amount=5"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
ref={buttonRef}
|
||||
>
|
||||
<Button
|
||||
buttonHeight="30px"
|
||||
|
|
@ -99,7 +118,21 @@ const Donate = ({ onDonate = null }) => {
|
|||
title={t('donate.title')}
|
||||
>{t('donate.button')}</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<Options
|
||||
isOpen={isOpen}
|
||||
ref={modalRef}
|
||||
onBlur={e => {
|
||||
if (modalRef.current.contains(e.relatedTarget)) return;
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
<a onClick={() => setIsOpen(false)} ref={firstLinkRef} href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD&amount=2" target="_blank" rel="noreferrer">{t('donate.options.$2')}</a>
|
||||
<a onClick={() => setIsOpen(false)} href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD&amount=5" target="_blank" rel="noreferrer"><strong>{t('donate.options.$5')}</strong></a>
|
||||
<a onClick={() => setIsOpen(false)} href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD&amount=10" target="_blank" rel="noreferrer">{t('donate.options.$10')}</a>
|
||||
<a onClick={() => setIsOpen(false)} href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD" target="_blank" rel="noreferrer">{t('donate.options.choose')}</a>
|
||||
</Options>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
52
crabfit-frontend/src/components/Donate/donateStyle.ts
Normal file
52
crabfit-frontend/src/components/Donate/donateStyle.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import styled from '@emotion/styled';
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
margin-top: 6px;
|
||||
margin-left: 12px;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
export const Options = styled.div`
|
||||
position: absolute;
|
||||
bottom: calc(100% + 20px);
|
||||
right: 0;
|
||||
background-color: ${props => props.theme.background};
|
||||
${props => props.theme.mode === 'dark' && `
|
||||
border: 1px solid ${props.theme.primaryBackground};
|
||||
`}
|
||||
z-index: 60;
|
||||
padding: 4px 10px;
|
||||
border-radius: 14px;
|
||||
box-sizing: border-box;
|
||||
max-width: calc(100vw - 20px);
|
||||
box-shadow: 0 3px 6px 0 rgba(0,0,0,.3);
|
||||
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: translateY(5px);
|
||||
transition: opacity .15s, transform .15s, visibility .15s;
|
||||
|
||||
${props => props.isOpen && `
|
||||
pointer-events: all;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
visibility: visible;
|
||||
`}
|
||||
|
||||
& a {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
padding: 4px 20px;
|
||||
margin: 6px 0;
|
||||
text-decoration: none;
|
||||
border-radius: 100px;
|
||||
background-color: ${props => props.theme.primary};
|
||||
color: ${props => props.theme.background};
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
@ -1,28 +1,15 @@
|
|||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Donate } from 'components';
|
||||
import { Wrapper, Link } from './footerStyle';
|
||||
import { Wrapper } from './footerStyle';
|
||||
|
||||
const Footer = (props) => {
|
||||
const [donateMode, setDonateMode] = useState(false);
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
return (
|
||||
<Wrapper id="donate" donateMode={donateMode} {...props}>
|
||||
{donateMode ? (
|
||||
<>
|
||||
<Link href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD&amount=2" target="_blank">{t('donate.options.$2')}</Link>
|
||||
<Link href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD&amount=5" target="_blank"><strong>{t('donate.options.$5')}</strong></Link>
|
||||
<Link href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD&amount=10" target="_blank">{t('donate.options.$10')}</Link>
|
||||
<Link href="https://www.paypal.com/donate?business=N89X6YXRT5HKW&item_name=Crab+Fit+Donation¤cy_code=AUD" target="_blank">{t('donate.options.choose')}</Link>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>{t('donate.info')}</span>
|
||||
<Donate onDonate={() => setDonateMode(true)} />
|
||||
</>
|
||||
)}
|
||||
<Wrapper id="donate" {...props}>
|
||||
<span>{t('donate.info')}</span>
|
||||
<Donate />
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,20 +19,4 @@ export const Wrapper = styled.footer`
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
`}
|
||||
|
||||
${props => props.donateMode && `
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
`}
|
||||
`;
|
||||
|
||||
export const Link = styled.a`
|
||||
padding: 11px 10px;
|
||||
white-space: nowrap;
|
||||
|
||||
& strong {
|
||||
font-weight: 800;
|
||||
}
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import dayjs from 'dayjs';
|
||||
|
|
@ -27,9 +27,18 @@ const setDefaults = (lang, store) => {
|
|||
const Settings = () => {
|
||||
const theme = useTheme();
|
||||
const store = useSettingsStore();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isOpen, _setIsOpen] = useState(false);
|
||||
const { t, i18n } = useTranslation('common');
|
||||
const setLocale = useLocaleUpdateStore(state => state.setLocale);
|
||||
const firstControlRef = useRef();
|
||||
|
||||
const setIsOpen = open => {
|
||||
_setIsOpen(open);
|
||||
|
||||
if (open) {
|
||||
window.setTimeout(() => firstControlRef.current.focus(), 150);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (Object.keys(locales).includes(i18n.language)) {
|
||||
|
|
@ -57,7 +66,6 @@ const Settings = () => {
|
|||
<>
|
||||
<OpenButton
|
||||
isOpen={isOpen}
|
||||
tabIndex="1"
|
||||
type="button"
|
||||
onClick={() => setIsOpen(!isOpen)} title={t('options.name')}
|
||||
>
|
||||
|
|
@ -78,6 +86,7 @@ const Settings = () => {
|
|||
}}
|
||||
value={store.weekStart === 0 ? 'Sunday' : 'Monday'}
|
||||
onChange={value => store.setWeekStart(value === 'Sunday' ? 0 : 1)}
|
||||
inputRef={firstControlRef}
|
||||
/>
|
||||
|
||||
<ToggleField
|
||||
|
|
|
|||
|
|
@ -64,12 +64,14 @@ export const Modal = styled.div`
|
|||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity .15s, transform .15s;
|
||||
visibility: hidden;
|
||||
transition: opacity .15s, transform .15s, visibility .15s;
|
||||
|
||||
${props => props.isOpen && `
|
||||
pointer-events: all;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
visibility: visible;
|
||||
`}
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const ToggleField = ({
|
|||
options = [],
|
||||
value,
|
||||
onChange,
|
||||
inputRef,
|
||||
...props
|
||||
}) => (
|
||||
<Wrapper>
|
||||
|
|
@ -30,6 +31,7 @@ const ToggleField = ({
|
|||
id={`${name}-${label}`}
|
||||
checked={value === key}
|
||||
onChange={() => onChange(key)}
|
||||
ref={inputRef}
|
||||
/>
|
||||
<LabelButton htmlFor={`${name}-${label}`}>{label}</LabelButton>
|
||||
</Option>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export const ToggleContainer = styled.div`
|
|||
border: 1px solid ${props => props.theme.primary};
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
|
||||
&:focus-within {
|
||||
outline: Highlight auto 1px;
|
||||
outline: -webkit-focus-ring-color auto 1px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue