Skip to content

Commit

Permalink
Merge branch 'main' into cmartins-addDonePaidBadges
Browse files Browse the repository at this point in the history
  • Loading branch information
luacmartins committed Jun 18, 2024
2 parents 170821c + 2a65835 commit 08455c4
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 583 deletions.
10 changes: 0 additions & 10 deletions __mocks__/@react-native-reanimated/index.ts

This file was deleted.

4 changes: 4 additions & 0 deletions docs/_sass/_main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,10 @@ button {
padding: 0;
margin: 0;
}

li {
margin-left: 12px;
}
}
}
}
Expand Down
17 changes: 8 additions & 9 deletions src/pages/InviteReportParticipantsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import InviteMemberListItem from '@components/SelectionList/InviteMemberListItem
import type {Section} from '@components/SelectionList/types';
import withNavigationTransitionEnd from '@components/withNavigationTransitionEnd';
import type {WithNavigationTransitionEndProps} from '@components/withNavigationTransitionEnd';
import useDebouncedState from '@hooks/useDebouncedState';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
Expand Down Expand Up @@ -45,7 +44,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen

const styles = useThemeStyles();
const {translate} = useLocalize();
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
const [searchTerm, setSearchTerm] = useState('');
const [selectedOptions, setSelectedOptions] = useState<ReportUtils.OptionData[]>([]);
const [invitePersonalDetails, setInvitePersonalDetails] = useState<ReportUtils.OptionData[]>([]);
const [recentReports, setRecentReports] = useState<ReportUtils.OptionData[]>([]);
Expand All @@ -58,7 +57,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen
);

useEffect(() => {
const inviteOptions = OptionsListUtils.getMemberInviteOptions(options.personalDetails, betas ?? [], debouncedSearchTerm, excludedUsers, false, options.reports, true);
const inviteOptions = OptionsListUtils.getMemberInviteOptions(options.personalDetails, betas ?? [], searchTerm, excludedUsers, false, options.reports, true);

// Update selectedOptions with the latest personalDetails information
const detailsMap: Record<string, OptionsListUtils.MemberForList> = {};
Expand All @@ -78,7 +77,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen
setRecentReports(inviteOptions.recentReports);
setSelectedOptions(newSelectedOptions);
// eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to recalculate when selectedOptions change
}, [personalDetails, betas, debouncedSearchTerm, excludedUsers, options]);
}, [personalDetails, betas, searchTerm, excludedUsers, options]);

const sections = useMemo(() => {
const sectionsArr: Sections = [];
Expand All @@ -89,11 +88,11 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen

// Filter all options that is a part of the search term or in the personal details
let filterSelectedOptions = selectedOptions;
if (debouncedSearchTerm !== '') {
if (searchTerm !== '') {
filterSelectedOptions = selectedOptions.filter((option) => {
const accountID = option?.accountID;
const isOptionInPersonalDetails = invitePersonalDetails.some((personalDetail) => accountID && personalDetail?.accountID === accountID);
const searchValue = OptionsListUtils.getSearchValueForPhoneOrEmail(debouncedSearchTerm);
const searchValue = OptionsListUtils.getSearchValueForPhoneOrEmail(searchTerm);
const isPartOfSearchTerm = !!option.text?.toLowerCase().includes(searchValue) || !!option.login?.toLowerCase().includes(searchValue);
return isPartOfSearchTerm || isOptionInPersonalDetails;
});
Expand Down Expand Up @@ -131,7 +130,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen
}

return sectionsArr;
}, [invitePersonalDetails, debouncedSearchTerm, selectedOptions, translate, userToInvite, areOptionsInitialized, recentReports]);
}, [invitePersonalDetails, searchTerm, selectedOptions, translate, userToInvite, areOptionsInitialized, recentReports]);

const toggleOption = useCallback(
(option: OptionsListUtils.MemberForList) => {
Expand Down Expand Up @@ -172,7 +171,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen
}, [selectedOptions, backRoute, reportID, validate]);

const headerMessage = useMemo(() => {
const searchValue = debouncedSearchTerm.trim().toLowerCase();
const searchValue = searchTerm.trim().toLowerCase();
const expensifyEmails = CONST.EXPENSIFY_EMAILS as string[];
if (!userToInvite && expensifyEmails.includes(searchValue)) {
return translate('messages.errorMessageInvalidEmail');
Expand All @@ -188,7 +187,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen
return translate('messages.userIsAlreadyMember', {login: searchValue, name: reportName ?? ''});
}
return OptionsListUtils.getHeaderMessage(invitePersonalDetails.length !== 0, !!userToInvite, searchValue);
}, [debouncedSearchTerm, userToInvite, excludedUsers, invitePersonalDetails, translate, reportName]);
}, [searchTerm, userToInvite, excludedUsers, invitePersonalDetails, translate, reportName]);

const footerContent = useMemo(
() => (
Expand Down
40 changes: 32 additions & 8 deletions src/pages/NewChatConfirmPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useMemo, useRef} 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';
Expand All @@ -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';
Expand Down Expand Up @@ -45,7 +46,7 @@ function navigateToEditChatName() {

function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmPageProps) {
const optimisticReportID = useRef<string>(ReportUtils.generateReportID());
const fileRef = useRef<File | CustomRNImageManipulatorResult | undefined>();
const [avatarFile, setAvatarFile] = useState<File | CustomRNImageManipulatorResult | undefined>();
const {translate} = useLocalize();
const styles = useThemeStyles();
const personalData = useCurrentUserPersonalDetails();
Expand Down Expand Up @@ -104,10 +105,33 @@ 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});
};

// 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, 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 (
<ScreenWrapper testID={NewChatConfirmPage.displayName}>
<HeaderWithBackButton
Expand All @@ -119,12 +143,12 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP
isUsingDefaultAvatar={!stashedLocalAvatarImage}
source={stashedLocalAvatarImage ?? ReportUtils.getDefaultGroupAvatar(optimisticReportID.current)}
onImageSelected={(image) => {
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}
Expand Down
6 changes: 6 additions & 0 deletions src/types/onyx/NewGroupChatDraft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ 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};
export default NewGroupChatDraft;
Loading

0 comments on commit 08455c4

Please sign in to comment.