From 6590db4e213d998e3de3b71fc746a64a61422498 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 19 Mar 2024 18:32:39 +0700 Subject: [PATCH 001/366] fix create block send message view --- src/ONYXKEYS.ts | 4 ++++ src/components/BlockedReportFooter.tsx | 23 +++++++++++++++++++++++ src/pages/home/report/ReportFooter.tsx | 12 +++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/components/BlockedReportFooter.tsx diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index d7f3104cd8b4..a335cb6f6c7c 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -113,6 +113,9 @@ const ONYXKEYS = { /** Contains the users's block expiration (if they have one) */ NVP_BLOCKED_FROM_CONCIERGE: 'private_blockedFromConcierge', + /** Whether the user is blocked from chat */ + NVP_BLOCKED_FROM_CHAT: 'nvp_privateBlockedFromChat', + /** A unique identifier that each user has that's used to send notifications */ NVP_PRIVATE_PUSH_NOTIFICATION_ID: 'private_pushNotificationID', @@ -533,6 +536,7 @@ type OnyxValuesMapping = { [ONYXKEYS.BETAS]: OnyxTypes.Beta[]; [ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf; [ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE]: OnyxTypes.BlockedFromConcierge; + [ONYXKEYS.NVP_BLOCKED_FROM_CHAT]: boolean; [ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string; [ONYXKEYS.NVP_TRY_FOCUS_MODE]: boolean; [ONYXKEYS.NVP_HOLD_USE_EXPLAINED]: boolean; diff --git a/src/components/BlockedReportFooter.tsx b/src/components/BlockedReportFooter.tsx new file mode 100644 index 000000000000..b945bfd6f927 --- /dev/null +++ b/src/components/BlockedReportFooter.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Banner from './Banner'; + +function ArchivedReportFooter() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const text = 'Note: You have been banned from communicating in this channel'; + + return ( + + ); +} + +ArchivedReportFooter.displayName = 'ArchivedReportFooter'; + +export default ArchivedReportFooter; diff --git a/src/pages/home/report/ReportFooter.tsx b/src/pages/home/report/ReportFooter.tsx index 3a787e1dbd0f..d1d35195fc09 100644 --- a/src/pages/home/report/ReportFooter.tsx +++ b/src/pages/home/report/ReportFooter.tsx @@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import AnonymousReportFooter from '@components/AnonymousReportFooter'; import ArchivedReportFooter from '@components/ArchivedReportFooter'; +import BlockedReportFooter from '@components/BlockedReportFooter'; import OfflineIndicator from '@components/OfflineIndicator'; import {usePersonalDetails} from '@components/OnyxProvider'; import SwipeableView from '@components/SwipeableView'; @@ -28,6 +29,9 @@ type ReportFooterOnyxProps = { /** Session info for the currently logged in user. */ session: OnyxEntry; + + /** Whether user is blocked from chat. */ + blockedFromChat: OnyxEntry; }; type ReportFooterProps = ReportFooterOnyxProps & { @@ -63,6 +67,7 @@ function ReportFooter({ isReportReadyForDisplay = true, listHeight = 0, isComposerFullSize = false, + blockedFromChat, }: ReportFooterProps) { const styles = useThemeStyles(); const {isOffline} = useNetwork(); @@ -72,7 +77,7 @@ function ReportFooter({ const isAnonymousUser = session?.authTokenType === CONST.AUTH_TOKEN_TYPES.ANONYMOUS; const isSmallSizeLayout = windowWidth - (isSmallScreenWidth ? 0 : variables.sideBarWidth) < variables.anonymousReportFooterBreakpoint; - const hideComposer = !ReportUtils.canUserPerformWriteAction(report); + const hideComposer = !ReportUtils.canUserPerformWriteAction(report) || blockedFromChat; const allPersonalDetails = usePersonalDetails(); @@ -128,6 +133,7 @@ function ReportFooter({ /> )} {isArchivedRoom && } + {!isArchivedRoom && blockedFromChat && } {!isSmallScreenWidth && {hideComposer && }} )} @@ -163,6 +169,10 @@ export default withOnyx({ session: { key: ONYXKEYS.SESSION, }, + blockedFromChat: { + key: ONYXKEYS.NVP_BLOCKED_FROM_CHAT, + + }, })( memo( ReportFooter, From 2812c29ae8e72466f67937600a0e5bee651a5e5c Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Thu, 21 Mar 2024 04:43:10 +0530 Subject: [PATCH 002/366] fix: Fix scrollable elements in Policy pages. Signed-off-by: Krishna Gupta --- .../SelectionList/BaseSelectionList.tsx | 71 +++++++++++-------- src/components/SelectionList/types.ts | 2 + .../categories/WorkspaceCategoriesPage.tsx | 20 ++++-- 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 015fd284c0b4..94287109386d 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -69,6 +69,7 @@ function BaseSelectionList( listHeaderWrapperStyle, isRowMultilineSupported = false, textInputRef, + ListHeaderComponent, }: BaseSelectionListProps, ref: ForwardedRef, ) { @@ -339,6 +340,39 @@ function BaseSelectionList( ); }; + const header = () => ( + <> + {!headerMessage && canSelectMultiple && shouldShowSelectAll && ( + + + + {!customListHeader && ( + e.preventDefault() : undefined} + > + {translate('workspace.people.selectAll')} + + )} + + {customListHeader} + + )} + {!headerMessage && !canSelectMultiple && customListHeader} + + ); + const scrollToFocusedIndexOnFirstRender = useCallback( (nativeEvent: LayoutChangeEvent) => { if (shouldUseDynamicMaxToRenderPerBatch) { @@ -523,34 +557,7 @@ function BaseSelectionList( ) : ( <> - {!headerMessage && canSelectMultiple && shouldShowSelectAll && ( - - - - {!customListHeader && ( - e.preventDefault() : undefined} - > - {translate('workspace.people.selectAll')} - - )} - - {customListHeader} - - )} - {!headerMessage && !canSelectMultiple && customListHeader} + {!ListHeaderComponent && header()} ( onLayout={onSectionListLayout} style={(!maxToRenderPerBatch || isInitialSectionListRender) && styles.opacity0} ListFooterComponent={ShowMoreButtonInstance} + ListHeaderComponent={ + ListHeaderComponent && ( + <> + {ListHeaderComponent} + {header()} + + ) + } /> {children} diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index fac78ee786a0..504a715c0181 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -250,6 +250,8 @@ type BaseSelectionListProps = Partial & { /** Custom content to display in the header */ headerContent?: ReactNode; + ListHeaderComponent?: React.JSX.Element | null; + /** Custom content to display in the footer */ footerContent?: ReactNode; diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index f3456c3875f5..55bc5ab4520c 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -261,6 +261,15 @@ function WorkspaceCategoriesPage({policy, policyCategories, route}: WorkspaceCat const shouldShowEmptyState = !categoryList.some((category) => category.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) && !isLoading; + const getSmallWidthHeaderComponent = () => ( + <> + {getHeaderButtons()} + + {translate('workspace.categories.subtitle')} + + + ); + return ( @@ -291,10 +300,12 @@ function WorkspaceCategoriesPage({policy, policyCategories, route}: WorkspaceCat cancelText={translate('common.cancel')} danger /> - {isSmallScreenWidth && {getHeaderButtons()}} - - {translate('workspace.categories.subtitle')} - + {/* {isSmallScreenWidth && {getHeaderButtons()}} */} + {!isSmallScreenWidth && ( + + {translate('workspace.categories.subtitle')} + + )} {isLoading && ( )} From fa5e9e83f2a45498d8294683e206d618199aa135 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Fri, 22 Mar 2024 02:12:29 +0700 Subject: [PATCH 003/366] fix add translations --- src/components/BlockedReportFooter.tsx | 8 ++++---- src/languages/en.ts | 1 + src/languages/es.ts | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/BlockedReportFooter.tsx b/src/components/BlockedReportFooter.tsx index b945bfd6f927..b97c7dbc4f5e 100644 --- a/src/components/BlockedReportFooter.tsx +++ b/src/components/BlockedReportFooter.tsx @@ -3,11 +3,11 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Banner from './Banner'; -function ArchivedReportFooter() { +function BlockedReportFooter() { const styles = useThemeStyles(); const {translate} = useLocalize(); - const text = 'Note: You have been banned from communicating in this channel'; + const text = translate('youHaveBeenBanned'); return ( Date: Fri, 22 Mar 2024 02:24:40 +0700 Subject: [PATCH 004/366] fix lint --- src/pages/home/report/ReportFooter.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ReportFooter.tsx b/src/pages/home/report/ReportFooter.tsx index d1d35195fc09..e5a3345c1a63 100644 --- a/src/pages/home/report/ReportFooter.tsx +++ b/src/pages/home/report/ReportFooter.tsx @@ -171,7 +171,6 @@ export default withOnyx({ }, blockedFromChat: { key: ONYXKEYS.NVP_BLOCKED_FROM_CHAT, - }, })( memo( From 20912d7fde785437a66b90b9cede7bae9e775290 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Tue, 2 Apr 2024 11:15:37 +0530 Subject: [PATCH 005/366] feat: sticky header component selection list. Signed-off-by: Krishna Gupta --- .../SelectionList/BaseSelectionList.tsx | 22 +++++++++---------- src/styles/index.ts | 4 ++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 0d8c8d06bf68..619cb2ce40ab 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -301,7 +301,7 @@ function BaseSelectionList( }; const renderSectionHeader = ({section}: {section: SectionListDataType}) => { - if (!section.title || isEmptyObject(section.data)) { + if (!section.title || isEmptyObject(section.data) || ListHeaderComponent) { return null; } @@ -345,7 +345,7 @@ function BaseSelectionList( const header = () => ( <> {!headerMessage && canSelectMultiple && shouldShowSelectAll && ( - + ( ( + <> + {renderSectionHeader(arg)} + {ListHeaderComponent && header()} + + )} renderItem={renderItem} getItemLayout={getItemLayout} onScroll={onScroll} @@ -582,14 +586,8 @@ function BaseSelectionList( onLayout={onSectionListLayout} style={(!maxToRenderPerBatch || isInitialSectionListRender) && styles.opacity0} ListFooterComponent={ShowMoreButtonInstance} - ListHeaderComponent={ - ListHeaderComponent && ( - <> - {ListHeaderComponent} - {header()} - - ) - } + ListHeaderComponent={ListHeaderComponent && ListHeaderComponent} + stickySectionHeadersEnabled={!!ListHeaderComponent && true} /> {children} diff --git a/src/styles/index.ts b/src/styles/index.ts index a736bc537fa6..6f4383fbbaff 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4338,6 +4338,10 @@ const styles = (theme: ThemeColors) => borderRadius: 8, }, + selectionListStickyHeader: { + backgroundColor: theme.dropUIBG, + }, + draggableTopBar: { height: 30, width: '100%', From 950c69d0d94657b3cf103e778a49ff1f5b8d67c7 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Tue, 2 Apr 2024 11:55:57 +0530 Subject: [PATCH 006/366] feat: make header buttons scroll on small screen width in policy pages. Signed-off-by: Krishna Gupta --- src/pages/workspace/WorkspaceMembersPage.tsx | 11 +++++++++-- .../distanceRates/PolicyDistanceRatesPage.tsx | 19 +++++++++++++++---- .../workspace/tags/WorkspaceTagsPage.tsx | 19 +++++++++++++++---- .../workspace/taxes/WorkspaceTaxesPage.tsx | 19 +++++++++++++++---- 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 7b77f6b60ede..8c93fd9fe455 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -563,7 +563,6 @@ function WorkspaceMembersPage({ > {!isSmallScreenWidth && getHeaderButtons()} - {isSmallScreenWidth && {getHeaderButtons()}} toggleUser(item.accountID)} onSelectAll={() => toggleAllUsers(data)} @@ -600,6 +599,14 @@ function WorkspaceMembersPage({ shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} textInputRef={textInputRef} customListHeader={getCustomListHeader()} + ListHeaderComponent={ + isSmallScreenWidth ? ( + + {getHeaderContent()} + {getHeaderButtons()} + + ) : null + } listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]} /> diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index a5356a8fd05a..6a4fdbcf6e17 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -267,6 +267,15 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) ); + const getSmallWidthHeaderComponent = () => ( + <> + {headerButtons} + + {translate('workspace.distanceRates.centrallyManage')} + + + ); + return ( @@ -287,10 +296,11 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) > {!isSmallScreenWidth && headerButtons} - {isSmallScreenWidth && {headerButtons}} - - {translate('workspace.distanceRates.centrallyManage')} - + {!isSmallScreenWidth && ( + + {translate('workspace.distanceRates.centrallyManage')} + + )} {isLoading && ( )} diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 53376c05878f..072082eda916 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -256,6 +256,15 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { ); }; + const getSmallWidthHeaderComponent = () => ( + <> + {getHeaderButtons()} + + {translate('workspace.tags.subtitle')} + + + ); + return ( @@ -287,10 +296,11 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { cancelText={translate('common.cancel')} danger /> - {isSmallScreenWidth && {getHeaderButtons()}} - - {translate('workspace.tags.subtitle')} - + {!isSmallScreenWidth && ( + + {translate('workspace.tags.subtitle')} + + )} {isLoading && ( Policy.clearPolicyTagErrors(route.params.policyID, item.value)} /> diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index 4f8782dcdf3f..b46d5564aedc 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -234,6 +234,15 @@ function WorkspaceTaxesPage({ /> ); + const getSmallWidthHeaderComponent = () => ( + <> + {headerButtons} + + {translate('workspace.taxes.subtitle')} + + + ); + return ( @@ -255,11 +264,12 @@ function WorkspaceTaxesPage({ {!isSmallScreenWidth && headerButtons} - {isSmallScreenWidth && {headerButtons}} + {!isSmallScreenWidth && ( + + {translate('workspace.taxes.subtitle')} + + )} - - {translate('workspace.taxes.subtitle')} - {isLoading && ( (item.keyForList ? clearTaxRateError(policyID, item.keyForList, item.pendingAction) : undefined)} /> From d46dc8eaa13d4ba70835cb36a5ea041d7fd1b8d4 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Tue, 2 Apr 2024 12:34:49 +0530 Subject: [PATCH 007/366] fix header bg color. Signed-off-by: Krishna Gupta --- src/styles/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index 6f4383fbbaff..1629840a6bd0 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4339,7 +4339,7 @@ const styles = (theme: ThemeColors) => }, selectionListStickyHeader: { - backgroundColor: theme.dropUIBG, + backgroundColor: theme.appBG, }, draggableTopBar: { From c6111876d7a99b59db83cd2e8fe48403c2708b91 Mon Sep 17 00:00:00 2001 From: Monil Bhavsar Date: Mon, 15 Apr 2024 19:43:16 +0530 Subject: [PATCH 008/366] Pass taxCode and taxAmount params for split bill request --- src/libs/API/parameters/SplitBillParams.ts | 2 ++ src/libs/actions/IOU.ts | 13 ++++++++++++- .../iou/request/step/IOURequestStepConfirmation.tsx | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/libs/API/parameters/SplitBillParams.ts b/src/libs/API/parameters/SplitBillParams.ts index 310923093d5e..0f121da76025 100644 --- a/src/libs/API/parameters/SplitBillParams.ts +++ b/src/libs/API/parameters/SplitBillParams.ts @@ -14,6 +14,8 @@ type SplitBillParams = { createdReportActionID?: string; policyID: string | undefined; chatType: string | undefined; + taxCode: string; + taxAmount: number; }; export default SplitBillParams; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index cd0264ddb6ea..8601b37b979a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2543,6 +2543,7 @@ function createSplitsAndOnyxData( existingSplitChatReportID = '', billable = false, iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL, + taxAmount: number, ): SplitsAndOnyxData { const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); @@ -2709,7 +2710,8 @@ function createSplitsAndOnyxData( // Loop through participants creating individual chats, iouReports and reportActionIDs as needed const splitAmount = IOUUtils.calculateAmount(participants.length, amount, currency, false); - const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true)}]; + const splitTaxAmount = IOUUtils.calculateAmount(participants.length, taxAmount, currency, false); + const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true), taxAmount: IOUUtils.calculateAmount(participants.length, taxAmount, currency, true)}]; const hasMultipleParticipants = participants.length > 1; participants.forEach((participant) => { @@ -2863,6 +2865,7 @@ function createSplitsAndOnyxData( reportPreviewReportActionID: oneOnOneReportPreviewAction.reportActionID, transactionThreadReportID: optimisticTransactionThread.reportID, createdReportActionIDForThread: optimisticCreatedActionForTransactionThread.reportActionID, + taxAmount: splitTaxAmount, }; splits.push(individualSplit); @@ -2904,6 +2907,8 @@ type SplitBillActionsParams = { billable?: boolean; iouRequestType?: IOURequestType; existingSplitChatReportID?: string; + taxCode?: string; + taxAmount?: number; }; /** @@ -2924,7 +2929,10 @@ function splitBill({ billable = false, iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, existingSplitChatReportID = '', + taxCode = '', + taxAmount = 0, }: SplitBillActionsParams) { + console.debug(taxCode); const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const {splitData, splits, onyxData} = createSplitsAndOnyxData( participants, @@ -2940,6 +2948,7 @@ function splitBill({ existingSplitChatReportID, billable, iouRequestType, + taxAmount, ); const parameters: SplitBillParams = { @@ -2958,6 +2967,8 @@ function splitBill({ createdReportActionID: splitData.createdReportActionID, policyID: splitData.policyID, chatType: splitData.chatType, + taxCode, + taxAmount, }; API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 83f831708799..1e1ab4da3092 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -307,6 +307,8 @@ function IOURequestStepConfirmation({ existingSplitChatReportID: report?.reportID, billable: transaction.billable, iouRequestType: transaction.iouRequestType, + taxCode: transaction.taxCode, + taxAmount: transaction.taxAmount, }); } return; @@ -328,6 +330,8 @@ function IOURequestStepConfirmation({ tag: transaction.tag, billable: !!transaction.billable, iouRequestType: transaction.iouRequestType, + taxCode: transaction.taxCode, + taxAmount: transaction.taxAmount, }); } return; From 1a8bd9efc629eaa27375b7752bdfd1a4507f546d Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Tue, 16 Apr 2024 19:27:49 +0530 Subject: [PATCH 009/366] revert changes in WorkspaceMembersPage & BaseSelectionList. Signed-off-by: Krishna Gupta --- .../SelectionList/BaseSelectionList.tsx | 292 +++++++++--------- src/pages/workspace/WorkspaceMembersPage.tsx | 136 ++++---- 2 files changed, 196 insertions(+), 232 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 1d9a0a64d599..62f098e76228 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -4,7 +4,6 @@ import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import type {LayoutChangeEvent, SectionList as RNSectionList, TextInput as RNTextInput, SectionListRenderItemInfo} from 'react-native'; import {View} from 'react-native'; -import ArrowKeyFocusManager from '@components/ArrowKeyFocusManager'; import Button from '@components/Button'; import Checkbox from '@components/Checkbox'; import FixedFooter from '@components/FixedFooter'; @@ -16,7 +15,9 @@ import ShowMoreButton from '@components/ShowMoreButton'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useActiveElementRole from '@hooks/useActiveElementRole'; +import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -56,7 +57,6 @@ function BaseSelectionList( showConfirmButton = false, shouldPreventDefaultFocusOnSelectRow = false, containerStyle, - isKeyboardShown = false, disableKeyboardShortcuts = false, children, shouldStopPropagation = false, @@ -69,7 +69,6 @@ function BaseSelectionList( listHeaderWrapperStyle, isRowMultilineSupported = false, textInputRef, - ListHeaderComponent, headerMessageStyle, shouldHideListOnInitialRender = true, textInputIconLeft, @@ -89,6 +88,7 @@ function BaseSelectionList( const isFocused = useIsFocused(); const [maxToRenderPerBatch, setMaxToRenderPerBatch] = useState(shouldUseDynamicMaxToRenderPerBatch ? 0 : CONST.MAX_TO_RENDER_PER_BATCH.DEFAULT); const [isInitialSectionListRender, setIsInitialSectionListRender] = useState(true); + const {isKeyboardShown} = useKeyboardState(); const [itemsToHighlight, setItemsToHighlight] = useState | null>(null); const itemFocusTimeoutRef = useRef(null); const [currentPage, setCurrentPage] = useState(1); @@ -167,9 +167,6 @@ function BaseSelectionList( }; }, [canSelectMultiple, sections]); - // If `initiallyFocusedOptionKey` is not passed, we fall back to `-1`, to avoid showing the highlight on the first member - const [focusedIndex, setFocusedIndex] = useState(() => flattenedSections.allOptions.findIndex((option) => option.keyForList === initiallyFocusedOptionKey)); - const [slicedSections, ShowMoreButtonInstance] = useMemo(() => { let remainingOptionsLimit = CONST.MAX_OPTIONS_SELECTOR_PAGE_LENGTH * currentPage; const processedSections = getSectionsWithIndexOffset( @@ -226,6 +223,17 @@ function BaseSelectionList( [flattenedSections.allOptions], ); + // If `initiallyFocusedOptionKey` is not passed, we fall back to `-1`, to avoid showing the highlight on the first member + const [focusedIndex, setFocusedIndex] = useArrowKeyFocusManager({ + initialFocusedIndex: flattenedSections.allOptions.findIndex((option) => option.keyForList === initiallyFocusedOptionKey), + maxIndex: flattenedSections.allOptions.length - 1, + isActive: true, + onFocusedIndexChange: (index: number) => { + scrollToIndex(index, true); + }, + isFocused, + }); + /** * Logic to run when a row is selected, either with click/press or keyboard hotkeys. * @@ -305,7 +313,7 @@ function BaseSelectionList( }; const renderSectionHeader = ({section}: {section: SectionListDataType}) => { - if (!section.title || isEmptyObject(section.data) || ListHeaderComponent) { + if (!section.title || isEmptyObject(section.data)) { return null; } @@ -341,43 +349,11 @@ function BaseSelectionList( rightHandSideComponent={rightHandSideComponent} keyForList={item.keyForList ?? ''} isMultilineSupported={isRowMultilineSupported} + onFocus={() => setFocusedIndex(index)} /> ); }; - const header = () => ( - <> - {!headerMessage && canSelectMultiple && shouldShowSelectAll && ( - - - - {!customListHeader && ( - e.preventDefault() : undefined} - > - {translate('workspace.people.selectAll')} - - )} - - {customListHeader} - - )} - {!headerMessage && !canSelectMultiple && customListHeader} - - ); - const scrollToFocusedIndexOnFirstRender = useCallback( (nativeEvent: LayoutChangeEvent) => { if (shouldUseDynamicMaxToRenderPerBatch) { @@ -408,7 +384,7 @@ function BaseSelectionList( setFocusedIndex(newFocusedIndex); scrollToIndex(newFocusedIndex, true); }, - [scrollToIndex], + [scrollToIndex, setFocusedIndex], ); /** Focuses the text input when the component comes into focus and after any navigation animations finish. */ @@ -494,7 +470,7 @@ function BaseSelectionList( setItemsToHighlight(null); }, timeout); }, - [flattenedSections.allOptions, updateAndScrollToFocusedIndex], + [flattenedSections.allOptions, setFocusedIndex, updateAndScrollToFocusedIndex], ); useImperativeHandle(ref, () => ({scrollAndHighlightItem}), [scrollAndHighlightItem]); @@ -526,115 +502,129 @@ function BaseSelectionList( ); return ( - section.data).length - 1} - onFocusedIndexChanged={updateAndScrollToFocusedIndex} - > - - {({safeAreaPaddingBottomStyle}) => ( - - {shouldShowTextInput && ( - - { - innerTextInputRef.current = element as RNTextInput; - - if (!textInputRef) { - return; - } - - if (typeof textInputRef === 'function') { - textInputRef(element as RNTextInput); - } else { - // eslint-disable-next-line no-param-reassign - textInputRef.current = element as RNTextInput; - } - }} - label={textInputLabel} - accessibilityLabel={textInputLabel} - hint={textInputHint} - role={CONST.ROLE.PRESENTATION} - value={textInputValue} - placeholder={textInputPlaceholder} - maxLength={textInputMaxLength} - onChangeText={onChangeText} - inputMode={inputMode} - selectTextOnFocus - spellCheck={false} - iconLeft={textInputIconLeft} - onSubmitEditing={selectFocusedOption} - blurOnSubmit={!!flattenedSections.allOptions.length} - isLoading={isLoadingNewOptions} - testID="selection-list-text-input" - /> - - )} - {/* If we are loading new options we will avoid showing any header message. This is mostly because one of the header messages says there are no options. */} - {/* This is misleading because we might be in the process of loading fresh options from the server. */} - {!isLoadingNewOptions && !!headerMessage && ( - - {headerMessage} - - )} - {!!headerContent && headerContent} - {flattenedSections.allOptions.length === 0 && showLoadingPlaceholder ? ( - - ) : ( - <> - {!ListHeaderComponent && header()} - ( - <> - {renderSectionHeader(arg)} - {ListHeaderComponent && header()} - - )} - renderItem={renderItem} - getItemLayout={getItemLayout} - onScroll={onScroll} - onScrollBeginDrag={onScrollBeginDrag} - keyExtractor={(item, index) => item.keyForList ?? `${index}`} - extraData={focusedIndex} - // the only valid values on the new arch are "white", "black", and "default", other values will cause a crash - indicatorStyle="white" - keyboardShouldPersistTaps="always" - showsVerticalScrollIndicator={showScrollIndicator} - initialNumToRender={12} - maxToRenderPerBatch={maxToRenderPerBatch} - windowSize={5} - viewabilityConfig={{viewAreaCoveragePercentThreshold: 95}} - testID="selection-list" - onLayout={onSectionListLayout} - style={(!maxToRenderPerBatch || (shouldHideListOnInitialRender && isInitialSectionListRender)) && styles.opacity0} - ListFooterComponent={ShowMoreButtonInstance} - ListHeaderComponent={ListHeaderComponent && ListHeaderComponent} - stickySectionHeadersEnabled={!!ListHeaderComponent && true} - /> - {children} - - )} - {showConfirmButton && ( - -