about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/dialogs/BirthDateSettings.tsx16
-rw-r--r--src/components/forms/DateField/index.android.tsx4
-rw-r--r--src/components/forms/DateField/index.shared.tsx2
-rw-r--r--src/components/forms/DateField/index.tsx24
-rw-r--r--src/components/forms/DateField/index.web.tsx7
-rw-r--r--src/components/forms/DateField/types.ts3
-rw-r--r--src/screens/Signup/StepInfo/index.tsx3
-rw-r--r--src/view/com/util/forms/DateInput.tsx105
-rw-r--r--src/view/com/util/forms/DateInput.web.tsx76
9 files changed, 37 insertions, 203 deletions
diff --git a/src/components/dialogs/BirthDateSettings.tsx b/src/components/dialogs/BirthDateSettings.tsx
index 8f47d05b0..9fbf378ac 100644
--- a/src/components/dialogs/BirthDateSettings.tsx
+++ b/src/components/dialogs/BirthDateSettings.tsx
@@ -12,12 +12,12 @@ import {
   usePreferencesSetBirthDateMutation,
 } from '#/state/queries/preferences'
 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
-import {DateInput} from '#/view/com/util/forms/DateInput'
 import {atoms as a, useTheme} from '#/alf'
 import * as Dialog from '#/components/Dialog'
+import {DateField} from '#/components/forms/DateField'
 import {Loader} from '#/components/Loader'
+import {Text} from '#/components/Typography'
 import {Button, ButtonIcon, ButtonText} from '../Button'
-import {Text} from '../Typography'
 
 export function BirthDateSettingsDialog({
   control,
@@ -95,17 +95,13 @@ function BirthdayInner({
   return (
     <View style={a.gap_lg} testID="birthDateSettingsDialog">
       <View style={isIOS && [a.w_full, a.align_center]}>
-        <DateInput
-          handleAsUTC
+        <DateField
           testID="birthdayInput"
           value={date}
-          onChange={setDate}
-          buttonType="default-light"
-          buttonStyle={[a.rounded_sm]}
-          buttonLabelType="lg"
-          accessibilityLabel={_(msg`Birthday`)}
+          onChangeDate={newDate => setDate(new Date(newDate))}
+          label={_(msg`Birthday`)}
           accessibilityHint={_(msg`Enter your birth date`)}
-          accessibilityLabelledBy="birthDate"
+          maximumDate={new Date()}
         />
       </View>
 
diff --git a/src/components/forms/DateField/index.android.tsx b/src/components/forms/DateField/index.android.tsx
index 58f4d4f89..a6b6993dc 100644
--- a/src/components/forms/DateField/index.android.tsx
+++ b/src/components/forms/DateField/index.android.tsx
@@ -17,6 +17,7 @@ export function DateField({
   isInvalid,
   testID,
   accessibilityHint,
+  maximumDate,
 }: DateFieldProps) {
   const t = useTheme()
   const [open, setOpen] = React.useState(false)
@@ -67,6 +68,9 @@ export function DateField({
           aria-label={label}
           accessibilityLabel={label}
           accessibilityHint={accessibilityHint}
+          maximumDate={
+            maximumDate ? new Date(toSimpleDateString(maximumDate)) : undefined
+          }
         />
       )}
     </>
diff --git a/src/components/forms/DateField/index.shared.tsx b/src/components/forms/DateField/index.shared.tsx
index 7438f5622..7b03ba901 100644
--- a/src/components/forms/DateField/index.shared.tsx
+++ b/src/components/forms/DateField/index.shared.tsx
@@ -19,7 +19,7 @@ export function DateFieldButton({
   accessibilityHint,
 }: {
   label: string
-  value: string
+  value: string | Date
   onPress: () => void
   isInvalid?: boolean
   accessibilityHint?: string
diff --git a/src/components/forms/DateField/index.tsx b/src/components/forms/DateField/index.tsx
index 1c78d2abb..eca4d5cbd 100644
--- a/src/components/forms/DateField/index.tsx
+++ b/src/components/forms/DateField/index.tsx
@@ -16,10 +16,11 @@ export * as utils from '#/components/forms/DateField/utils'
 export const LabelText = TextField.LabelText
 
 /**
- * Date-only input. Accepts a date in the format YYYY-MM-DD, and reports date
- * changes in the same format.
+ * Date-only input. Accepts a string in the format YYYY-MM-DD, or a Date object.
+ * Date objects are converted to strings in the format YYYY-MM-DD.
+ * Returns a string in the format YYYY-MM-DD.
  *
- * For dates of unknown format, convert with the
+ * To generate a string in the format YYYY-MM-DD from a Date object, use the
  * `utils.toSimpleDateString(Date)` export of this file.
  */
 export function DateField({
@@ -29,6 +30,7 @@ export function DateField({
   label,
   isInvalid,
   accessibilityHint,
+  maximumDate,
 }: DateFieldProps) {
   const {_} = useLingui()
   const t = useTheme()
@@ -56,21 +58,29 @@ export function DateField({
         isInvalid={isInvalid}
         accessibilityHint={accessibilityHint}
       />
-      <Dialog.Outer control={control} testID={testID}>
+      <Dialog.Outer
+        control={control}
+        testID={testID}
+        nativeOptions={{preventExpansion: true}}>
         <Dialog.Handle />
-        <Dialog.Inner label={label}>
+        <Dialog.ScrollableInner label={label}>
           <View style={a.gap_lg}>
             <View style={[a.relative, a.w_full, a.align_center]}>
               <DatePicker
                 timeZoneOffsetInMinutes={0}
                 theme={t.name === 'light' ? 'light' : 'dark'}
-                date={new Date(value)}
+                date={new Date(toSimpleDateString(value))}
                 onDateChange={onChangeInternal}
                 mode="date"
                 testID={`${testID}-datepicker`}
                 aria-label={label}
                 accessibilityLabel={label}
                 accessibilityHint={accessibilityHint}
+                maximumDate={
+                  maximumDate
+                    ? new Date(toSimpleDateString(maximumDate))
+                    : undefined
+                }
               />
             </View>
             <Button
@@ -84,7 +94,7 @@ export function DateField({
               </ButtonText>
             </Button>
           </View>
-        </Dialog.Inner>
+        </Dialog.ScrollableInner>
       </Dialog.Outer>
     </>
   )
diff --git a/src/components/forms/DateField/index.web.tsx b/src/components/forms/DateField/index.web.tsx
index b764620e3..057ea1673 100644
--- a/src/components/forms/DateField/index.web.tsx
+++ b/src/components/forms/DateField/index.web.tsx
@@ -1,6 +1,6 @@
 import React from 'react'
 import {StyleSheet, TextInput, TextInputProps} from 'react-native'
-// @ts-ignore
+// @ts-expect-error untyped
 import {unstable_createElement} from 'react-native-web'
 
 import {DateFieldProps} from '#/components/forms/DateField/types'
@@ -39,6 +39,7 @@ export function DateField({
   isInvalid,
   testID,
   accessibilityHint,
+  maximumDate,
 }: DateFieldProps) {
   const handleOnChange = React.useCallback(
     (e: any) => {
@@ -56,12 +57,14 @@ export function DateField({
     <TextField.Root isInvalid={isInvalid}>
       <TextField.Icon icon={CalendarDays} />
       <Input
-        value={value}
+        value={toSimpleDateString(value)}
         label={label}
         onChange={handleOnChange}
         onChangeText={() => {}}
         testID={testID}
         accessibilityHint={accessibilityHint}
+        // @ts-expect-error not typed as <input type="date"> even though it is one
+        max={maximumDate ? toSimpleDateString(maximumDate) : undefined}
       />
     </TextField.Root>
   )
diff --git a/src/components/forms/DateField/types.ts b/src/components/forms/DateField/types.ts
index 5400cf903..1784b884f 100644
--- a/src/components/forms/DateField/types.ts
+++ b/src/components/forms/DateField/types.ts
@@ -1,8 +1,9 @@
 export type DateFieldProps = {
-  value: string
+  value: string | Date
   onChangeDate: (date: string) => void
   label: string
   isInvalid?: boolean
   testID?: string
   accessibilityHint?: string
+  maximumDate?: string | Date
 }
diff --git a/src/screens/Signup/StepInfo/index.tsx b/src/screens/Signup/StepInfo/index.tsx
index fa0c7c8cf..4ad899864 100644
--- a/src/screens/Signup/StepInfo/index.tsx
+++ b/src/screens/Signup/StepInfo/index.tsx
@@ -206,7 +206,7 @@ export function StepInfo({
               </DateField.LabelText>
               <DateField.DateField
                 testID="date"
-                value={DateField.utils.toSimpleDateString(state.dateOfBirth)}
+                value={state.dateOfBirth}
                 onChangeDate={date => {
                   dispatch({
                     type: 'setDateOfBirth',
@@ -215,6 +215,7 @@ export function StepInfo({
                 }}
                 label={_(msg`Date of birth`)}
                 accessibilityHint={_(msg`Select your date of birth`)}
+                maximumDate={new Date()}
               />
             </View>
             <Policies
diff --git a/src/view/com/util/forms/DateInput.tsx b/src/view/com/util/forms/DateInput.tsx
deleted file mode 100644
index 594bb48f6..000000000
--- a/src/view/com/util/forms/DateInput.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import {useCallback, useState} from 'react'
-import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
-import DatePicker from 'react-native-date-picker'
-import {
-  FontAwesomeIcon,
-  FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import {useLingui} from '@lingui/react'
-
-import {usePalette} from '#/lib/hooks/usePalette'
-import {TypographyVariant} from '#/lib/ThemeContext'
-import {useTheme} from '#/lib/ThemeContext'
-import {isAndroid, isIOS} from '#/platform/detection'
-import {Text} from '../text/Text'
-import {Button, ButtonType} from './Button'
-
-interface Props {
-  testID?: string
-  value: Date
-  onChange: (date: Date) => void
-  buttonType?: ButtonType
-  buttonStyle?: StyleProp<ViewStyle>
-  buttonLabelType?: TypographyVariant
-  buttonLabelStyle?: StyleProp<TextStyle>
-  accessibilityLabel: string
-  accessibilityHint: string
-  accessibilityLabelledBy?: string
-  handleAsUTC?: boolean
-}
-
-export function DateInput(props: Props) {
-  const {i18n} = useLingui()
-  const [show, setShow] = useState(false)
-  const theme = useTheme()
-  const pal = usePalette('default')
-
-  const onChangeInternal = useCallback(
-    (date: Date) => {
-      setShow(false)
-      props.onChange(date)
-    },
-    [setShow, props],
-  )
-
-  const onPress = useCallback(() => {
-    setShow(true)
-  }, [setShow])
-
-  const onCancel = useCallback(() => {
-    setShow(false)
-  }, [])
-
-  return (
-    <View>
-      {isAndroid && (
-        <Button
-          type={props.buttonType}
-          style={props.buttonStyle}
-          onPress={onPress}
-          accessibilityLabel={props.accessibilityLabel}
-          accessibilityHint={props.accessibilityHint}
-          accessibilityLabelledBy={props.accessibilityLabelledBy}>
-          <View style={styles.button}>
-            <FontAwesomeIcon
-              icon={['far', 'calendar']}
-              style={pal.textLight as FontAwesomeIconStyle}
-            />
-            <Text
-              type={props.buttonLabelType}
-              style={[pal.text, props.buttonLabelStyle]}>
-              {i18n.date(props.value, {
-                timeZone: props.handleAsUTC ? 'UTC' : undefined,
-              })}
-            </Text>
-          </View>
-        </Button>
-      )}
-      {(isIOS || show) && (
-        <DatePicker
-          timeZoneOffsetInMinutes={0}
-          modal={isAndroid}
-          open={isAndroid}
-          theme={theme.colorScheme}
-          date={props.value}
-          onDateChange={onChangeInternal}
-          onConfirm={onChangeInternal}
-          onCancel={onCancel}
-          mode="date"
-          testID={props.testID ? `${props.testID}-datepicker` : undefined}
-          accessibilityLabel={props.accessibilityLabel}
-          accessibilityHint={props.accessibilityHint}
-          accessibilityLabelledBy={props.accessibilityLabelledBy}
-        />
-      )}
-    </View>
-  )
-}
-
-const styles = StyleSheet.create({
-  button: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    gap: 10,
-  },
-})
diff --git a/src/view/com/util/forms/DateInput.web.tsx b/src/view/com/util/forms/DateInput.web.tsx
deleted file mode 100644
index 988d8aee6..000000000
--- a/src/view/com/util/forms/DateInput.web.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import {useCallback, useState} from 'react'
-import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
-// @ts-ignore types not available -prf
-import {unstable_createElement} from 'react-native-web'
-
-import {usePalette} from '#/lib/hooks/usePalette'
-
-interface Props {
-  testID?: string
-  value: Date
-  onChange: (date: Date) => void
-  buttonType?: string
-  buttonStyle?: StyleProp<ViewStyle>
-  buttonLabelType?: string
-  buttonLabelStyle?: StyleProp<TextStyle>
-  accessibilityLabel: string
-  accessibilityHint: string
-  accessibilityLabelledBy?: string
-}
-
-export function DateInput(props: Props) {
-  const pal = usePalette('default')
-  const [value, setValue] = useState(toDateInputValue(props.value))
-
-  const onChangeInternal = useCallback(
-    (v: Date) => {
-      if (!v) {
-        return
-      }
-      setValue(toDateInputValue(v))
-      props.onChange(v)
-    },
-    [setValue, props],
-  )
-
-  return (
-    <View style={[pal.borderDark, styles.container]}>
-      {unstable_createElement('input', {
-        type: 'date',
-        testID: props.testID,
-        value,
-        onChange: (e: any) => onChangeInternal(e.currentTarget.valueAsDate),
-        style: [pal.text, pal.view, pal.border, styles.textInput],
-        placeholderTextColor: pal.colors.textLight,
-        accessibilityLabel: props.accessibilityLabel,
-        accessibilityHint: props.accessibilityHint,
-        accessibilityLabelledBy: props.accessibilityLabelledBy,
-      })}
-    </View>
-  )
-}
-
-// we need the date in the form yyyy-MM-dd to pass to the input
-function toDateInputValue(d: Date): string {
-  return d.toISOString().split('T')[0]
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flexDirection: 'row',
-    paddingHorizontal: 4,
-    borderWidth: 1,
-    borderRadius: 10,
-  },
-  textInput: {
-    flex: 1,
-    width: '100%',
-    paddingVertical: 10,
-    paddingHorizontal: 10,
-    fontSize: 17,
-    letterSpacing: 0.25,
-    fontWeight: '400',
-    borderRadius: 10,
-    borderWidth: 0,
-  },
-})