diff --git a/package.json b/package.json index 5331031d..fedc3bf6 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "@motify/skeleton": "^0.18.0", "@react-native-async-storage/async-storage": "1.23.1", "@react-native-community/netinfo": "11.4.1", + "@react-native-community/slider": "^4.5.5", "@react-native-google-signin/google-signin": "^13.1.0", "@react-navigation/bottom-tabs": "^7.2.0", "@react-navigation/native": "^7.0.14", diff --git a/src/components/molecules/Field/Field.tsx b/src/components/molecules/Field/Field.tsx index 580ef547..e43dcd7f 100644 --- a/src/components/molecules/Field/Field.tsx +++ b/src/components/molecules/Field/Field.tsx @@ -5,6 +5,7 @@ import { FieldCheckboxGroup } from './FieldCheckboxGroup' import { FieldInput } from './FieldInput' import { FieldRadioGroup } from './FieldRadioGroup' import { FieldSelect } from './FieldSelect' +import { FieldSlider } from './FieldSlider' type FieldComposition = React.FC & { Input: typeof FieldInput @@ -12,6 +13,7 @@ type FieldComposition = React.FC & { Checkbox: typeof FieldCheckbox RadioGroup: typeof FieldRadioGroup Select: typeof FieldSelect + Slider: typeof FieldSlider } const Field: FieldComposition = ({ children }) => { @@ -23,6 +25,7 @@ Field.CheckboxGroup = FieldCheckboxGroup Field.Checkbox = FieldCheckbox Field.RadioGroup = FieldRadioGroup Field.Select = FieldSelect +Field.Slider = FieldSlider export { Field } export * from './types' diff --git a/src/components/molecules/Field/FieldSlider.tsx b/src/components/molecules/Field/FieldSlider.tsx new file mode 100644 index 00000000..5cf83678 --- /dev/null +++ b/src/components/molecules/Field/FieldSlider.tsx @@ -0,0 +1,38 @@ +import { useMemo } from 'react' + +import type { FieldSliderProps } from './types' + +import { FormErrorMessage, FormLabel, Box, Slider } from '@/design-system/components' +import { getLayoutProps } from '@/design-system/utils/getLayoutProps' + +export const FieldSlider = ({ + errorMessage, + isInvalid, + isRequired, + label, + labelStyle, + testID, + onChangeValue, + value, + ...props +}: FieldSliderProps) => { + const { layoutProps, restProps: sliderProps } = useMemo(() => getLayoutProps(props), [props]) + + return ( + + + + + + + ) +} diff --git a/src/components/molecules/Field/types.ts b/src/components/molecules/Field/types.ts index acde71ce..1e8fc2cc 100644 --- a/src/components/molecules/Field/types.ts +++ b/src/components/molecules/Field/types.ts @@ -7,6 +7,7 @@ import { SelectProps, StyledProps, TouchableRef, + SliderProps, } from '@/design-system' // ----------------------- @@ -92,3 +93,13 @@ export type FieldCheckboxProps = FormLabelProps & CheckboxProps & { errorMessage?: string } + +// ----------------------- +// ----- SLIDER ------ +// ----------------------- + +export type FieldSliderProps = FormLabelProps & + SliderProps & { + errorMessage?: string + onChangeValue: (value: number) => void + } diff --git a/src/components/organisms/ControlledField/ControlledField.tsx b/src/components/organisms/ControlledField/ControlledField.tsx index 64a21940..f810912f 100644 --- a/src/components/organisms/ControlledField/ControlledField.tsx +++ b/src/components/organisms/ControlledField/ControlledField.tsx @@ -5,6 +5,7 @@ import { ControlledCheckboxGroup } from './ControlledCheckboxGroup' import { ControlledInput } from './ControlledInput' import { ControlledRadioGroup } from './ControlledRadioGroup' import { ControlledSelect } from './ControlledSelect' +import { ControlledSlider } from './ControlledSlider' type ControlledFieldComposition = React.FC & { Input: typeof ControlledInput @@ -12,6 +13,7 @@ type ControlledFieldComposition = React.FC & { RadioGroup: typeof ControlledRadioGroup Checkbox: typeof ControlledCheckbox Select: typeof ControlledSelect + Slider: typeof ControlledSlider } const ControlledField: ControlledFieldComposition = ({ children }) => { @@ -23,6 +25,7 @@ ControlledField.CheckboxGroup = ControlledCheckboxGroup ControlledField.Checkbox = ControlledCheckbox ControlledField.RadioGroup = ControlledRadioGroup ControlledField.Select = ControlledSelect +ControlledField.Slider = ControlledSlider export { ControlledField } export * from './types' diff --git a/src/components/organisms/ControlledField/ControlledSlider.tsx b/src/components/organisms/ControlledField/ControlledSlider.tsx new file mode 100644 index 00000000..09b17f20 --- /dev/null +++ b/src/components/organisms/ControlledField/ControlledSlider.tsx @@ -0,0 +1,43 @@ +import { useCallback } from 'react' +import { Controller, ControllerProps, FieldValues, get } from 'react-hook-form' + +import type { ControlledSliderProps } from './types' +import { Field } from '../../molecules' + +export const ControlledSlider = ({ + control, + name, + errors, + rules, + children, + ...props +}: ControlledSliderProps) => { + const errorMessage = get(errors, name)?.message + + const renderSlider = useCallback( + ({ + field: { onChange, name, value, ref: _ref, ...fieldProps }, + }: Parameters[0]) => { + return ( + + ) + }, + [errorMessage, props] + ) + + return ( + + ) +} diff --git a/src/components/organisms/ControlledField/types.ts b/src/components/organisms/ControlledField/types.ts index 1050d955..8c61ffdc 100644 --- a/src/components/organisms/ControlledField/types.ts +++ b/src/components/organisms/ControlledField/types.ts @@ -6,6 +6,7 @@ import { FieldRadioGroupProps, FieldSelectProps, FieldCheckboxProps, + FieldSliderProps, } from '@/components/molecules' // ----------------------- @@ -68,3 +69,13 @@ export type ControlledCheckboxProps & ControlledFieldProps + +// ----------------------- +// ----- SLIDER ------ +// ----------------------- + +export type ControlledSliderProps = Omit< + FieldSliderProps, + 'onChangeValue' | 'value' +> & + ControlledFieldProps diff --git a/src/design-system/components/Slider.tsx b/src/design-system/components/Slider.tsx new file mode 100644 index 00000000..4b444259 --- /dev/null +++ b/src/design-system/components/Slider.tsx @@ -0,0 +1,25 @@ +import RNSlider from '@react-native-community/slider' + +import { Box } from './Box' +import { SliderProps } from './types' + +export const Slider = ({ + style, + isDisabled, + isInvalid, + value, + onChangeValue, + ...props +}: SliderProps) => { + return ( + + + + ) +} diff --git a/src/design-system/components/index.ts b/src/design-system/components/index.ts index 245103eb..764c777f 100644 --- a/src/design-system/components/index.ts +++ b/src/design-system/components/index.ts @@ -8,6 +8,7 @@ export * from './Column' export * from './GradientBox' export * from './Row' export * from './Spacer' +export * from './Slider' export * from './Text' export * from './Touchables' export * from './ScrollView' diff --git a/src/design-system/components/types.ts b/src/design-system/components/types.ts index 4f0d0897..8ec699c9 100644 --- a/src/design-system/components/types.ts +++ b/src/design-system/components/types.ts @@ -269,3 +269,22 @@ export type CheckboxProps = TouchableProps & { size?: 'sm' | 'md' pb?: SizingValue } + +// ----------------------- +// ----- SLIDER ------ +// ----------------------- + +export type SliderRef = { focus: () => void; blur: () => void } + +export type SliderProps = BoxProps & { + // Logic + onChangeValue: (newValue: number) => void + value?: number + + // UI + isDisabled?: boolean + isInvalid?: boolean + minimumValue?: number + maximumValue?: number + step?: number +} diff --git a/src/hooks/forms/useTestForm.ts b/src/hooks/forms/useTestForm.ts index a3f16ed1..26dffe74 100644 --- a/src/hooks/forms/useTestForm.ts +++ b/src/hooks/forms/useTestForm.ts @@ -10,6 +10,7 @@ const defaultValues: TestFormValues = { email: '', city: '', phone: '', + points: 0, postalCode: '', sex: '', music: [], @@ -69,6 +70,7 @@ export const useTestForm = () => { try { setIsSubmitting(true) setError('') + alert('selected points: ' + data.points) console.log(data) } catch (e) { console.log(e) diff --git a/src/i18n/translations/en.json b/src/i18n/translations/en.json index 00e55679..9c42bada 100644 --- a/src/i18n/translations/en.json +++ b/src/i18n/translations/en.json @@ -312,6 +312,7 @@ "middle": "Middle", "name_placeholder": "Name", "phone_placeholder": "Phone number", + "points": "Points", "postalCode_placeholder": "Postal code", "postsecondary": "Postsecondary", "primary": "Primary", diff --git a/src/i18n/translations/pl.json b/src/i18n/translations/pl.json index 6cb1495a..17fa7c6e 100644 --- a/src/i18n/translations/pl.json +++ b/src/i18n/translations/pl.json @@ -311,6 +311,7 @@ "middle": "Gimnazjalne", "name_placeholder": "Imie", "phone_placeholder": "Telefon", + "points": "Punkty", "postalCode_placeholder": "Kod pocztowy", "postsecondary": "Wyższe", "primary": "Podstawowe", diff --git a/src/screens/TestFormScreen.tsx b/src/screens/TestFormScreen.tsx index 69d61094..a7af3797 100644 --- a/src/screens/TestFormScreen.tsx +++ b/src/screens/TestFormScreen.tsx @@ -192,6 +192,16 @@ export const TestFormScreen = (): JSX.Element => { name="interests" rules={VALIDATION.interests} /> + {t('test_form.additional_comment')} diff --git a/src/types/testForm.ts b/src/types/testForm.ts index 7f7ec8da..8e450e38 100644 --- a/src/types/testForm.ts +++ b/src/types/testForm.ts @@ -3,6 +3,7 @@ export type TestFormValues = { surname: string email: string phone: string + points: number postalCode: string city: string sex: string diff --git a/yarn.lock b/yarn.lock index 18f59776..a4719b8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1250,6 +1250,7 @@ __metadata: "@motify/skeleton": "npm:^0.18.0" "@react-native-async-storage/async-storage": "npm:1.23.1" "@react-native-community/netinfo": "npm:11.4.1" + "@react-native-community/slider": "npm:^4.5.5" "@react-native-google-signin/google-signin": "npm:^13.1.0" "@react-navigation/bottom-tabs": "npm:^7.2.0" "@react-navigation/native": "npm:^7.0.14" @@ -3137,6 +3138,13 @@ __metadata: languageName: node linkType: hard +"@react-native-community/slider@npm:^4.5.5": + version: 4.5.5 + resolution: "@react-native-community/slider@npm:4.5.5" + checksum: 10/8c49f7e0b7d7c37b91c936805106e88ee31011dc210d5c237c07e35d330870536b560b48e6212195fffc2e2706b16c31715b6cebbb2cc33127702bff9850f134 + languageName: node + linkType: hard + "@react-native-google-signin/google-signin@npm:^13.1.0": version: 13.1.0 resolution: "@react-native-google-signin/google-signin@npm:13.1.0"