From bc020b18a133a70e9bc2de81ce1b5eb203bfc0a5 Mon Sep 17 00:00:00 2001 From: burczu Date: Fri, 23 Feb 2024 13:23:25 +0100 Subject: [PATCH 01/49] button with dropdown menu refactor --- .../BaseButtonWithDropdownMenu.tsx} | 75 +++---------------- .../PaymentButtonWithDropdownMenu.tsx | 16 ++++ .../ButtonWithDropdownMenu/types.ts | 59 +++++++++++++++ .../MoneyRequestConfirmationList.js | 4 +- ...oraryForRefactorRequestConfirmationList.js | 4 +- src/components/SettlementButton.tsx | 4 +- src/stories/ButtonWithDropdownMenu.stories.js | 2 +- 7 files changed, 91 insertions(+), 73 deletions(-) rename src/components/{ButtonWithDropdownMenu.tsx => ButtonWithDropdownMenu/BaseButtonWithDropdownMenu.tsx} (72%) create mode 100644 src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx create mode 100644 src/components/ButtonWithDropdownMenu/types.ts diff --git a/src/components/ButtonWithDropdownMenu.tsx b/src/components/ButtonWithDropdownMenu/BaseButtonWithDropdownMenu.tsx similarity index 72% rename from src/components/ButtonWithDropdownMenu.tsx rename to src/components/ButtonWithDropdownMenu/BaseButtonWithDropdownMenu.tsx index 9466da601825..6737cf61a2f7 100644 --- a/src/components/ButtonWithDropdownMenu.tsx +++ b/src/components/ButtonWithDropdownMenu/BaseButtonWithDropdownMenu.tsx @@ -1,73 +1,18 @@ -import type {RefObject} from 'react'; import React, {useEffect, useRef, useState} from 'react'; -import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import type {ValueOf} from 'type-fest'; +import Button from '@components/Button'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import PopoverMenu from '@components/PopoverMenu'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import type {AnchorPosition} from '@styles/index'; import CONST from '@src/CONST'; -import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; -import type DeepValueOf from '@src/types/utils/DeepValueOf'; -import type IconAsset from '@src/types/utils/IconAsset'; -import Button from './Button'; -import Icon from './Icon'; -import * as Expensicons from './Icon/Expensicons'; -import PopoverMenu from './PopoverMenu'; +import type {AnchorPosition} from '@src/styles'; +import type {BaseButtonWithDropdownMenuProps} from './types'; -type PaymentType = DeepValueOf; - -type DropdownOption = { - value: PaymentType; - text: string; - icon: IconAsset; - iconWidth?: number; - iconHeight?: number; - iconDescription?: string; -}; - -type ButtonWithDropdownMenuProps = { - /** Text to display for the menu header */ - menuHeaderText?: string; - - /** Callback to execute when the main button is pressed */ - onPress: (event: GestureResponderEvent | KeyboardEvent | undefined, value: PaymentType) => void; - - /** Callback to execute when a dropdown option is selected */ - onOptionSelected?: (option: DropdownOption) => void; - - /** Call the onPress function on main button when Enter key is pressed */ - pressOnEnter?: boolean; - - /** Whether we should show a loading state for the main button */ - isLoading?: boolean; - - /** The size of button size */ - buttonSize: ValueOf; - - /** Should the confirmation button be disabled? */ - isDisabled?: boolean; - - /** Additional styles to add to the component */ - style?: StyleProp; - - /** Menu options to display */ - /** e.g. [{text: 'Pay with Expensify', icon: Wallet}] */ - options: DropdownOption[]; - - /** The anchor alignment of the popover menu */ - anchorAlignment?: AnchorAlignment; - - /* ref for the button */ - buttonRef: RefObject; - - /** The priority to assign the enter key event listener to buttons. 0 is the highest priority. */ - enterKeyEventListenerPriority?: number; -}; - -function ButtonWithDropdownMenu({ +function BaseButtonWithDropdownMenu({ isLoading = false, isDisabled = false, pressOnEnter = false, @@ -83,7 +28,7 @@ function ButtonWithDropdownMenu({ options, onOptionSelected, enterKeyEventListenerPriority = 0, -}: ButtonWithDropdownMenuProps) { +}: BaseButtonWithDropdownMenuProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -198,6 +143,4 @@ function ButtonWithDropdownMenu({ ); } -ButtonWithDropdownMenu.displayName = 'ButtonWithDropdownMenu'; - -export default React.memo(ButtonWithDropdownMenu); +export default BaseButtonWithDropdownMenu; diff --git a/src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx b/src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx new file mode 100644 index 000000000000..fbd258cbc3a9 --- /dev/null +++ b/src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import BaseButtonWithDropdownMenu from './BaseButtonWithDropdownMenu'; +import type {BaseButtonWithDropdownMenuProps, PaymentType} from './types'; + +function PaymentButtonWithDropdownMenu({...props}: BaseButtonWithDropdownMenuProps) { + return ( + + // eslint-disable-next-line react/jsx-props-no-spreading + {...props} + /> + ); +} + +PaymentButtonWithDropdownMenu.displayName = 'PaymentButtonWithDropdownMenu'; + +export default React.memo(PaymentButtonWithDropdownMenu); diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts new file mode 100644 index 000000000000..56841390efb2 --- /dev/null +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -0,0 +1,59 @@ +import type {RefObject} from 'react'; +import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; +import type IconAsset from '@src/types/utils/IconAsset'; + +type PaymentType = DeepValueOf; + +type DropdownOption = { + value: TValueType; + text: string; + icon: IconAsset; + iconWidth?: number; + iconHeight?: number; + iconDescription?: string; +}; + +type BaseButtonWithDropdownMenuProps = { + /** Text to display for the menu header */ + menuHeaderText?: string; + + /** Callback to execute when the main button is pressed */ + onPress: (event: GestureResponderEvent | KeyboardEvent | undefined, value: TValueType) => void; + + /** Callback to execute when a dropdown option is selected */ + onOptionSelected?: (option: DropdownOption) => void; + + /** Call the onPress function on main button when Enter key is pressed */ + pressOnEnter?: boolean; + + /** Whether we should show a loading state for the main button */ + isLoading?: boolean; + + /** The size of button size */ + buttonSize: ValueOf; + + /** Should the confirmation button be disabled? */ + isDisabled?: boolean; + + /** Additional styles to add to the component */ + style?: StyleProp; + + /** Menu options to display */ + /** e.g. [{text: 'Pay with Expensify', icon: Wallet}] */ + options: Array>; + + /** The anchor alignment of the popover menu */ + anchorAlignment?: AnchorAlignment; + + /* ref for the button */ + buttonRef: RefObject; + + /** The priority to assign the enter key event listener to buttons. 0 is the highest priority. */ + enterKeyEventListenerPriority?: number; +}; + +export type {PaymentType, DropdownOption, BaseButtonWithDropdownMenuProps}; diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 2b18ab9bc003..ad4f5bb37b33 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -28,7 +28,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; +import PaymentButtonWithDropdownMenu from './ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu'; import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import FormHelpMessage from './FormHelpMessage'; @@ -548,7 +548,7 @@ function MoneyRequestConfirmationList(props) { enterKeyEventListenerPriority={1} /> ) : ( - confirm(value)} diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index c69b0476f9c7..b9d7dedf10d0 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -28,7 +28,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import Button from './Button'; -import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; +import PaymentButtonWithDropdownMenu from './ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu'; import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import FormHelpMessage from './FormHelpMessage'; @@ -597,7 +597,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ enterKeyEventListenerPriority={1} /> ) : ( - confirm(value)} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 50bfcd4cc8be..2d0b51bbd669 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -18,7 +18,7 @@ import type {LastPaymentMethod, Report} from '@src/types/onyx'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; -import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; +import PaymentButtonWithDropdownMenu from './ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu'; import * as Expensicons from './Icon/Expensicons'; import KYCWall from './KYCWall'; @@ -224,7 +224,7 @@ function SettlementButton({ shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > {(triggerKYCFlow, buttonRef) => ( - Date: Fri, 23 Feb 2024 13:34:49 +0100 Subject: [PATCH 02/49] button with dropdown refactor simplified --- .../PaymentButtonWithDropdownMenu.tsx | 16 ---------------- ...{BaseButtonWithDropdownMenu.tsx => index.tsx} | 10 ++++++---- src/components/ButtonWithDropdownMenu/types.ts | 4 ++-- src/components/MoneyRequestConfirmationList.js | 4 ++-- ...emporaryForRefactorRequestConfirmationList.js | 4 ++-- src/components/SettlementButton.tsx | 5 +++-- src/stories/ButtonWithDropdownMenu.stories.js | 2 +- 7 files changed, 16 insertions(+), 29 deletions(-) delete mode 100644 src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx rename src/components/ButtonWithDropdownMenu/{BaseButtonWithDropdownMenu.tsx => index.tsx} (96%) diff --git a/src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx b/src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx deleted file mode 100644 index fbd258cbc3a9..000000000000 --- a/src/components/ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; -import BaseButtonWithDropdownMenu from './BaseButtonWithDropdownMenu'; -import type {BaseButtonWithDropdownMenuProps, PaymentType} from './types'; - -function PaymentButtonWithDropdownMenu({...props}: BaseButtonWithDropdownMenuProps) { - return ( - - // eslint-disable-next-line react/jsx-props-no-spreading - {...props} - /> - ); -} - -PaymentButtonWithDropdownMenu.displayName = 'PaymentButtonWithDropdownMenu'; - -export default React.memo(PaymentButtonWithDropdownMenu); diff --git a/src/components/ButtonWithDropdownMenu/BaseButtonWithDropdownMenu.tsx b/src/components/ButtonWithDropdownMenu/index.tsx similarity index 96% rename from src/components/ButtonWithDropdownMenu/BaseButtonWithDropdownMenu.tsx rename to src/components/ButtonWithDropdownMenu/index.tsx index 6737cf61a2f7..61c6bbae2cd2 100644 --- a/src/components/ButtonWithDropdownMenu/BaseButtonWithDropdownMenu.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -10,9 +10,9 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import type {AnchorPosition} from '@src/styles'; -import type {BaseButtonWithDropdownMenuProps} from './types'; +import type {ButtonWithDropdownMenuProps} from './types'; -function BaseButtonWithDropdownMenu({ +function ButtonWithDropdownMenu({ isLoading = false, isDisabled = false, pressOnEnter = false, @@ -28,7 +28,7 @@ function BaseButtonWithDropdownMenu({ options, onOptionSelected, enterKeyEventListenerPriority = 0, -}: BaseButtonWithDropdownMenuProps) { +}: ButtonWithDropdownMenuProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -143,4 +143,6 @@ function BaseButtonWithDropdownMenu({ ); } -export default BaseButtonWithDropdownMenu; +ButtonWithDropdownMenu.displayName = 'ButtonWithDropdownMenu'; + +export default ButtonWithDropdownMenu; diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index 56841390efb2..6c1e3d7903ad 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -17,7 +17,7 @@ type DropdownOption = { iconDescription?: string; }; -type BaseButtonWithDropdownMenuProps = { +type ButtonWithDropdownMenuProps = { /** Text to display for the menu header */ menuHeaderText?: string; @@ -56,4 +56,4 @@ type BaseButtonWithDropdownMenuProps = { enterKeyEventListenerPriority?: number; }; -export type {PaymentType, DropdownOption, BaseButtonWithDropdownMenuProps}; +export type {PaymentType, DropdownOption, ButtonWithDropdownMenuProps}; diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index ad4f5bb37b33..2b18ab9bc003 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -28,7 +28,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import PaymentButtonWithDropdownMenu from './ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu'; +import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import FormHelpMessage from './FormHelpMessage'; @@ -548,7 +548,7 @@ function MoneyRequestConfirmationList(props) { enterKeyEventListenerPriority={1} /> ) : ( - confirm(value)} diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index b9d7dedf10d0..c69b0476f9c7 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -28,7 +28,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import Button from './Button'; -import PaymentButtonWithDropdownMenu from './ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu'; +import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import FormHelpMessage from './FormHelpMessage'; @@ -597,7 +597,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ enterKeyEventListenerPriority={1} /> ) : ( - confirm(value)} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 2d0b51bbd669..bba9233baed2 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -18,7 +18,8 @@ import type {LastPaymentMethod, Report} from '@src/types/onyx'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; -import PaymentButtonWithDropdownMenu from './ButtonWithDropdownMenu/PaymentButtonWithDropdownMenu'; +import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; +import type {PaymentType} from './ButtonWithDropdownMenu/types'; import * as Expensicons from './Icon/Expensicons'; import KYCWall from './KYCWall'; @@ -224,7 +225,7 @@ function SettlementButton({ shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > {(triggerKYCFlow, buttonRef) => ( - buttonRef={buttonRef} isDisabled={isDisabled} isLoading={isLoading} diff --git a/src/stories/ButtonWithDropdownMenu.stories.js b/src/stories/ButtonWithDropdownMenu.stories.js index d911483d83a7..b87bdc321d45 100644 --- a/src/stories/ButtonWithDropdownMenu.stories.js +++ b/src/stories/ButtonWithDropdownMenu.stories.js @@ -1,5 +1,5 @@ import React from 'react'; -import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu/BaseButtonWithDropdownMenu'; +import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; /** * We use the Component Story Format for writing stories. Follow the docs here: From 6b016485ac237aa247d78603fe422a4b9cdbbda8 Mon Sep 17 00:00:00 2001 From: burczu Date: Fri, 23 Feb 2024 14:27:54 +0100 Subject: [PATCH 03/49] showing button with dropdown menu when item selected --- assets/images/make-admin.svg | 5 ++ assets/images/make-member.svg | 4 ++ assets/images/remove-members.svg | 5 ++ src/CONST.ts | 5 ++ .../ButtonWithDropdownMenu/types.ts | 6 +- src/components/Icon/Expensicons.ts | 6 ++ src/languages/en.ts | 2 + src/languages/es.ts | 2 + src/pages/workspace/WorkspaceMembersPage.tsx | 71 ++++++++++++++++--- 9 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 assets/images/make-admin.svg create mode 100644 assets/images/make-member.svg create mode 100644 assets/images/remove-members.svg diff --git a/assets/images/make-admin.svg b/assets/images/make-admin.svg new file mode 100644 index 000000000000..619790cc487c --- /dev/null +++ b/assets/images/make-admin.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/make-member.svg b/assets/images/make-member.svg new file mode 100644 index 000000000000..f21b46cc86d0 --- /dev/null +++ b/assets/images/make-member.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/remove-members.svg b/assets/images/remove-members.svg new file mode 100644 index 000000000000..f6b3b3730118 --- /dev/null +++ b/assets/images/remove-members.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/CONST.ts b/src/CONST.ts index 008002a71078..f7c19a36166f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1383,6 +1383,11 @@ const CONST = { }, ID_FAKE: '_FAKE_', EMPTY: 'EMPTY', + MEMBERS_BULK_ACTION_TYPES: { + REMOVE: 'remove', + MAKE_MEMBER: 'makeMember', + MAKE_ADMIN: 'makeAdmin', + }, }, CUSTOM_UNITS: { diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index 6c1e3d7903ad..7d2f6342f002 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -8,6 +8,10 @@ import type IconAsset from '@src/types/utils/IconAsset'; type PaymentType = DeepValueOf; +type WorkspaceMemberBulkActionType = DeepValueOf< + typeof CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.REMOVE | typeof CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_MEMBER | typeof CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_ADMIN +>; + type DropdownOption = { value: TValueType; text: string; @@ -56,4 +60,4 @@ type ButtonWithDropdownMenuProps = { enterKeyEventListenerPriority?: number; }; -export type {PaymentType, DropdownOption, ButtonWithDropdownMenuProps}; +export type {PaymentType, WorkspaceMemberBulkActionType, DropdownOption, ButtonWithDropdownMenuProps}; diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 553a60e568ec..f9592335d544 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -90,6 +90,8 @@ import Lock from '@assets/images/lock.svg'; import Luggage from '@assets/images/luggage.svg'; import MagnifyingGlass from '@assets/images/magnifying-glass.svg'; import Mail from '@assets/images/mail.svg'; +import MakeAdmin from '@assets/images/make-admin.svg'; +import MakeMember from '@assets/images/make-member.svg'; import Megaphone from '@assets/images/megaphone.svg'; import Menu from '@assets/images/menu.svg'; import Meter from '@assets/images/meter.svg'; @@ -116,6 +118,7 @@ import QrCode from '@assets/images/qrcode.svg'; import QuestionMark from '@assets/images/question-mark-circle.svg'; import ReceiptSearch from '@assets/images/receipt-search.svg'; import Receipt from '@assets/images/receipt.svg'; +import RemoveMembers from '@assets/images/remove-members.svg'; import Rotate from '@assets/images/rotate-image.svg'; import RotateLeft from '@assets/images/rotate-left.svg'; import Scan from '@assets/images/scan.svg'; @@ -238,6 +241,8 @@ export { Luggage, MagnifyingGlass, Mail, + MakeAdmin, + MakeMember, Menu, Meter, Megaphone, @@ -265,6 +270,7 @@ export { QrCode, QuestionMark, Receipt, + RemoveMembers, ReceiptSearch, Rotate, RotateLeft, diff --git a/src/languages/en.ts b/src/languages/en.ts index b6a24f33035c..09492a0b424d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1740,6 +1740,8 @@ export default { genericFailureMessage: 'An error occurred removing a user from the workspace, please try again.', removeMembersPrompt: 'Are you sure you want to remove the selected members from your workspace?', removeMembersTitle: 'Remove members', + makeMember: 'Make member', + makeAdmin: 'Make admin', selectAll: 'Select all', error: { genericAdd: 'There was a problem adding this workspace member.', diff --git a/src/languages/es.ts b/src/languages/es.ts index fc6755519d6f..8d544bd5efc2 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1764,6 +1764,8 @@ export default { genericFailureMessage: 'Se ha producido un error al intentar eliminar a un usuario del espacio de trabajo. Por favor, inténtalo más tarde.', removeMembersPrompt: '¿Estás seguro que quieres eliminar a los miembros seleccionados de tu espacio de trabajo?', removeMembersTitle: 'Eliminar miembros', + makeMember: 'Hacer miembro', + makeAdmin: 'Hacer administrador', selectAll: 'Seleccionar todo', error: { genericAdd: 'Ha ocurrido un problema al añadir el miembro al espacio de trabajo.', diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index f28a435d26d9..5164b4222700 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -8,6 +8,8 @@ import {withOnyx} from 'react-native-onyx'; import Badge from '@components/Badge'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import Button from '@components/Button'; +import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; +import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -83,6 +85,7 @@ function WorkspaceMembersPage({policyMembers, personalDetails, route, policy, se const prevPersonalDetails = usePrevious(personalDetails); const {translate, formatPhoneNumber, preferredLocale} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); + const dropdownButtonRef = useRef(null); /** * Get filtered personalDetails list with current policyMembers @@ -382,18 +385,66 @@ function WorkspaceMembersPage({policyMembers, personalDetails, route, policy, se ); + const getBulkActionsButtonOptions = () => { + const iconSettings = { + iconWidth: 40, + iconHeight: 40, + }; + const options: Array> = [ + { + text: translate('workspace.people.removeMembersTitle'), + value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.REMOVE, + icon: Expensicons.RemoveMembers, + ...iconSettings, + }, + ]; + + if (selectedEmployees.find((employee) => policyMembers?.[employee].role === CONST.POLICY.ROLE.ADMIN)) { + options.push({ + text: translate('workspace.people.makeMember'), + value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_MEMBER, + icon: Expensicons.MakeMember, + ...iconSettings, + }); + } else if (selectedEmployees.find((employee) => policyMembers?.[employee].role === CONST.POLICY.ROLE.USER)) { + options.push({ + text: translate('workspace.people.makeAdmin'), + value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_ADMIN, + icon: Expensicons.MakeAdmin, + ...iconSettings, + }); + } + + return options; + }; + + const handleBulkAction = (action: WorkspaceMemberBulkActionType) => { + // eslint-disable-next-line no-console + console.log(action); + }; + const getHeaderButtons = () => ( -