From 7d23f2fda5cf57c99ff66902f159387d33abe0a9 Mon Sep 17 00:00:00 2001 From: Innei Date: Fri, 28 Feb 2025 13:38:04 +0800 Subject: [PATCH] refactor(mobile): simplify SafeModalScrollView and RSSHub form handling - Replace KeyboardAwareScrollView with standard ScrollView - Update form error handling to use JSON parsing - Modify ScreenOptions and ModalHeaderSubmitButtonImpl to pass form errors - Improve type safety and component props Signed-off-by: Innei --- .../layouts/views/SafeModalScrollView.tsx | 10 ++-- .../src/screens/(modal)/rsshub-form.tsx | 60 ++++++++++++------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/apps/mobile/src/components/layouts/views/SafeModalScrollView.tsx b/apps/mobile/src/components/layouts/views/SafeModalScrollView.tsx index 85a5692c1..f8013faa2 100644 --- a/apps/mobile/src/components/layouts/views/SafeModalScrollView.tsx +++ b/apps/mobile/src/components/layouts/views/SafeModalScrollView.tsx @@ -8,21 +8,21 @@ * ``` */ import { useHeaderHeight } from "@react-navigation/elements" -import type { KeyboardAwareScrollViewProps } from "react-native-keyboard-controller" -import { KeyboardAwareScrollView } from "react-native-keyboard-controller" +import type { ScrollViewProps } from "react-native" +import { ScrollView } from "react-native" import { useSafeAreaInsets } from "react-native-safe-area-context" -interface SafeModalScrollViewProps extends KeyboardAwareScrollViewProps {} +interface SafeModalScrollViewProps extends ScrollViewProps {} export const SafeModalScrollView = (props: SafeModalScrollViewProps) => { const headerHeight = useHeaderHeight() const insets = useSafeAreaInsets() return ( - {props.children} - + ) } diff --git a/apps/mobile/src/screens/(modal)/rsshub-form.tsx b/apps/mobile/src/screens/(modal)/rsshub-form.tsx index d69c167a9..7078a700e 100644 --- a/apps/mobile/src/screens/(modal)/rsshub-form.tsx +++ b/apps/mobile/src/screens/(modal)/rsshub-form.tsx @@ -8,6 +8,7 @@ import { import { zodResolver } from "@hookform/resolvers/zod" import { router, Stack, useLocalSearchParams } from "expo-router" import { memo, useEffect, useMemo, useState } from "react" +import type { FieldErrors } from "react-hook-form" import { Controller, useForm } from "react-hook-form" import { Linking, Text, TouchableOpacity, View } from "react-native" import { z } from "zod" @@ -111,6 +112,9 @@ function FormImpl({ route, routePrefix, name }: RsshubFormParams) { mode: "all", }) + // eslint-disable-next-line unicorn/prefer-structured-clone + const nextErrors = JSON.parse(JSON.stringify(form.formState.errors)) + return ( @@ -231,33 +236,40 @@ type ScreenOptionsProps = { routeName: string route: string routePrefix: string + errors: FieldErrors } -const ScreenOptions = memo(({ name, routeName, route, routePrefix }: ScreenOptionsProps) => { - const form = useFormContext() +const ScreenOptions = memo( + ({ name, routeName, route, routePrefix, errors }: ScreenOptionsProps) => { + const form = useFormContext() - return ( - ( - - - - ), + headerRight: () => ( + + + + ), - headerTitle: () => ( - - ), - }} - /> - ) -}) + headerTitle: () => ( + <Title name={name} routeName={routeName} route={route} routePrefix={routePrefix} /> + ), + }} + /> + ) + }, +) -const Title = ({ name, routeName, route, routePrefix }: ScreenOptionsProps) => { +const Title = ({ name, routeName, route, routePrefix }: Omit<ScreenOptionsProps, "errors">) => { return ( <HeaderTitleExtra subText={`rsshub://${routePrefix}${route}`}> {`${name} - ${routeName}`} @@ -270,12 +282,14 @@ const routeParamsKeyPrefix = "route-params-" const ModalHeaderSubmitButtonImpl = ({ routePrefix, route, + errors, }: { routePrefix: string route: string + errors: FieldErrors }) => { const form = useFormContext() - const { isValid } = form.formState + const isValid = Object.keys(errors).length === 0 const [isLoading, setIsLoading] = useState(false)