Handle birth dates as UTC, handle locale formatting (#2363)
* Enforce UTC for birthdate picker * Handle locales * Remove log * Add a second snap point to the date input in case text is zoomed * Guard against bad dates * Log message --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>zio/stable
parent
23c9c8977b
commit
705f9b61ef
|
@ -13,6 +13,17 @@ import {isWeb} from 'platform/detection'
|
||||||
import {Trans, msg} from '@lingui/macro'
|
import {Trans, msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
|
import {logger} from '#/logger'
|
||||||
|
|
||||||
|
function sanitizeDate(date: Date): Date {
|
||||||
|
if (!date || date.toString() === 'Invalid Date') {
|
||||||
|
logger.error(`Create account: handled invalid date for birthDate`, {
|
||||||
|
hasDate: !!date,
|
||||||
|
})
|
||||||
|
return new Date()
|
||||||
|
}
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
|
||||||
/** STEP 2: Your account
|
/** STEP 2: Your account
|
||||||
* @field Invite code or waitlist
|
* @field Invite code or waitlist
|
||||||
|
@ -38,6 +49,10 @@ export function Step2({
|
||||||
openModal({name: 'waitlist'})
|
openModal({name: 'waitlist'})
|
||||||
}, [openModal])
|
}, [openModal])
|
||||||
|
|
||||||
|
const birthDate = React.useMemo(() => {
|
||||||
|
return sanitizeDate(uiState.birthDate)
|
||||||
|
}, [uiState.birthDate])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<StepHeader step="2" title={_(msg`Your account`)} />
|
<StepHeader step="2" title={_(msg`Your account`)} />
|
||||||
|
@ -122,8 +137,9 @@ export function Step2({
|
||||||
<Trans>Your birth date</Trans>
|
<Trans>Your birth date</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
<DateInput
|
<DateInput
|
||||||
|
handleAsUTC
|
||||||
testID="birthdayInput"
|
testID="birthdayInput"
|
||||||
value={uiState.birthDate}
|
value={birthDate}
|
||||||
onChange={value => uiDispatch({type: 'set-birth-date', value})}
|
onChange={value => uiDispatch({type: 'set-birth-date', value})}
|
||||||
buttonType="default-light"
|
buttonType="default-light"
|
||||||
buttonStyle={[pal.border, styles.dateInputButton]}
|
buttonStyle={[pal.border, styles.dateInputButton]}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import {
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
|
||||||
export const snapPoints = ['50%']
|
export const snapPoints = ['50%', '90%']
|
||||||
|
|
||||||
function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
@ -63,6 +63,7 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
<DateInput
|
<DateInput
|
||||||
|
handleAsUTC
|
||||||
testID="birthdayInput"
|
testID="birthdayInput"
|
||||||
value={date}
|
value={date}
|
||||||
onChange={setDate}
|
onChange={setDate}
|
||||||
|
|
|
@ -13,6 +13,9 @@ import {Text} from '../text/Text'
|
||||||
import {TypographyVariant} from 'lib/ThemeContext'
|
import {TypographyVariant} from 'lib/ThemeContext'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
import {getLocales} from 'expo-localization'
|
||||||
|
|
||||||
|
const LOCALE = getLocales()[0]
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
testID?: string
|
testID?: string
|
||||||
|
@ -25,6 +28,7 @@ interface Props {
|
||||||
accessibilityLabel: string
|
accessibilityLabel: string
|
||||||
accessibilityHint: string
|
accessibilityHint: string
|
||||||
accessibilityLabelledBy?: string
|
accessibilityLabelledBy?: string
|
||||||
|
handleAsUTC?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DateInput(props: Props) {
|
export function DateInput(props: Props) {
|
||||||
|
@ -32,6 +36,12 @@ export function DateInput(props: Props) {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
|
||||||
|
const formatter = React.useMemo(() => {
|
||||||
|
return new Intl.DateTimeFormat(LOCALE.languageTag, {
|
||||||
|
timeZone: props.handleAsUTC ? 'UTC' : undefined,
|
||||||
|
})
|
||||||
|
}, [props.handleAsUTC])
|
||||||
|
|
||||||
const onChangeInternal = useCallback(
|
const onChangeInternal = useCallback(
|
||||||
(event: DateTimePickerEvent, date: Date | undefined) => {
|
(event: DateTimePickerEvent, date: Date | undefined) => {
|
||||||
setShow(false)
|
setShow(false)
|
||||||
|
@ -64,7 +74,7 @@ export function DateInput(props: Props) {
|
||||||
<Text
|
<Text
|
||||||
type={props.buttonLabelType}
|
type={props.buttonLabelType}
|
||||||
style={[pal.text, props.buttonLabelStyle]}>
|
style={[pal.text, props.buttonLabelStyle]}>
|
||||||
{props.value.toLocaleDateString()}
|
{formatter.format(props.value)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -73,6 +83,7 @@ export function DateInput(props: Props) {
|
||||||
<DateTimePicker
|
<DateTimePicker
|
||||||
testID={props.testID ? `${props.testID}-datepicker` : undefined}
|
testID={props.testID ? `${props.testID}-datepicker` : undefined}
|
||||||
mode="date"
|
mode="date"
|
||||||
|
timeZoneName={props.handleAsUTC ? 'Etc/UTC' : undefined}
|
||||||
display="spinner"
|
display="spinner"
|
||||||
// @ts-ignore applies in iOS only -prf
|
// @ts-ignore applies in iOS only -prf
|
||||||
themeVariant={theme.colorScheme}
|
themeVariant={theme.colorScheme}
|
||||||
|
|
Loading…
Reference in New Issue