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
Eric Bailey 2023-12-28 16:13:51 -06:00 committed by GitHub
parent 23c9c8977b
commit 705f9b61ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 3 deletions

View File

@ -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]}

View File

@ -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}

View File

@ -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}