From 89824350745307336616627d515cfd2c7bb106ba Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sun, 9 Jun 2024 23:12:25 +0700 Subject: [PATCH 1/4] Fix avatar attachment missing when re-select members --- src/pages/NewChatConfirmPage.tsx | 36 ++++++++++++++++++++++------- src/types/onyx/NewGroupChatDraft.ts | 3 +++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/pages/NewChatConfirmPage.tsx b/src/pages/NewChatConfirmPage.tsx index 2c94dbbc7840..f9c8e290c25c 100644 --- a/src/pages/NewChatConfirmPage.tsx +++ b/src/pages/NewChatConfirmPage.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useMemo, useRef} from 'react'; +import React, {useCallback, useMemo, useRef, useState, useEffect} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -24,6 +24,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; +import * as FileUtils from '@libs/fileDownload/FileUtils'; type NewChatConfirmPageOnyxProps = { /** New group chat draft data */ @@ -45,7 +46,7 @@ function navigateToEditChatName() { function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmPageProps) { const optimisticReportID = useRef(ReportUtils.generateReportID()); - const fileRef = useRef(); + const [avatarFile, setAvatarFile] = useState(); const {translate} = useLocalize(); const styles = useThemeStyles(); const personalData = useCurrentUserPersonalDetails(); @@ -104,10 +105,29 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP } const logins: string[] = (newGroupDraft.participants ?? []).map((participant) => participant.login); - Report.navigateToAndOpenReport(logins, true, newGroupDraft.reportName ?? '', newGroupDraft.avatarUri ?? '', fileRef.current, optimisticReportID.current, true); - }, [newGroupDraft]); + Report.navigateToAndOpenReport(logins, true, newGroupDraft.reportName ?? '', newGroupDraft.avatarUri ?? '', avatarFile, optimisticReportID.current, true); + }, [newGroupDraft, avatarFile]); const stashedLocalAvatarImage = newGroupDraft?.avatarUri; + + useEffect(() => { + if (!stashedLocalAvatarImage) { + return; + } + + const onSuccess = (file: File) => { + setAvatarFile(file) + }; + + + const onFailure = () => { + setAvatarFile(undefined); + Report.setGroupDraft({avatarUri: null, avatarFileName: null, avatarFileType: null}); + }; + FileUtils.readFileAsync(stashedLocalAvatarImage.toString(), newGroupDraft?.avatarFileName ?? '', onSuccess, onFailure, newGroupDraft?.avatarFileType ?? ''); + + }, []); + return ( { - fileRef.current = image; - Report.setGroupDraft({avatarUri: image?.uri ?? ''}); + setAvatarFile(image); + Report.setGroupDraft({ avatarUri: image?.uri ?? '', avatarFileName: image?.name ?? '', avatarFileType: image?.type }); }} onImageRemoved={() => { - fileRef.current = undefined; - Report.setGroupDraft({avatarUri: null}); + setAvatarFile(undefined); + Report.setGroupDraft({avatarUri: null, avatarFileName: null, avatarFileType: null}); }} size={CONST.AVATAR_SIZE.XLARGE} avatarStyle={styles.avatarXLarge} diff --git a/src/types/onyx/NewGroupChatDraft.ts b/src/types/onyx/NewGroupChatDraft.ts index 9e4ad3c54299..57b16e8b2f92 100644 --- a/src/types/onyx/NewGroupChatDraft.ts +++ b/src/types/onyx/NewGroupChatDraft.ts @@ -17,6 +17,9 @@ type NewGroupChatDraft = { /** New group chat avatar URI */ avatarUri: string | null; + + avatarFileName: string | null; + avatarFileType: string | null; }; export type {SelectedParticipant}; export default NewGroupChatDraft; From 51bbb2a7cbab8260be4b60eca758ba3f1417769b Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 12 Jun 2024 21:53:13 +0700 Subject: [PATCH 2/4] Run prettier and lint --- src/pages/NewChatConfirmPage.tsx | 18 +++++++++++------- src/types/onyx/NewGroupChatDraft.ts | 3 +++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/pages/NewChatConfirmPage.tsx b/src/pages/NewChatConfirmPage.tsx index f9c8e290c25c..5cd2296895f2 100644 --- a/src/pages/NewChatConfirmPage.tsx +++ b/src/pages/NewChatConfirmPage.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useMemo, useRef, useState, useEffect} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -15,6 +15,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import type {CustomRNImageManipulatorResult} from '@libs/cropOrRotateImage/types'; +import * as FileUtils from '@libs/fileDownload/FileUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -24,7 +25,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; -import * as FileUtils from '@libs/fileDownload/FileUtils'; type NewChatConfirmPageOnyxProps = { /** New group chat draft data */ @@ -46,7 +46,7 @@ function navigateToEditChatName() { function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmPageProps) { const optimisticReportID = useRef(ReportUtils.generateReportID()); - const [avatarFile, setAvatarFile] = useState(); + const [avatarFile, setAvatarFile] = useState(); const {translate} = useLocalize(); const styles = useThemeStyles(); const personalData = useCurrentUserPersonalDetails(); @@ -116,16 +116,20 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP } const onSuccess = (file: File) => { - setAvatarFile(file) + setAvatarFile(file); }; - const onFailure = () => { setAvatarFile(undefined); Report.setGroupDraft({avatarUri: null, avatarFileName: null, avatarFileType: null}); }; + + // If the user navigates back to the member selection page and then returns to the confirmation page, the component will re-mount, causing avatarFile to be null. + // To handle this, we re-read the avatar image file from disk whenever the component re-mounts. FileUtils.readFileAsync(stashedLocalAvatarImage.toString(), newGroupDraft?.avatarFileName ?? '', onSuccess, onFailure, newGroupDraft?.avatarFileType ?? ''); - + + // we only need to run this when the component re-mounted + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( @@ -140,7 +144,7 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP source={stashedLocalAvatarImage ?? ReportUtils.getDefaultGroupAvatar(optimisticReportID.current)} onImageSelected={(image) => { setAvatarFile(image); - Report.setGroupDraft({ avatarUri: image?.uri ?? '', avatarFileName: image?.name ?? '', avatarFileType: image?.type }); + Report.setGroupDraft({avatarUri: image?.uri ?? '', avatarFileName: image?.name ?? '', avatarFileType: image?.type}); }} onImageRemoved={() => { setAvatarFile(undefined); diff --git a/src/types/onyx/NewGroupChatDraft.ts b/src/types/onyx/NewGroupChatDraft.ts index 57b16e8b2f92..e075ed6e5e33 100644 --- a/src/types/onyx/NewGroupChatDraft.ts +++ b/src/types/onyx/NewGroupChatDraft.ts @@ -18,7 +18,10 @@ type NewGroupChatDraft = { /** New group chat avatar URI */ avatarUri: string | null; + /** New group chat avatar file name */ avatarFileName: string | null; + + /** New group chat avatar file type */ avatarFileType: string | null; }; export type {SelectedParticipant}; From 1a991856ef91a515c0849144606994a934b02ae2 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 13 Jun 2024 10:22:44 +0700 Subject: [PATCH 3/4] Update src/pages/NewChatConfirmPage.tsx Co-authored-by: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> --- src/pages/NewChatConfirmPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/NewChatConfirmPage.tsx b/src/pages/NewChatConfirmPage.tsx index 5cd2296895f2..c91aba1abadd 100644 --- a/src/pages/NewChatConfirmPage.tsx +++ b/src/pages/NewChatConfirmPage.tsx @@ -126,7 +126,7 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP // If the user navigates back to the member selection page and then returns to the confirmation page, the component will re-mount, causing avatarFile to be null. // To handle this, we re-read the avatar image file from disk whenever the component re-mounts. - FileUtils.readFileAsync(stashedLocalAvatarImage.toString(), newGroupDraft?.avatarFileName ?? '', onSuccess, onFailure, newGroupDraft?.avatarFileType ?? ''); + FileUtils.readFileAsync(stashedLocalAvatarImage, newGroupDraft?.avatarFileName ?? '', onSuccess, onFailure, newGroupDraft?.avatarFileType ?? ''); // we only need to run this when the component re-mounted // eslint-disable-next-line react-hooks/exhaustive-deps From 4a042be48b4f37f8dbfc5216eb0c3d9d80ba0ec0 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 13 Jun 2024 10:23:55 +0700 Subject: [PATCH 4/4] Update src/pages/NewChatConfirmPage.tsx Co-authored-by: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> --- src/pages/NewChatConfirmPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/NewChatConfirmPage.tsx b/src/pages/NewChatConfirmPage.tsx index c91aba1abadd..78e28cda332f 100644 --- a/src/pages/NewChatConfirmPage.tsx +++ b/src/pages/NewChatConfirmPage.tsx @@ -144,7 +144,7 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP source={stashedLocalAvatarImage ?? ReportUtils.getDefaultGroupAvatar(optimisticReportID.current)} onImageSelected={(image) => { setAvatarFile(image); - Report.setGroupDraft({avatarUri: image?.uri ?? '', avatarFileName: image?.name ?? '', avatarFileType: image?.type}); + Report.setGroupDraft({avatarUri: image.uri ?? '', avatarFileName: image.name ?? '', avatarFileType: image.type}); }} onImageRemoved={() => { setAvatarFile(undefined);