diff --git a/app/(app)/post/[id]/index.tsx b/app/(app)/post/[id]/index.tsx index 1ae9fca..b64113b 100644 --- a/app/(app)/post/[id]/index.tsx +++ b/app/(app)/post/[id]/index.tsx @@ -14,7 +14,7 @@ import UserListItem from '../../../../src/components/uis/UserListItem'; import ControlItem from '../../../../src/components/uis/ControlItem'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import Replies from '../../replies'; -import {useCallback, useRef} from 'react'; +import {useCallback, useRef, useEffect} from 'react'; import {FlashList} from '@shopify/flash-list'; import CustomPressable from 'dooboo-ui/uis/CustomPressable'; import {delayPressIn} from '../../../../src/utils/constants'; @@ -22,17 +22,16 @@ import {useRecoilState} from 'recoil'; import {authRecoilState} from '../../../../src/recoil/atoms'; import {useAppLogic} from '../../../../src/providers/AppLogicProvider'; import {fetchDeletePost, fetchPostById} from '../../../../src/apis/postQueries'; +import {supabase} from '../../../../src/supabase'; const Container = styled.View` background-color: ${({theme}) => theme.bg.basic}; - flex: 1; align-self: stretch; `; const Content = styled.View` padding: 24px; - gap: 24px; `; @@ -49,9 +48,10 @@ export default function PostDetails(): JSX.Element { data: post, error, isValidating, + mutate, } = useSWR(id ? `post-${id}` : null, () => fetchPostById(id || '')); - console.log('post', id) + console.log('post', id); const handleDeletePost = useCallback(async () => { if (!post) return; @@ -93,6 +93,35 @@ export default function PostDetails(): JSX.Element { } }, [post]); + useEffect(() => { + if (!id) return; + + const channel = supabase + .channel('schema-db-changes') + .on( + 'postgres_changes', + { + event: 'UPDATE', + schema: 'public', + table: 'posts', + filter: `id=eq.${id}`, + }, + async (payload) => { + console.log('update', payload); + const updatedPost = await fetchPostById(id); + + if (updatedPost) { + mutate(updatedPost, false); // Update the post data without revalidation + } + }, + ) + .subscribe(); + + return () => { + channel.unsubscribe(); + }; + }, [id, mutate]); + const content = (() => { switch (true) { case isValidating && !authId: diff --git a/app/(app)/post/[id]/update.tsx b/app/(app)/post/[id]/update.tsx index f9670cd..737e55c 100644 --- a/app/(app)/post/[id]/update.tsx +++ b/app/(app)/post/[id]/update.tsx @@ -31,7 +31,7 @@ const Content = styled.View` const schema = yup.object().shape({ title: yup.string().required(t('post.write.titlePlaceholder')), content: yup.string().required(t('post.write.contentPlaceholder')), - url: yup.string(), + url: yup.string().url(t('common.invalidUrl')), }); type FormData = yup.InferType; @@ -189,6 +189,7 @@ export default function PostUpdate(): JSX.Element { placeholder={t('post.write.urlPlaceholder')} value={value} decoration="boxed" + error={errors.url ? errors.url.message : ''} /> )} rules={{required: true, validate: (value) => !!value}} diff --git a/app/(app)/post/write.tsx b/app/(app)/post/write.tsx index 886dc21..2c2804f 100644 --- a/app/(app)/post/write.tsx +++ b/app/(app)/post/write.tsx @@ -27,7 +27,7 @@ const Content = styled.View` const schema = yup.object().shape({ title: yup.string().required(t('post.write.titlePlaceholder')), content: yup.string().required(t('post.write.contentPlaceholder')), - url: yup.string(), + url: yup.string().url(t('common.invalidUrl')), }); type FormData = yup.InferType; @@ -179,6 +179,7 @@ export default function PostWrite(): JSX.Element { placeholder={t('post.write.urlPlaceholder')} value={value} decoration="boxed" + error={errors.url ? errors.url.message : ''} /> )} rules={{required: true, validate: (value) => !!value}} diff --git a/assets/langs/en.json b/assets/langs/en.json index d0c30d1..c9a49c2 100644 --- a/assets/langs/en.json +++ b/assets/langs/en.json @@ -1,38 +1,39 @@ { "common": { "appErrorMessage": "Communication is not smooth.\nPlease check your network status.", - "ok": "OK", + "block": "Block", + "blockUser": "Block {{user}}", + "blockUserDesc": "If you block a user, you will not be able to access the user's content. Do you want to block this user?", + "blockUserSuccess": "User has been blocked", "cancel": "Cancel", "confirm": "Confirm", + "delete": "Delete", + "deleteSuccess": "Successfully deleted", "deletedAccount": "Retired account.", "image": "Image", + "invalidUrl": "Invalid URL", "latest": "Latest", "leaveComment": "Leave a comment", "noComment": "No comments", "notFound": "Not found", + "ok": "OK", "or": "or", "permissionGrantCamera": "Please grant camera permission to take pictures.", "post": "Post", "profile": "Profile", + "report": "Report", + "reportSubject": "Report {{subject}}", "retry": "Retry", "selectFromGallery": "Select from gallery", "takeAPhoto": "Take a photo", + "unhandledError": "An unhandled error occurred.", + "update": "Update", "updateApp": "Update App", + "user": "User", "viewsWithCount": { "one": "Views %{count}", "other": "Views %{count}" - }, - "reportSubject": "Report {{subject}}", - "report": "Report", - "block": "Block", - "blockUser": "Block {{user}}", - "blockUserDesc": "If you block a user, you will not be able to access the user's content. Do you want to block this user?", - "blockUserSuccess": "User has been blocked", - "delete": "Delete", - "user": "User", - "deleteSuccess": "Successfully deleted", - "unhandledError": "An unhandled error occurred.", - "update": "Update" + } }, "error": { "default": "Error occurred!" @@ -47,6 +48,10 @@ "title": "Login Information" }, "post": { + "update": { + "updateFailed": "Update failed!", + "updateSuccess": "Successfully updated!" + }, "write": { "content": "Content", "contentPlaceholder": "Enter the content", @@ -58,10 +63,6 @@ "write": "Write", "writeFailed": "Write failed!", "writeSuccess": "Successfully written!" - }, - "update": { - "updateFailed": "Update failed!", - "updateSuccess": "Successfully updated!" } }, "settings": { diff --git a/assets/langs/ko.json b/assets/langs/ko.json index fe67cb6..d375c7c 100644 --- a/assets/langs/ko.json +++ b/assets/langs/ko.json @@ -1,38 +1,39 @@ { "common": { "appErrorMessage": "통신이 원활하지 않습니다.\n네트워크 상태를 확인해주세요.", + "block": "차단", + "blockUser": "{{user}} 차단", + "blockUserDesc": "사용자를 차단하면 해당 사용자의 콘텐츠에 접근할 수 없습니다. 이 사용자를 차단하시겠습니까?", + "blockUserSuccess": "사용자가 차단되었습니다", "cancel": "취소", - "ok": "확인", "confirm": "확인", + "delete": "삭제", + "deleteSuccess": "성공적으로 삭제되었습니다", "deletedAccount": "탈퇴한 계정입니다.", "image": "이미지", + "invalidUrl": "유효하지 않은 URL", "latest": "최신순", "leaveComment": "댓글 남기기", "noComment": "댓글이 없습니다", "notFound": "찾을 수 없습니다", + "ok": "확인", "or": "또는", "permissionGrantCamera": "촬영을 위해 카메라 권한을 부여해주세요.", "post": "게시판", "profile": "프로필", + "report": "신고", + "reportSubject": "Report {{subject}}", "retry": "재시도", "selectFromGallery": "갤러리에서 선택", "takeAPhoto": "사진 찍기", + "unhandledError": "처리되지 않은 오류가 발생했습니다.", + "update": "업데이트", "updateApp": "앱 업데이트", + "user": "사용자", "viewsWithCount": { "one": "조회수 %{count}", "other": "조회수 %{count}" - }, - "reportSubject": "Report {{subject}}", - "report": "신고", - "block": "차단", - "blockUser": "{{user}} 차단", - "blockUserDesc": "사용자를 차단하면 해당 사용자의 콘텐츠에 접근할 수 없습니다. 이 사용자를 차단하시겠습니까?", - "blockUserSuccess": "사용자가 차단되었습니다", - "delete": "삭제", - "user": "사용자", - "deleteSuccess": "성공적으로 삭제되었습니다", - "unhandledError": "처리되지 않은 오류가 발생했습니다.", - "update": "업데이트" + } }, "error": { "default": "오류가 발생했습니다!" @@ -47,6 +48,10 @@ "title": "로그인 정보" }, "post": { + "update": { + "updateFailed": "업데이트에 실패했습니다!", + "updateSuccess": "성공적으로 업데이트되었습니다!" + }, "write": { "content": "내용", "contentPlaceholder": "내용을 입력하세요", @@ -58,10 +63,6 @@ "write": "글쓰기", "writeFailed": "작성에 실패했습니다!", "writeSuccess": "성공적으로 작성되었습니다!" - }, - "update": { - "updateFailed": "업데이트에 실패했습니다!", - "updateSuccess": "성공적으로 업데이트되었습니다!" } }, "settings": {