@verifiedinc-public/shared-ui-elements 0.14.4 → 0.14.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verifiedinc-public/shared-ui-elements",
3
- "version": "0.14.4",
3
+ "version": "0.14.5-beta.1",
4
4
  "description": "A set of UI components, utilities that is shareable with the core apps.",
5
5
  "private": false,
6
6
  "keywords": [],
@@ -0,0 +1,42 @@
1
+ import {
2
+ AlertTitle,
3
+ Box,
4
+ type SxProps,
5
+ useTheme,
6
+ type AlertColor,
7
+ } from '@mui/material';
8
+
9
+ import { type ReactNode } from 'react';
10
+ import { FullWidthAlert } from '../Alert/FullWidthAlert';
11
+ import { Typography } from '../Typography';
12
+
13
+ interface BannerProps {
14
+ title: string;
15
+ severity: AlertColor;
16
+ children: ReactNode;
17
+ sx?: SxProps;
18
+ }
19
+
20
+ export function Banner({
21
+ title,
22
+ severity,
23
+ children,
24
+ sx,
25
+ }: BannerProps): React.JSX.Element {
26
+ const theme = useTheme();
27
+ return (
28
+ <Box sx={{ mt: 3, ...sx }}>
29
+ <FullWidthAlert severity={severity} sx={{ alignItems: 'start' }}>
30
+ <AlertTitle>
31
+ <Typography
32
+ sx={{ color: theme.palette.info.contrastText }}
33
+ fontWeight='bold'
34
+ >
35
+ {title}
36
+ </Typography>
37
+ </AlertTitle>
38
+ {children}
39
+ </FullWidthAlert>
40
+ </Box>
41
+ );
42
+ }
@@ -0,0 +1,18 @@
1
+ import { type SxProps } from '@mui/material';
2
+ import { Banner } from './Banner';
3
+
4
+ /**
5
+ * "Enter your exact Birthday" Banner
6
+ */
7
+ export function ExactBirthdayBanner({
8
+ sx,
9
+ }: {
10
+ sx?: SxProps;
11
+ }): React.JSX.Element {
12
+ return (
13
+ <Banner title='Enter your exact Birthday' severity='info' sx={sx}>
14
+ We need this to verify your identity with your phone carrier and pre-fill
15
+ your signup info.
16
+ </Banner>
17
+ );
18
+ }
@@ -0,0 +1,55 @@
1
+ import { type SxProps, useTheme } from '@mui/material';
2
+ import { FullWidthAlert } from '../Alert/FullWidthAlert';
3
+ import { Button } from '../Button';
4
+ import { parseToPhoneNational } from '../../utils';
5
+
6
+ interface ResendPhoneBannerProps {
7
+ phone: string;
8
+ onClick: () => void;
9
+ disabled?: boolean;
10
+ sx?: SxProps;
11
+ }
12
+
13
+ /**
14
+ * Banner to verify and resend the phone verification code.
15
+ * @param phone
16
+ * @param onClick
17
+ * @constructor
18
+ */
19
+ export function ResendPhoneBanner({
20
+ phone,
21
+ onClick,
22
+ disabled = false,
23
+ sx,
24
+ }: ResendPhoneBannerProps): React.JSX.Element {
25
+ const theme = useTheme();
26
+ return (
27
+ <>
28
+ <FullWidthAlert
29
+ action={
30
+ <Button
31
+ onClick={onClick}
32
+ disabled={disabled}
33
+ sx={{
34
+ color: theme.palette.info.contrastText,
35
+ fontWeight: 800,
36
+ fontSize: '13px',
37
+ padding: '0',
38
+ '&:hover': {
39
+ backgroundColor: 'initial',
40
+ },
41
+ ...sx,
42
+ }}
43
+ size='small'
44
+ variant='text'
45
+ color='info'
46
+ >
47
+ Resend
48
+ </Button>
49
+ }
50
+ >
51
+ Use the text we sent to <strong>{parseToPhoneNational(phone)}</strong>{' '}
52
+ </FullWidthAlert>
53
+ </>
54
+ );
55
+ }
@@ -0,0 +1,25 @@
1
+ import { Box, type SxProps } from '@mui/material';
2
+ import { Banner } from './Banner';
3
+
4
+ /**
5
+ * Banner to inform about the test phone numbers
6
+ */
7
+ export function TestPhoneNumbersBanner({
8
+ sx,
9
+ }: {
10
+ sx?: SxProps;
11
+ }): React.JSX.Element {
12
+ return (
13
+ <Banner title='Test Phone Numbers' severity='info' sx={sx}>
14
+ <Box
15
+ component='ul'
16
+ sx={{
17
+ listStyle: 'inside',
18
+ }}
19
+ >
20
+ <li>Phone Only Input: +10123456789</li>
21
+ <li>Phone and Birth Date Inputs: +10019999999</li>
22
+ </Box>
23
+ </Banner>
24
+ );
25
+ }
@@ -0,0 +1,4 @@
1
+ export * from './Banner';
2
+ export * from './ResendPhoneBanner';
3
+ export * from './ExactBirthdayBanner';
4
+ export * from './TestPhoneNumbersBanner';
@@ -71,6 +71,7 @@ export function useSnackbar(): {
71
71
  _enqueueSnackbar(message, {
72
72
  severity,
73
73
  variant: 'customAlertComponent',
74
+ persist: true,
74
75
  ...options,
75
76
  });
76
77
  };
@@ -1,64 +1,46 @@
1
- import { Box, TextField } from '@mui/material';
2
- import {
3
- forwardRef,
4
- useEffect,
5
- useState,
6
- type ChangeEventHandler,
7
- } from 'react';
8
- import {
9
- formatDateMMDDYYYY,
10
- getMaxDateInstance,
11
- getMinDateInstance,
12
- } from '../../utils/date';
1
+ import { Box, TextField, type TextFieldProps } from '@mui/material';
2
+ import { forwardRef, useState, type ChangeEventHandler } from 'react';
13
3
  import { masks } from '../../utils/masks';
14
- import { USDateSchema } from '../../validations';
15
- import { type TextFieldProps } from '../TextField';
16
4
  import { InputMask } from './InputMask';
17
5
  import { inputStyle } from './styles/input';
18
6
 
19
- interface DateInputProps {
20
- name?: string;
21
- value?: string;
7
+ interface DateInputProps extends Omit<TextFieldProps, 'onBlur' | 'onChange'> {
22
8
  label?: string;
23
- error?: boolean;
9
+ value?: string;
24
10
  helperText?: string;
25
- onChange?: (event: { target: { value: string } }) => void;
11
+ onChange?: (value: string) => void;
26
12
  onBlur?: ChangeEventHandler<HTMLInputElement>;
27
- disabled?: boolean;
28
- allowFutureDates?: boolean;
29
13
  }
30
14
 
31
- /**
32
- * The input with date format.
33
- * @constructor
34
- */
35
15
  function DateInputComponent(
36
16
  {
37
- label = 'Date of Birth',
38
- value = '',
17
+ label = 'Date',
18
+ value: controlledValue,
39
19
  error,
40
20
  helperText,
41
21
  onChange,
42
22
  onBlur,
43
23
  disabled,
44
- allowFutureDates = true,
45
24
  ...rest
46
25
  }: Readonly<DateInputProps>,
47
26
  ref: any,
48
27
  ): React.JSX.Element {
49
- // Arbitrary value to format the timestamp into human-readable date.
50
- const [localValue, setLocalValue] = useState<string>(
51
- value ? formatDateMMDDYYYY(value) : '',
52
- );
28
+ const [internalValue, setInternalValue] = useState<string>('');
53
29
 
54
- useEffect(() => {
55
- if (value === '') {
56
- setLocalValue('');
30
+ // Determine the value to display
31
+ const isControlled = controlledValue !== undefined;
32
+ const value = isControlled ? controlledValue : internalValue;
33
+
34
+ const handleChange = (e: any): void => {
35
+ const date = e.target.value;
36
+ if (!isControlled) {
37
+ setInternalValue(date); // Update internal state only if uncontrolled
57
38
  }
58
- }, [value]);
59
39
 
60
- const minDateInstance = getMinDateInstance();
61
- const maxDateInstance = getMaxDateInstance(allowFutureDates);
40
+ if (onChange) {
41
+ onChange(date);
42
+ }
43
+ };
62
44
 
63
45
  const textFieldStyle: TextFieldProps = {
64
46
  ...inputStyle,
@@ -74,6 +56,7 @@ function DateInputComponent(
74
56
  mask: masks.DOB_MASK,
75
57
  },
76
58
  fullWidth: true,
59
+ ...rest,
77
60
  };
78
61
 
79
62
  return (
@@ -82,33 +65,11 @@ function DateInputComponent(
82
65
  mask={masks.DOB_MASK}
83
66
  maskPlaceholder={null}
84
67
  disabled={disabled}
85
- value={localValue}
68
+ value={value}
86
69
  onBlur={onBlur}
87
- onChange={(e) => {
88
- const value = e.target.value;
89
- const valid = USDateSchema.safeParse(value);
90
-
91
- // Update the facade input value, so it let user input wrong/right values.
92
- setLocalValue(value);
93
-
94
- if (!valid.success) {
95
- // A way to make sure the data field state is invalid is to empty the value.
96
- return onChange?.({ target: { value: '' } });
97
- }
98
-
99
- const date = new Date(value);
100
- if (date < minDateInstance || date > maxDateInstance) {
101
- // A way to make sure the data field state is invalid is to empty the value.
102
- return onChange?.({ target: { value: '' } });
103
- }
104
-
105
- date.setUTCHours(12);
106
-
107
- // The date is valid in the US date format and is in between the valid min-max date range.
108
- onChange?.({ target: { value: String(+date) } });
109
- }}
70
+ onChange={handleChange}
110
71
  >
111
- <TextField {...textFieldStyle} inputRef={ref} {...rest} />
72
+ <TextField {...textFieldStyle} inputRef={ref} />
112
73
  </InputMask>
113
74
  </Box>
114
75
  );
@@ -1,5 +1,4 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
-
3
2
  import { fn } from '@storybook/test';
4
3
  import { DateInput } from '../../../components/form/DateInput';
5
4
 
@@ -13,6 +12,10 @@ const meta = {
13
12
  },
14
13
  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
15
14
  tags: ['autodocs'],
15
+ argTypes: {
16
+ size: { control: 'select', options: ['small', 'medium'] },
17
+ value: { control: 'date' },
18
+ },
16
19
  } satisfies Meta<typeof DateInput>;
17
20
 
18
21
  export default meta;
@@ -26,14 +29,8 @@ export const Default: Story = {
26
29
  onChange: fn(),
27
30
  disabled: false,
28
31
  error: false,
32
+ size: 'small',
29
33
  helperText: 'Helper text',
30
- allowFutureDates: true,
31
- },
32
- argTypes: {
33
- allowFutureDates: {
34
- control: 'boolean',
35
- description:
36
- 'Allow future dates. If false and the limit is reached, onChange will return an empty string.',
37
- },
38
34
  },
35
+ argTypes: {},
39
36
  };