From ed78fb2bfaa38e77b677744dacccbe6286393ab7 Mon Sep 17 00:00:00 2001 From: Gavin Kasdorf Date: Tue, 24 Oct 2023 23:08:58 -0700 Subject: [PATCH] [feat] Add edit comment --- CHANGELOG.md | 4 + .../hooks/useCommentContextMenu.ts | 2 +- src/components/Navigation/MainScreens.tsx | 6 ++ .../Reply/hooks/useEditReplyScreen.tsx | 100 ++++++++++++++++++ .../Reply/screens/EditReplyScreen.tsx | 52 +++++++++ src/helpers/comments/getParentId.ts | 5 + src/helpers/comments/index.ts | 1 + src/state/comment/actions/updateComment.ts | 13 +++ 8 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 src/components/Reply/hooks/useEditReplyScreen.tsx create mode 100644 src/components/Reply/screens/EditReplyScreen.tsx create mode 100644 src/helpers/comments/getParentId.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 09bd40c1c..dc1e587f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Toast added to both reply and post screen +### Added + +- Added edit comments + ## [Version 1.0 (46)] - 2023-10-23T11:20:39Z ### Fixed diff --git a/src/components/Common/ContextMenu/hooks/useCommentContextMenu.ts b/src/components/Common/ContextMenu/hooks/useCommentContextMenu.ts index 1ecde56f6..ac05c8d7e 100644 --- a/src/components/Common/ContextMenu/hooks/useCommentContextMenu.ts +++ b/src/components/Common/ContextMenu/hooks/useCommentContextMenu.ts @@ -60,7 +60,7 @@ export const useCommentContextMenu = ( }; const edit = (): void => { - navigation.push('Reply', { commentId: itemId, edit: true }); + navigation.push('EditReply', { commentId: itemId }); }; const delet = (): void => { diff --git a/src/components/Navigation/MainScreens.tsx b/src/components/Navigation/MainScreens.tsx index f61da68f6..501410af4 100644 --- a/src/components/Navigation/MainScreens.tsx +++ b/src/components/Navigation/MainScreens.tsx @@ -17,6 +17,7 @@ import ReplyScreen from '@components/Reply/screens/ReplyScreen'; import ProfileScreen from '@components/Profile/screens/ProfileScreen'; import NewPostScreen from '@components/NewPost/screens/NewPostScreen'; import WebViewScreen from '@components/WebViewer/WebViewScreen'; +import EditReplyScreen from '@components/Reply/screens/EditReplyScreen'; export default function MainScreens( stack: TypedNavigator< @@ -73,6 +74,11 @@ export default function MainScreens( component={NewPostScreen} options={{ gestureEnabled: false, headerTitle: 'New Post' }} /> + >; + selection: ITextSelection; + onSelectionChange: ( + e: NativeSyntheticEvent, + ) => void; + isLoading: boolean; + inputRef: React.MutableRefObject; +} + +export const useEditReplyScreen = (): UseEditReplyScreen => { + const navigation = useNavigation>(); + const { commentId } = useRoute().params; + + const commentContent = useCommentContent(commentId); + + const [text, setText] = useState(commentContent ?? ''); + const [selection, setSelection] = useState({ + start: 0, + end: 0, + }); + + const { isLoading, refresh: submit } = useLoadData(); + + const inputRef = useRef(); + + const onSubmitPress = (): void => { + submit(async () => { + await instance.editComment(commentId, text); + + updateCommentContent(commentId, text); + + navigation.pop(); + }); + }; + + const onSelectionChange = useCallback( + (e: NativeSyntheticEvent) => { + setSelection({ + start: e.nativeEvent.selection.start, + end: e.nativeEvent.selection.end, + }); + }, + [setSelection], + ); + + useEffect(() => { + navigation.setOptions({ + headerLeft: () => ( + { + navigation.pop(); + }} + /> + ), + }); + + inputRef.current?.setNativeProps({ + text, + }); + }, []); + + useEffect(() => { + navigation.setOptions({ + headerRight: () => ( + + ), + }); + }, [text]); + + return { + text, + setText, + onSelectionChange, + selection, + isLoading, + inputRef, + }; +}; diff --git a/src/components/Reply/screens/EditReplyScreen.tsx b/src/components/Reply/screens/EditReplyScreen.tsx new file mode 100644 index 000000000..7d0418816 --- /dev/null +++ b/src/components/Reply/screens/EditReplyScreen.tsx @@ -0,0 +1,52 @@ +import React, { useCallback, useRef } from 'react'; +import { INavigationProps } from '@src/types'; +import { ScrollView, YStack } from 'tamagui'; +import AppToast from '@components/Common/Toast/AppToast'; +import LoadingOverlay from '@components/Common/Loading/LoadingOverlay'; +import TextInput from '@components/Common/Form/TextInput'; +import KeyboardAccessoryView from '@components/Common/Keyboard/KeyboardAccesoryView'; +import { useEditReplyScreen } from '@components/Reply/hooks/useEditReplyScreen'; +import { ScrollView as RNScrollView } from 'react-native'; + +export default function EditReplyScreen({ + navigation, + route, +}: INavigationProps): React.JSX.Element { + const editReplyScreen = useEditReplyScreen(); + + const viewRef = useRef(); + + const onLayout = useCallback(() => { + viewRef.current?.scrollToEnd({ animated: false }); + }, []); + + return ( + <> + {/* @ts-expect-error - this is valid */} + + + + + + + + + + ); +} diff --git a/src/helpers/comments/getParentId.ts b/src/helpers/comments/getParentId.ts new file mode 100644 index 000000000..21ba95a15 --- /dev/null +++ b/src/helpers/comments/getParentId.ts @@ -0,0 +1,5 @@ +export const getParentId = (path: string): number => { + const pathArr = path.split('.'); + + return Number(pathArr[pathArr.length - 2]); +}; diff --git a/src/helpers/comments/index.ts b/src/helpers/comments/index.ts index 2577ca1ac..03d87e503 100644 --- a/src/helpers/comments/index.ts +++ b/src/helpers/comments/index.ts @@ -1,2 +1,3 @@ export * from './buildCommentChains'; export * from './createCommentReplyComponents'; +export * from './getParentId'; diff --git a/src/state/comment/actions/updateComment.ts b/src/state/comment/actions/updateComment.ts index e1a794c4d..52eb0edbe 100644 --- a/src/state/comment/actions/updateComment.ts +++ b/src/state/comment/actions/updateComment.ts @@ -12,3 +12,16 @@ export const updateComment = (comment: CommentView): void => { current.view.comment.deleted = comment.comment.deleted; }); }; + +export const updateCommentContent = ( + commentId: number, + content: string, +): void => { + useCommentStore.setState((state) => { + const current = state.comments.get(commentId); + + if (current == null) return; + + current.view.comment.content = content; + }); +};