diff --git a/Storybook/components/DateSelector/DateSelector.stories.tsx b/Storybook/components/DateSelector/DateSelector.stories.tsx index 2cbb8a10..689023bc 100644 --- a/Storybook/components/DateSelector/DateSelector.stories.tsx +++ b/Storybook/components/DateSelector/DateSelector.stories.tsx @@ -1,25 +1,27 @@ import React from 'react'; -import { DateSelector } from '../../../src/components/dateSelector/DateSelector'; +import { DateSelector } from '../../../src'; import type { ComponentMeta, ComponentStory } from '@storybook/react-native'; -import { StyleSheet, View } from 'react-native'; import { action } from '@storybook/addon-actions'; +import { View } from 'react-native'; export default { title: 'components/DateSelector', component: DateSelector, argTypes: { prefilled: { control: { type: 'date' } }, + errorMessage: { control: { type: 'text' } }, }, args: { prefilled: new Date(2023, 0, 8), + onUpdatedDate: (date: Date) => { + action('onChange')(date.toDateString()); + }, + errorMessage: undefined, }, decorators: [ (Story) => { - const styles = StyleSheet.create({ - container: { paddingTop: 16 }, - }); return ( - + ); @@ -28,20 +30,5 @@ export default { } as ComponentMeta; export const Base: ComponentStory = (args) => { - const handleChange = (date: Date) => { - action('onChange')(date.toDateString()); - }; - return ; -}; -export const WithErrorMessage: ComponentStory = (args) => { - const handleChange = (date: Date) => { - action('onChange')(date.toDateString()); - }; - return ( - - ); + return ; }; diff --git a/src/__tests__/components/DateSelector.test.tsx b/src/__tests__/components/DateSelector.test.tsx index c8d7dad1..992b5729 100644 --- a/src/__tests__/components/DateSelector.test.tsx +++ b/src/__tests__/components/DateSelector.test.tsx @@ -11,7 +11,7 @@ beforeEach(() => { tree = render( , ); @@ -73,7 +73,7 @@ describe('MODULE | DateField', () => { tree.rerender( , diff --git a/src/components/dateSelector/DateField.tsx b/src/components/dateSelector/DateField.tsx index 4fa51179..d3157c6b 100644 --- a/src/components/dateSelector/DateField.tsx +++ b/src/components/dateSelector/DateField.tsx @@ -8,90 +8,15 @@ import { import { TextInput } from 'react-native'; import { Theme, useTheme } from '../../styles/themes'; -type State = - | 'readonly' - | 'filled' - | 'empty' - | 'filled-focused' - | 'empty-focused' - | 'error'; - export interface DateFieldProps extends TextInputProps { hasError?: boolean; } -function getColorsStyle(theme: Theme, state: State) { - let backgroundColor, borderColor, textColor; - - switch (state) { - case 'filled-focused': - textColor = theme.sw.colors.neutral[800]; - backgroundColor = theme.sw.colors.neutral[50]; - borderColor = theme.sw.colors.primary.main; - break; - case 'empty-focused': - textColor = theme.sw.colors.primary.main; - borderColor = theme.sw.colors.primary.main; - backgroundColor = - theme.sw.colors.primary.main + theme.sw.transparency[16]; - break; - case 'filled': - textColor = theme.sw.colors.neutral[800]; - backgroundColor = - theme.sw.colors.neutral[500] + theme.sw.transparency[8]; - break; - case 'error': - textColor = theme.sw.colors.error.main; - backgroundColor = - theme.sw.colors.error.main + theme.sw.transparency[8]; - break; - default: - textColor = theme.sw.colors.neutral[500]; - backgroundColor = - theme.sw.colors.neutral[500] + theme.sw.transparency[8]; - break; - } - return { backgroundColor, borderColor, textColor }; -} - -function getStyle(theme: Theme, state: State) { - const { backgroundColor, borderColor, textColor } = getColorsStyle( - theme, - state, - ); - - const style = StyleSheet.create({ - main: { - borderRadius: 18, - height: 48, - borderWidth: borderColor !== undefined ? 1 : 0, - borderColor: borderColor, - width: 72, - color: textColor, - fontFamily: 'PublicSans-Bold', - fontSize: 20, - lineHeight: 23.5, - backgroundColor: backgroundColor, - paddingVertical: 0, - marginVertical: 0, - }, - placeholder: { - color: - state === 'empty-focused' - ? theme.sw.colors.primary.main - : theme.sw.colors.neutral[500], - }, - }); - return style; -} - export const DateField = forwardRef( ({ value = '', hasError, ...props }, ref) => { - const theme = useTheme(); const [isFocused, setIsFocused] = useState(false); - const state = getState(hasError, isFocused, value); - const style = getStyle(theme, state); + const { style, theme } = useDateFieldStyle(hasError, isFocused, value); const onFocus = (e: NativeSyntheticEvent) => { setIsFocused(true); @@ -138,28 +63,120 @@ export const DateField = forwardRef( DateField.displayName = 'DateFieldRef'; -function getState( +function useDateFieldStyle( hasError: boolean | undefined, isFocused: boolean, value: string, -): State { - if (hasError) { - return 'error'; +) { + type State = + | 'readonly' + | 'filled' + | 'empty' + | 'filled-focused' + | 'empty-focused' + | 'error'; + + const theme = useTheme(); + + function getState( + hasError: boolean | undefined, + isFocused: boolean, + value: string, + ): State { + if (hasError) { + return 'error'; + } + + if (!isFocused && value === '') { + return 'empty'; + } + + if (isFocused && value === '') { + return 'empty-focused'; + } + + if (!isFocused) { + return 'filled'; + } + + return 'filled-focused'; } - if (!isFocused && value === '') { - return 'empty'; + function getPlaceholderColorsStyle(theme: Theme, state: State) { + return { + textColor: + state === 'empty-focused' + ? theme.sw.colors.primary.main + : theme.sw.colors.neutral[500], + }; } - if (isFocused && value === '') { - return 'empty-focused'; + function getTextInputStyle(theme: Theme, state: State) { + let backgroundColor, borderColor, textColor; + + switch (state) { + case 'filled-focused': + textColor = theme.sw.colors.neutral[800]; + backgroundColor = theme.sw.colors.neutral[50]; + borderColor = theme.sw.colors.primary.main; + break; + case 'empty-focused': + textColor = theme.sw.colors.primary.main; + borderColor = theme.sw.colors.primary.main; + backgroundColor = + theme.sw.colors.primary.main + theme.sw.transparency[16]; + break; + case 'filled': + textColor = theme.sw.colors.neutral[800]; + backgroundColor = + theme.sw.colors.neutral[500] + theme.sw.transparency[8]; + break; + case 'error': + textColor = theme.sw.colors.error.main; + backgroundColor = + theme.sw.colors.error.main + theme.sw.transparency[8]; + break; + default: + textColor = theme.sw.colors.neutral[500]; + backgroundColor = + theme.sw.colors.neutral[500] + theme.sw.transparency[8]; + break; + } + return { backgroundColor, borderColor, textColor }; } - if (!isFocused) { - return 'filled'; + function getStyle(theme: Theme, state: State) { + const { backgroundColor, borderColor, textColor } = getTextInputStyle( + theme, + state, + ); + + const placeholderColorsStyle = getPlaceholderColorsStyle(theme, state); + + return StyleSheet.create({ + main: { + borderRadius: 18, + height: 48, + borderWidth: borderColor !== undefined ? 1 : 0, + borderColor: borderColor, + width: 72, + color: textColor, + fontFamily: 'PublicSans-Bold', + fontSize: 20, + lineHeight: 23.5, + backgroundColor: backgroundColor, + paddingVertical: 0, + marginVertical: 0, + }, + placeholder: { + color: placeholderColorsStyle.textColor, + }, + }); } - return 'filled-focused'; + const state = getState(hasError, isFocused, value); + + return { style: getStyle(theme, state), theme }; } function removeNonNumeric(str: string): string { diff --git a/src/components/dateSelector/DateSelector.tsx b/src/components/dateSelector/DateSelector.tsx index 0bd42d0f..5f97125a 100644 --- a/src/components/dateSelector/DateSelector.tsx +++ b/src/components/dateSelector/DateSelector.tsx @@ -13,7 +13,7 @@ import { type DateSelectorProps = WithTestID<{ prefilled: Date; errorMessage?: string; - onChange: (date: Date) => void; + onUpdatedDate: (date: Date) => void; }>; interface FieldsValues { @@ -27,7 +27,7 @@ const MAX_DATE_FIELD_LENGTH = 2; export const DateSelector = ({ prefilled, errorMessage, - onChange, + onUpdatedDate, testID, }: DateSelectorProps) => { const theme = useTheme(); @@ -55,8 +55,8 @@ export const DateSelector = ({ setMonthField(completeFields.monthField); setYearField(completeFields.yearField); - onChange(fromFieldsToDate(completeFields)); - }, [prefilledFields, dayField, monthField, yearField, onChange]); + onUpdatedDate(fromFieldsToDate(completeFields)); + }, [prefilledFields, dayField, monthField, yearField, onUpdatedDate]); useListenerOnKeyboardHiding(leaveDateSelector); @@ -102,6 +102,7 @@ export const DateSelector = ({ testID={testID + '/day'} placeholder={prefilledFields.dayField} value={dayField} + hasError={!!errorMessage} onBlur={handleBlurPrefixWith0(setDayField)} onChangeText={handleDayChange} /> @@ -115,6 +116,7 @@ export const DateSelector = ({ testID={testID + '/month'} placeholder={prefilledFields.monthField} value={monthField} + hasError={!!errorMessage} onBlur={handleBlurPrefixWith0(setMonthField)} onChangeText={handleMonthChange} /> @@ -128,6 +130,7 @@ export const DateSelector = ({ testID={testID + '/year'} placeholder={prefilledFields.yearField} value={yearField} + hasError={!!errorMessage} onBlur={handleBlurPrefixWith0(setYearField)} onChangeText={handleYearChange} />