From 2477045225a704607379d3f98c4f7b9e68a819fe Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 1 Nov 2023 18:32:36 +0700 Subject: [PATCH 1/8] fix: Start Chat - Invalid red dot briefly appears by closing 'room' tab when there's no prior action --- src/CONST.ts | 9 +++++++++ src/components/Form.js | 8 ++++++++ src/components/Form/FormProvider.js | 5 +++++ src/components/HeaderWithBackButton/index.js | 1 + src/components/RoomNameInput/index.js | 2 +- src/components/RoomNameInput/index.native.js | 2 +- src/libs/Navigation/AppNavigator/Navigators/Overlay.js | 2 ++ 7 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 155e50a35cde..fbdf75514325 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2809,6 +2809,15 @@ const CONST = { * The count of characters we'll allow the user to type after reaching SEARCH_MAX_LENGTH in an input. */ ADDITIONAL_ALLOWED_CHARACTERS: 20, + + /** + * native IDs for close buttons in Overlay component + */ + OVERLAY: { + TOP_BUTTON_NATIVE_ID: 'overLayTopButton', + BOTTOM_BUTTON_NATIVE_ID: 'overLayBottomButton', + }, + BACK_BUTTON_NATIVE_ID: 'backButton', } as const; export default CONST; diff --git a/src/components/Form.js b/src/components/Form.js index 4d3acf754715..0e109f092ec4 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -353,6 +353,14 @@ function Form(props) { // the user are focusing a TextInput and proceeds to toggle a CheckBox in // web and mobile web platforms. setTimeout(() => { + const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id'); + console.log('duke event ', event); + if ( + relatedTargetId && + _.includes([CONST.OVERLAY.BOTTOM_BUTTON_NATIVE_ID, CONST.OVERLAY.TOP_BUTTON_NATIVE_ID, CONST.BACK_BUTTON_NATIVE_ID], relatedTargetId) + ) { + return; + } setTouchedInput(inputID); if (props.shouldValidateOnBlur) { onValidate(inputValues, !hasServerError); diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js index 85408323c9f2..3255bbbad6ef 100644 --- a/src/components/Form/FormProvider.js +++ b/src/components/Form/FormProvider.js @@ -281,6 +281,11 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC // the user is focusing a TextInput and proceeds to toggle a CheckBox in // web and mobile web platforms. setTimeout(() => { + const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id'); + console.warn('duke native event', event); + if (relatedTargetId && _.includes([CONST.OVERLAY.BOTTOM_BUTTON_NATIVE_ID, CONST.OVERLAY.TOP_BUTTON_NATIVE_ID, CONST.BACK_BUTTON_NATIVE_ID], relatedTargetId)) { + return; + } setTouchedInput(inputID); if (shouldValidateOnBlur) { onValidate(inputValues, !hasServerError); diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js index 67e8790560dc..4a03dce10001 100755 --- a/src/components/HeaderWithBackButton/index.js +++ b/src/components/HeaderWithBackButton/index.js @@ -78,6 +78,7 @@ function HeaderWithBackButton({ style={[styles.touchableButtonImage]} accessibilityRole="button" accessibilityLabel={translate('common.back')} + nativeID={CONST.BACK_BUTTON_NATIVE_ID} > setSelection(event.nativeEvent.selection)} errorText={errorText} autoCapitalize="none" - onBlur={() => isFocused && onBlur()} + onBlur={(event) => isFocused && onBlur(event)} shouldDelayFocus={shouldDelayFocus} autoFocus={isFocused && autoFocus} maxLength={CONST.REPORT.MAX_ROOM_NAME_LENGTH} diff --git a/src/components/RoomNameInput/index.native.js b/src/components/RoomNameInput/index.native.js index d9b592b1537d..19a9c6fdb938 100644 --- a/src/components/RoomNameInput/index.native.js +++ b/src/components/RoomNameInput/index.native.js @@ -41,7 +41,7 @@ function RoomNameInput({isFocused, autoFocus, disabled, errorText, forwardedRef, errorText={errorText} maxLength={CONST.REPORT.MAX_ROOM_NAME_LENGTH} keyboardType={keyboardType} // this is a bit hacky solution to a RN issue https://github.com/facebook/react-native/issues/27449 - onBlur={() => isFocused && onBlur()} + onBlur={(event) => isFocused && onBlur(event)} autoFocus={isFocused && autoFocus} autoCapitalize="none" shouldDelayFocus={shouldDelayFocus} diff --git a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js b/src/libs/Navigation/AppNavigator/Navigators/Overlay.js index a36f98076d22..f256cd41a002 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js +++ b/src/libs/Navigation/AppNavigator/Navigators/Overlay.js @@ -28,6 +28,7 @@ function Overlay(props) { onPress={props.onPress} accessibilityLabel={translate('common.close')} accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON} + nativeID={CONST.OVERLAY.TOP_BUTTON_NATIVE_ID} /> From 59b50e4e90615c168572ce297762e23c1030e438 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:11:54 +0100 Subject: [PATCH 2/8] sort tags alphabetically by name --- src/libs/OptionsListUtils.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 5cd04375ce62..023c52f576e9 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -744,6 +744,21 @@ function sortCategories(categories) { return flatHierarchy(hierarchy); } +/** + * Sorts tags alphabetically by name. + * + * @param {Object} tags + * @returns {Array} + */ +function sortTags(tags) { + const sortedTags = _.chain(tags) + .values() + .sortBy((tag) => tag.name) + .value(); + + return sortedTags; +} + /** * Builds the options for the category tree hierarchy via indents * @@ -934,7 +949,8 @@ function getTagsOptions(tags) { */ function getTagListSections(tags, recentlyUsedTags, selectedOptions, searchInputValue, maxRecentReportsToShow) { const tagSections = []; - const enabledTags = _.filter(tags, (tag) => tag.enabled); + const sortedTags = sortTags(tags); + const enabledTags = _.filter(sortedTags, (tag) => tag.enabled); const numberOfTags = _.size(enabledTags); let indexOffset = 0; @@ -1747,6 +1763,7 @@ export { getEnabledCategoriesCount, hasEnabledOptions, sortCategories, + sortTags, getCategoryOptionTree, formatMemberForList, formatSectionsFromSearchTerm, From ce828d2d46e0388c5c2a91bca61eb5b359cc6280 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:43:11 +0100 Subject: [PATCH 3/8] fix failing test --- tests/unit/OptionsListUtilsTest.js | 46 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 7f8fae8e3812..dff19baabd3d 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -1077,14 +1077,8 @@ describe('OptionsListUtils', () => { title: '', shouldShow: false, indexOffset: 0, + // data sorted alphabetically by name data: [ - { - text: 'Medical', - keyForList: 'Medical', - searchText: 'Medical', - tooltipText: 'Medical', - isDisabled: false, - }, { text: 'Accounting', keyForList: 'Accounting', @@ -1099,6 +1093,13 @@ describe('OptionsListUtils', () => { tooltipText: 'HR', isDisabled: false, }, + { + text: 'Medical', + keyForList: 'Medical', + searchText: 'Medical', + tooltipText: 'Medical', + isDisabled: false, + }, ], }, ]; @@ -1205,6 +1206,7 @@ describe('OptionsListUtils', () => { title: 'All', shouldShow: true, indexOffset: 2, + // data sorted alphabetically by name data: [ { text: 'Accounting', @@ -1214,10 +1216,17 @@ describe('OptionsListUtils', () => { isDisabled: false, }, { - text: 'HR', - keyForList: 'HR', - searchText: 'HR', - tooltipText: 'HR', + text: 'Benefits', + keyForList: 'Benefits', + searchText: 'Benefits', + tooltipText: 'Benefits', + isDisabled: false, + }, + { + text: 'Cleaning', + keyForList: 'Cleaning', + searchText: 'Cleaning', + tooltipText: 'Cleaning', isDisabled: false, }, { @@ -1228,10 +1237,10 @@ describe('OptionsListUtils', () => { isDisabled: false, }, { - text: 'Cleaning', - keyForList: 'Cleaning', - searchText: 'Cleaning', - tooltipText: 'Cleaning', + text: 'HR', + keyForList: 'HR', + searchText: 'HR', + tooltipText: 'HR', isDisabled: false, }, { @@ -1248,13 +1257,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Taxes', isDisabled: false, }, - { - text: 'Benefits', - keyForList: 'Benefits', - searchText: 'Benefits', - tooltipText: 'Benefits', - isDisabled: false, - }, ], }, ]; From b35b74b8f7f52d8106445910cbd2369bf4f44c0a Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 10 Nov 2023 17:31:42 +0700 Subject: [PATCH 4/8] fix: cannot navigate to address page using deeplink --- src/libs/actions/Report.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index a10e7e01da03..fa2861e43363 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -20,6 +20,7 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as Pusher from '@libs/Pusher/pusher'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import SidebarUtils from '@libs/SidebarUtils'; import * as UserUtils from '@libs/UserUtils'; import Visibility from '@libs/Visibility'; import CONFIG from '@src/CONFIG'; @@ -1999,7 +2000,7 @@ function openReportFromDeepLink(url, isAuthenticated) { // Navigate to the report after sign-in/sign-up. InteractionManager.runAfterInteractions(() => { - Session.waitForUserSignIn().then(() => { + SidebarUtils.isSidebarLoadedReady().then(() => { if (route === ROUTES.CONCIERGE) { navigateToConciergeChat(true); return; From 96c5f71c148dc7dc7b1345dd0730100a287cdba0 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:38:30 +0100 Subject: [PATCH 5/8] remove sortTags function export --- src/libs/OptionsListUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 023c52f576e9..182eafec447f 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -1763,7 +1763,6 @@ export { getEnabledCategoriesCount, hasEnabledOptions, sortCategories, - sortTags, getCategoryOptionTree, formatMemberForList, formatSectionsFromSearchTerm, From 489518b130a9df84e2b2eed78cacc77e12bdc1f0 Mon Sep 17 00:00:00 2001 From: Conor Pendergrast Date: Thu, 16 Nov 2023 11:07:54 +1300 Subject: [PATCH 6/8] Create Profile.md --- .../new-expensify/account-settings/Profile.md | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/articles/new-expensify/account-settings/Profile.md diff --git a/docs/articles/new-expensify/account-settings/Profile.md b/docs/articles/new-expensify/account-settings/Profile.md new file mode 100644 index 000000000000..fa6907ad7dab --- /dev/null +++ b/docs/articles/new-expensify/account-settings/Profile.md @@ -0,0 +1,74 @@ +--- +title: Profile +description: How to manage your Expensify Profile +--- +# Overview +Your Profile in Expensify allows you to: +- set your public profile pic +- set a display name +- manage your contact methods +- set your pronouns +- set your timezone +- store your personal details (for travel and payment purposes) + +# How to set your profile pic + +To set or update your profile pic: +1. Go to **Settings > Profile** +2. Tap on the default or your existing profile pic, +3. You can either either upload (to set a new profile pic), remove or view your profile pic + +Your profile pic is visible to all Expensify users. + +# How to set a display name + +To set or update your display name: +1. Go to **Settings > Profile** +2. Tap on **Display name** +3. Set a first name and a last name, then **Save** + +Your display name is public to all Expensify users. + +# How to add or remove a contact methods (email address and phone number) + +Your contact methods allow people to contact you, and allow you to forward receipts to receipts@expensify.com from multiple email addresses. + +To manage your contact methods: +1. Go to **Settings > Profile** +2. Tap on **Contact method** +3. Tap **New contact method** to add a new email or phone number + +Your default contact method (email address or phone number) will be visible to "known" users, with whom you have interacted or are part of your team. + +To change the email address or phone number that's displayed on your Expensify account, add a new contact method, then tap on that email address and tap **Set as default**. + +# How to set your pronouns + +To set your pronouns: +1. Go to **Settings > Profile** +2. Tap on **Pronouns** +3. Search for your preferred pronouns, then tap on your choice + +Your pronouns will be visible to "known" users, with whom you have interacted or are part of your team. + +# How to set your timezone + +Your timezone is automatically set using an estimation based on your IP address. + +To set your timezone manually: +1. Go to **Settings > Profile** +2. Tap on **Timezone** +3. Disable **Automatically determine your location** +4. Tap on **Timezone** +5. Search for your preferred timezone, then tap on your choice + +Your timezone will be visible to "known" users, with whom you have interacted or are part of your team. + +# How to store your personal details (for travel and payment purposes) + +Your personal details can be used in Expensify for travel and payment purposes. These will not be shared with any other Expensify user. + +To set your timezone manually: +1. Go to **Settings > Profile** +2. Tap on **Personal details** +3. Tap on **Legal name**, **Date of birth**, and **Address** to set your personal details From 850b2d94492672d858ea4b83b4672abfa50df22f Mon Sep 17 00:00:00 2001 From: Conor Pendergrast Date: Fri, 17 Nov 2023 11:39:25 +1300 Subject: [PATCH 7/8] Update Profile.md --- .../new-expensify/account-settings/Profile.md | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/docs/articles/new-expensify/account-settings/Profile.md b/docs/articles/new-expensify/account-settings/Profile.md index fa6907ad7dab..908cf39c7ac6 100644 --- a/docs/articles/new-expensify/account-settings/Profile.md +++ b/docs/articles/new-expensify/account-settings/Profile.md @@ -4,21 +4,22 @@ description: How to manage your Expensify Profile --- # Overview Your Profile in Expensify allows you to: -- set your public profile pic -- set a display name -- manage your contact methods -- set your pronouns -- set your timezone -- store your personal details (for travel and payment purposes) +- Set your public profile photo +- Set a display name +- Manage your contact methods +- Communicate your current status +- Set your pronouns +- Configure your timezone +- Store your personal details (for travel and payment purposes) -# How to set your profile pic +# How to set your public profile photo -To set or update your profile pic: +To set or update your profile photo: 1. Go to **Settings > Profile** -2. Tap on the default or your existing profile pic, -3. You can either either upload (to set a new profile pic), remove or view your profile pic +2. Tap on the default or your existing profile photo, +3. You can either either upload (to set a new profile photo), remove or view your profile photo -Your profile pic is visible to all Expensify users. +Your profile photo is visible to all Expensify users. # How to set a display name @@ -29,9 +30,9 @@ To set or update your display name: Your display name is public to all Expensify users. -# How to add or remove a contact methods (email address and phone number) +# How to add or remove contact methods (email address and phone number) -Your contact methods allow people to contact you, and allow you to forward receipts to receipts@expensify.com from multiple email addresses. +Your contact methods allow people to contact you (using your email address or phone number), and allow you to forward receipts to receipts@expensify.com from multiple email addresses. To manage your contact methods: 1. Go to **Settings > Profile** @@ -42,6 +43,23 @@ Your default contact method (email address or phone number) will be visible to " To change the email address or phone number that's displayed on your Expensify account, add a new contact method, then tap on that email address and tap **Set as default**. +# How to communicate your current status + +You can use your status emoji to communicate your mood, focus or current activity. You can optionally add a status message too! + +To set your status emoji and status message: +1. Go to **Settings > Profile** +2. Tap on **Status** then **Status** +3. Choose a status emoji, and optionally set a status message +4. Tap on **Save** + +Your status emoji will be visible next to your name in Expensify, and your status emoji and status message will appear in your profile (which is public to all Expensify users). On a computer, your status message will also be visible by hovering your mouse over your name. + +You can also remove your current status: +1. Go to **Settings > Profile** +2. Tap on **Status** +3. Tap on **Clear status** + # How to set your pronouns To set your pronouns: @@ -51,7 +69,7 @@ To set your pronouns: Your pronouns will be visible to "known" users, with whom you have interacted or are part of your team. -# How to set your timezone +# How to configure your timezone Your timezone is automatically set using an estimation based on your IP address. From 4d112cf874f795f45a910c01559100eb5fa97873 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 17 Nov 2023 22:38:06 +0700 Subject: [PATCH 8/8] merge main --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 1c72c0a9156a..55beabb8e85e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2887,7 +2887,7 @@ const CONST = { TOP_BUTTON_NATIVE_ID: 'overLayTopButton', BOTTOM_BUTTON_NATIVE_ID: 'overLayBottomButton', }, - + BACK_BUTTON_NATIVE_ID: 'backButton', REFERRAL_PROGRAM: { CONTENT_TYPES: {