Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Travel - Enable trip room renaming #55936

Merged
merged 15 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1715,9 +1715,6 @@ const translations = {
roomDescriptionOptional: 'Room description (optional)',
explainerText: 'Set a custom description for the room.',
},
groupConfirmPage: {
groupName: 'Group name',
},
groupChat: {
lastMemberTitle: 'Heads up!',
lastMemberWarning: "Since you're the last person here, leaving will make this chat inaccessible to all members. Are you sure you want to leave?",
Expand Down Expand Up @@ -4644,6 +4641,7 @@ const translations = {
},
newRoomPage: {
newRoom: 'New room',
groupName: 'Group name',
roomName: 'Room name',
visibility: 'Visibility',
restrictedDescription: 'People in your workspace can find this room',
Expand Down
4 changes: 1 addition & 3 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1718,9 +1718,6 @@ const translations = {
roomDescriptionOptional: 'Descripción de la sala de chat (opcional)',
explainerText: 'Establece una descripción personalizada para la sala de chat.',
},
groupConfirmPage: {
groupName: 'Nombre del grupo',
},
groupChat: {
lastMemberTitle: '¡Atención!',
lastMemberWarning: 'Ya que eres la última persona aquí, si te vas, este chat quedará inaccesible para todos los miembros. ¿Estás seguro de que quieres salir del chat?',
Expand Down Expand Up @@ -4692,6 +4689,7 @@ const translations = {
},
newRoomPage: {
newRoom: 'Nueva sala de chat',
groupName: 'Nombre del grupo',
roomName: 'Nombre de la sala',
visibility: 'Visibilidad',
restrictedDescription: 'Sólo las personas en tu espacio de trabajo pueden encontrar esta sala',
Expand Down
6 changes: 6 additions & 0 deletions src/libs/API/parameters/UpdateChatNameParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type UpdateChatNameParams = {
reportName: string;
reportID: string;
};

export default UpdateChatNameParams;
5 changes: 0 additions & 5 deletions src/libs/API/parameters/UpdateGroupChatNameParams.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export type {default as UpdateAutomaticTimezoneParams} from './UpdateAutomaticTi
export type {default as UpdateChatPriorityModeParams} from './UpdateChatPriorityModeParams';
export type {default as UpdateDateOfBirthParams} from './UpdateDateOfBirthParams';
export type {default as UpdateDisplayNameParams} from './UpdateDisplayNameParams';
export type {default as UpdateGroupChatNameParams} from './UpdateGroupChatNameParams';
export type {default as UpdateChatNameParams} from './UpdateChatNameParams';
export type {default as UpdateGroupChatMemberRolesParams} from './UpdateGroupChatMemberRolesParams';
export type {default as UpdateHomeAddressParams} from './UpdateHomeAddressParams';
export type {default as UpdatePolicyAddressParams} from './UpdatePolicyAddressParams';
Expand Down
4 changes: 3 additions & 1 deletion src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ const WRITE_COMMANDS = {
LEAVE_GROUP_CHAT: 'LeaveGroupChat',
INVITE_TO_ROOM: 'InviteToRoom',
INVITE_TO_GROUP_CHAT: 'InviteToGroupChat',
UPDATE_TRIP_ROOM_NAME: 'UpdateTripRoomName',
UPDATE_GROUP_CHAT_NAME: 'UpdateGroupChatName',
UPDATE_GROUP_CHAT_MEMBER_ROLES: 'UpdateGroupChatMemberRoles',
REMOVE_FROM_ROOM: 'RemoveFromRoom',
Expand Down Expand Up @@ -563,7 +564,8 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.LEAVE_GROUP_CHAT]: Parameters.LeaveGroupChatParams;
[WRITE_COMMANDS.REMOVE_FROM_GROUP_CHAT]: Parameters.RemoveFromGroupChatParams;
[WRITE_COMMANDS.UPDATE_GROUP_CHAT_MEMBER_ROLES]: Parameters.UpdateGroupChatMemberRolesParams;
[WRITE_COMMANDS.UPDATE_GROUP_CHAT_NAME]: Parameters.UpdateGroupChatNameParams;
[WRITE_COMMANDS.UPDATE_TRIP_ROOM_NAME]: Parameters.UpdateChatNameParams;
[WRITE_COMMANDS.UPDATE_GROUP_CHAT_NAME]: Parameters.UpdateChatNameParams;
[WRITE_COMMANDS.REMOVE_FROM_ROOM]: Parameters.RemoveFromRoomParams;
[WRITE_COMMANDS.FLAG_COMMENT]: Parameters.FlagCommentParams;
[WRITE_COMMANDS.UPDATE_REPORT_PRIVATE_NOTE]: Parameters.UpdateReportPrivateNoteParams;
Expand Down
13 changes: 8 additions & 5 deletions src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ import type {
SearchForReportsParams,
SearchForRoomsToMentionParams,
TogglePinnedChatParams,
UpdateChatNameParams,
UpdateCommentParams,
UpdateGroupChatAvatarParams,
UpdateGroupChatMemberRolesParams,
UpdateGroupChatNameParams,
UpdatePolicyRoomNameParams,
UpdateReportNotificationPreferenceParams,
UpdateReportPrivateNoteParams,
Expand Down Expand Up @@ -725,7 +725,7 @@ function reportActionsExist(reportID: string): boolean {
return allReportActions?.[reportID] !== undefined;
}

function updateGroupChatName(reportID: string, reportName: string) {
function updateChatName(reportID: string, reportName: string, type: typeof CONST.REPORT.CHAT_TYPE.GROUP | typeof CONST.REPORT.CHAT_TYPE.TRIP_ROOM) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -765,8 +765,11 @@ function updateGroupChatName(reportID: string, reportName: string) {
},
},
];
const parameters: UpdateGroupChatNameParams = {reportName, reportID};
API.write(WRITE_COMMANDS.UPDATE_GROUP_CHAT_NAME, parameters, {optimisticData, successData, failureData});

const command = type === CONST.REPORT.CHAT_TYPE.GROUP ? WRITE_COMMANDS.UPDATE_GROUP_CHAT_NAME : WRITE_COMMANDS.UPDATE_TRIP_ROOM_NAME;
const parameters: UpdateChatNameParams = {reportName, reportID};

API.write(command, parameters, {optimisticData, successData, failureData});
}

function updateGroupChatAvatar(reportID: string, file?: File | CustomRNImageManipulatorResult) {
Expand Down Expand Up @@ -4728,7 +4731,7 @@ export {
updateDescription,
updateGroupChatAvatar,
updateGroupChatMemberRoles,
updateGroupChatName,
updateChatName,
updateLastVisitTime,
updateLoadingInitialReportAction,
updateNotificationPreference,
Expand Down
19 changes: 8 additions & 11 deletions src/pages/GroupChatNameEditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {NewChatNavigatorParamList} from '@libs/Navigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import * as ValidationUtils from '@libs/ValidationUtils';
import * as Report from '@userActions/Report';
import {getGroupChatName} from '@libs/ReportUtils';
import {isValidReportName} from '@libs/ValidationUtils';
import {setGroupDraft, updateChatName} from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand All @@ -38,17 +38,14 @@ function GroupChatNameEditPage({report}: GroupChatNameEditPageProps) {
const {translate} = useLocalize();
const {inputCallbackRef} = useAutoFocusInput();

const existingReportName = useMemo(
() => (report ? ReportUtils.getGroupChatName(undefined, false, report) : ReportUtils.getGroupChatName(groupChatDraft?.participants)),
[groupChatDraft?.participants, report],
);
const existingReportName = useMemo(() => (report ? getGroupChatName(undefined, false, report) : getGroupChatName(groupChatDraft?.participants)), [groupChatDraft?.participants, report]);
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const currentChatName = reportID ? existingReportName : groupChatDraft?.reportName || existingReportName;

const validate = useCallback(
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.NEW_CHAT_NAME_FORM>): Errors => {
const errors: Errors = {};
if (!ValidationUtils.isValidReportName(values[INPUT_IDS.NEW_CHAT_NAME] ?? '')) {
if (!isValidReportName(values[INPUT_IDS.NEW_CHAT_NAME] ?? '')) {
errors.newChatName = translate('common.error.characterLimit', {limit: CONST.REPORT_NAME_LIMIT});
}

Expand All @@ -61,15 +58,15 @@ function GroupChatNameEditPage({report}: GroupChatNameEditPageProps) {
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.NEW_CHAT_NAME_FORM>) => {
if (isUpdatingExistingReport) {
if (values[INPUT_IDS.NEW_CHAT_NAME] !== currentChatName) {
Report.updateGroupChatName(reportID, values[INPUT_IDS.NEW_CHAT_NAME] ?? '');
updateChatName(reportID, values[INPUT_IDS.NEW_CHAT_NAME] ?? '', CONST.REPORT.CHAT_TYPE.GROUP);
}

Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID)));

return;
}
if (values[INPUT_IDS.NEW_CHAT_NAME] !== currentChatName) {
Report.setGroupDraft({reportName: values[INPUT_IDS.NEW_CHAT_NAME]});
setGroupDraft({reportName: values[INPUT_IDS.NEW_CHAT_NAME]});
}
Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.goBack(ROUTES.NEW_CHAT_CONFIRM));
},
Expand All @@ -84,7 +81,7 @@ function GroupChatNameEditPage({report}: GroupChatNameEditPageProps) {
shouldEnableMaxHeight
>
<HeaderWithBackButton
title={translate('groupConfirmPage.groupName')}
title={translate('newRoomPage.groupName')}
onBackButtonPress={() => Navigation.goBack(isUpdatingExistingReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID) : ROUTES.NEW_CHAT_CONFIRM)}
/>
<FormProvider
Expand Down
58 changes: 21 additions & 37 deletions src/pages/NewChatConfirmPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
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';
import {useOnyx} from 'react-native-onyx';
import AvatarWithImagePicker from '@components/AvatarWithImagePicker';
import Badge from '@components/Badge';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
Expand All @@ -15,27 +14,16 @@ 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 {readFileAsync} from '@libs/fileDownload/FileUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as Report from '@userActions/Report';
import {getParticipantsOption} from '@libs/OptionsListUtils';
import {generateReportID, getDefaultGroupAvatar, getGroupChatName} from '@libs/ReportUtils';
import {navigateToAndOpenReport, setGroupDraft} from '@userActions/Report';
import CONST from '@src/CONST';
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';

type NewChatConfirmPageOnyxProps = {
/** New group chat draft data */
newGroupDraft: OnyxEntry<OnyxTypes.NewGroupChatDraft>;

/** All of the personal details for everyone */
allPersonalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>;
};

type NewChatConfirmPageProps = NewChatConfirmPageOnyxProps;

function navigateBack() {
Navigation.goBack(ROUTES.NEW_CHAT);
}
Expand All @@ -44,23 +32,26 @@ function navigateToEditChatName() {
Navigation.navigate(ROUTES.NEW_CHAT_EDIT_NAME);
}

function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmPageProps) {
const optimisticReportID = useRef<string>(ReportUtils.generateReportID());
function NewChatConfirmPage() {
const optimisticReportID = useRef<string>(generateReportID());
const [avatarFile, setAvatarFile] = useState<File | CustomRNImageManipulatorResult | undefined>();
const {translate} = useLocalize();
const styles = useThemeStyles();
const personalData = useCurrentUserPersonalDetails();
const [newGroupDraft] = useOnyx(ONYXKEYS.NEW_GROUP_CHAT_DRAFT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Came from this issue
Looks like using useOnyx instead withOnyx called this issue

To fix this we updated a condition here to call readFileAsync after the onyx value is loaded completely

const [allPersonalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);

const selectedOptions = useMemo((): Participant[] => {
if (!newGroupDraft?.participants) {
return [];
}
const options: Participant[] = newGroupDraft.participants.map((participant) =>
OptionsListUtils.getParticipantsOption({accountID: participant.accountID, login: participant?.login, reportID: ''}, allPersonalDetails),
getParticipantsOption({accountID: participant.accountID, login: participant?.login, reportID: ''}, allPersonalDetails),
);
return options;
}, [allPersonalDetails, newGroupDraft?.participants]);

const groupName = newGroupDraft?.reportName ? newGroupDraft?.reportName : ReportUtils.getGroupChatName(newGroupDraft?.participants);
const groupName = newGroupDraft?.reportName ? newGroupDraft?.reportName : getGroupChatName(newGroupDraft?.participants);
const sections: ListItem[] = useMemo(
() =>
selectedOptions
Expand Down Expand Up @@ -93,7 +84,7 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP
return;
}
const newSelectedParticipants = (newGroupDraft.participants ?? []).filter((participant) => participant?.login !== option.login);
Report.setGroupDraft({participants: newSelectedParticipants});
setGroupDraft({participants: newSelectedParticipants});
},
[newGroupDraft],
);
Expand All @@ -104,7 +95,7 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP
}

const logins: string[] = (newGroupDraft.participants ?? []).map((participant) => participant.login).filter((login): login is string => !!login);
Report.navigateToAndOpenReport(logins, true, undefined, newGroupDraft.reportName ?? '', newGroupDraft.avatarUri ?? '', avatarFile, optimisticReportID.current, true);
navigateToAndOpenReport(logins, true, undefined, newGroupDraft.reportName ?? '', newGroupDraft.avatarUri ?? '', avatarFile, optimisticReportID.current, true);
}, [newGroupDraft, avatarFile]);

const stashedLocalAvatarImage = newGroupDraft?.avatarUri;
Expand All @@ -120,12 +111,12 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP

const onFailure = () => {
setAvatarFile(undefined);
Report.setGroupDraft({avatarUri: null, avatarFileName: null, avatarFileType: null});
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 ?? '');
readFileAsync(stashedLocalAvatarImage, newGroupDraft?.avatarFileName ?? '', onSuccess, onFailure, newGroupDraft?.avatarFileType ?? '');

// we only need to run this when the component re-mounted
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
Expand All @@ -141,14 +132,14 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP
<AvatarWithImagePicker
isUsingDefaultAvatar={!stashedLocalAvatarImage}
// eslint-disable-next-line react-compiler/react-compiler
source={stashedLocalAvatarImage ?? ReportUtils.getDefaultGroupAvatar(optimisticReportID.current)}
source={stashedLocalAvatarImage ?? getDefaultGroupAvatar(optimisticReportID.current)}
onImageSelected={(image) => {
setAvatarFile(image);
Report.setGroupDraft({avatarUri: image.uri ?? '', avatarFileName: image.name ?? '', avatarFileType: image.type});
setGroupDraft({avatarUri: image.uri ?? '', avatarFileName: image.name ?? '', avatarFileType: image.type});
}}
onImageRemoved={() => {
setAvatarFile(undefined);
Report.setGroupDraft({avatarUri: null, avatarFileName: null, avatarFileType: null});
setGroupDraft({avatarUri: null, avatarFileName: null, avatarFileType: null});
}}
size={CONST.AVATAR_SIZE.XLARGE}
avatarStyle={styles.avatarXLarge}
Expand All @@ -164,7 +155,7 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP
onPress={navigateToEditChatName}
shouldShowRightIcon
shouldCheckActionAllowedOnPress={false}
description={translate('groupConfirmPage.groupName')}
description={translate('newRoomPage.groupName')}
wrapperStyle={[styles.ph4]}
/>
<View style={[styles.flex1, styles.mt3]}>
Expand All @@ -185,11 +176,4 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP

NewChatConfirmPage.displayName = 'NewChatConfirmPage';

export default withOnyx<NewChatConfirmPageProps, NewChatConfirmPageOnyxProps>({
newGroupDraft: {
key: ONYXKEYS.NEW_GROUP_CHAT_DRAFT,
},
allPersonalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
})(NewChatConfirmPage);
export default NewChatConfirmPage;
4 changes: 2 additions & 2 deletions src/pages/ReportDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,11 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta
? chatRoomSubtitle
: `${translate('threads.in')} ${chatRoomSubtitle}`;

let roomDescription;
let roomDescription: string | undefined;
if (caseID === CASES.MONEY_REQUEST) {
roomDescription = translate('common.name');
} else if (isGroupChat) {
roomDescription = translate('groupConfirmPage.groupName');
roomDescription = translate('newRoomPage.groupName');
} else {
roomDescription = translate('newRoomPage.roomName');
}
Expand Down
Loading