Skip to content

Commit

Permalink
Migrate FloatingActionButton to useOnyx and add small cleanups
Browse files Browse the repository at this point in the history
  • Loading branch information
Kicu committed Oct 14, 2024
1 parent d2e2119 commit 45dd97a
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 115 deletions.
3 changes: 2 additions & 1 deletion src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ import * as ReportActionsConnection from '@libs/ReportActionsConnection';
import * as ReportConnection from '@libs/ReportConnection';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover';
import * as PaymentMethods from '@userActions/PaymentMethods';
import * as PersistedRequests from '@userActions/PersistedRequests';
import CONST from '@src/CONST';
Expand All @@ -96,6 +95,8 @@ import type {OnyxData} from '@src/types/onyx/Request';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import {buildOptimisticPolicyCategories} from './Category';

type PolicySelector = Pick<Policy, 'type' | 'role' | 'isPolicyExpenseChatEnabled' | 'pendingAction' | 'avatarURL' | 'name' | 'id' | 'areInvoicesEnabled'>;

type ReportCreationData = Record<
string,
{
Expand Down
12 changes: 2 additions & 10 deletions src/pages/home/sidebar/BottomTabAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@ import AvatarWithOptionalStatus from './AvatarWithOptionalStatus';
import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator';

type BottomTabAvatarProps = {
/** Whether the create menu is open or not */
isCreateMenuOpen?: boolean;

/** Whether the avatar is selected */
isSelected?: boolean;
};

function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomTabAvatarProps) {
function BottomTabAvatar({isSelected = false}: BottomTabAvatarProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
Expand All @@ -39,11 +36,6 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT
const {shouldUseNarrowLayout} = useResponsiveLayout();

const showSettingsPage = useCallback(() => {
if (isCreateMenuOpen) {
// Prevent opening Settings page when click profile avatar quickly after clicking FAB icon
return;
}

if (route.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) {
Navigation.goUp(ROUTES.SETTINGS);
return;
Expand Down Expand Up @@ -84,7 +76,7 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT
// This case also covers if there is no route to remember.
Navigation.navigate(ROUTES.SETTINGS);
});
}, [isCreateMenuOpen, shouldUseNarrowLayout, route.name]);
}, [shouldUseNarrowLayout, route.name]);

let children;

Expand Down
138 changes: 34 additions & 104 deletions src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import {useIsFocused as useIsFocusedOriginal, useNavigationState} from '@react-navigation/native';
import type {ImageContentFit} from 'expo-image';
import type {ForwardedRef, RefAttributes} from 'react';
import type {ForwardedRef} from 'react';
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import {useOnyx, withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import type {SvgProps} from 'react-native-svg';
import FloatingActionButton from '@components/FloatingActionButton';
import * as Expensicons from '@components/Icon/Expensicons';
Expand Down Expand Up @@ -36,7 +35,6 @@ import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import type * as OnyxTypes from '@src/types/onyx';
import type {QuickActionName} from '@src/types/onyx/QuickAction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

Expand All @@ -49,35 +47,7 @@ const useIsFocused = () => {
return isFocused || (topmostCentralPane?.name === SCREENS.SEARCH.CENTRAL_PANE && shouldUseNarrowLayout);
};

type PolicySelector = Pick<OnyxTypes.Policy, 'type' | 'role' | 'isPolicyExpenseChatEnabled' | 'pendingAction' | 'avatarURL' | 'name' | 'id' | 'areInvoicesEnabled'>;

type FloatingActionButtonAndPopoverOnyxProps = {
/** The list of policies the user has access to. */
allPolicies: OnyxCollection<PolicySelector>;

/** Whether app is in loading state */
isLoading: OnyxEntry<boolean>;

/** Information on the last taken action to display as Quick Action */
quickAction: OnyxEntry<OnyxTypes.QuickAction>;

/** The report data of the quick action */
quickActionReport: OnyxEntry<OnyxTypes.Report>;

/** The policy data of the quick action */
quickActionPolicy: OnyxEntry<OnyxTypes.Policy>;

/** The current session */
session: OnyxEntry<OnyxTypes.Session>;

/** Personal details of all the users */
personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>;

/** Has user seen track expense training interstitial */
hasSeenTrackTraining: OnyxEntry<boolean>;
};

type FloatingActionButtonAndPopoverProps = FloatingActionButtonAndPopoverOnyxProps & {
type FloatingActionButtonAndPopoverProps = {
/* Callback function when the menu is shown */
onShowCreateMenu?: () => void;

Expand All @@ -89,18 +59,6 @@ type FloatingActionButtonAndPopoverRef = {
hideCreateMenu: () => void;
};

const policySelector = (policy: OnyxEntry<OnyxTypes.Policy>): PolicySelector =>
(policy && {
type: policy.type,
role: policy.role,
id: policy.id,
isPolicyExpenseChatEnabled: policy.isPolicyExpenseChatEnabled,
pendingAction: policy.pendingAction,
avatarURL: policy.avatarURL,
name: policy.name,
areInvoicesEnabled: policy.areInvoicesEnabled,
}) as PolicySelector;

const getQuickActionIcon = (action: QuickActionName): React.FC<SvgProps> => {
switch (action) {
case CONST.QUICK_ACTIONS.REQUEST_MANUAL:
Expand Down Expand Up @@ -161,44 +119,43 @@ const getQuickActionTitle = (action: QuickActionName): TranslationPaths => {
* Responsible for rendering the {@link PopoverMenu}, and the accompanying
* FAB that can open or close the menu.
*/
function FloatingActionButtonAndPopover(
{
onHideCreateMenu,
onShowCreateMenu,
isLoading = false,
allPolicies,
quickAction,
quickActionReport,
quickActionPolicy,
session,
personalDetails,
hasSeenTrackTraining,
}: FloatingActionButtonAndPopoverProps,
ref: ForwardedRef<FloatingActionButtonAndPopoverRef>,
) {
function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: FloatingActionButtonAndPopoverProps, ref: ForwardedRef<FloatingActionButtonAndPopoverRef>) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${quickActionReport?.reportID ?? -1}`);
const [isCreateMenuActive, setIsCreateMenuActive] = useState(false);
const fabRef = useRef<HTMLDivElement>(null);
const {windowHeight} = useWindowDimensions();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const isFocused = useIsFocused();
const prevIsFocused = usePrevious(isFocused);
const {isOffline} = useNetwork();

const {canUseSpotnanaTravel, canUseCombinedTrackSubmit} = usePermissions();
const canSendInvoice = useMemo(() => PolicyUtils.canSendInvoice(allPolicies as OnyxCollection<OnyxTypes.Policy>, session?.email), [allPolicies, session?.email]);

const [isLoading] = useOnyx(ONYXKEYS.IS_LOADING_APP);
const [policies = {}] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [session] = useOnyx(ONYXKEYS.SESSION);
const [hasSeenTrackTraining] = useOnyx(ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING);
const [quickAction = {}] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE);
const [quickActionReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${quickAction?.chatReportID}`);
const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${quickActionReport?.reportID ?? -1}`);
const [quickActionPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${quickActionReport?.policyID}`);

const sessionEmail = session?.email;
const sessionAccountID = session?.accountID;
const canSendInvoice = useMemo(() => PolicyUtils.canSendInvoice(policies, sessionEmail), [policies, sessionEmail]);

const quickActionName = quickAction.action;

const quickActionAvatars = useMemo(() => {
if (quickActionReport) {
const avatars = ReportUtils.getIcons(quickActionReport, personalDetails);
return avatars.length <= 1 || ReportUtils.isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== session?.accountID);
return avatars.length <= 1 || ReportUtils.isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== sessionAccountID);
}
return [];
// Policy is needed as a dependency in order to update the shortcut details when the workspace changes
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [personalDetails, session?.accountID, quickActionReport, quickActionPolicy]);
}, [personalDetails, sessionAccountID, quickActionReport, quickActionPolicy]);

const renderQuickActionTooltip = useCallback(
() => (
Expand All @@ -214,13 +171,14 @@ function FloatingActionButtonAndPopover(
if (isEmptyObject(quickActionReport)) {
return '';
}
if (quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && quickActionAvatars.length > 0) {
const name: string = ReportUtils.getDisplayNameForParticipant(+(quickActionAvatars.at(0)?.id ?? -1), true) ?? '';

if (quickActionName === CONST.QUICK_ACTIONS.SEND_MONEY && quickActionAvatars.length > 0) {
const name = ReportUtils.getDisplayNameForParticipant(+(quickActionAvatars.at(0)?.id ?? -1), true) ?? '';
return translate('quickAction.paySomeone', {name});
}
const titleKey = getQuickActionTitle(quickAction?.action ?? ('' as QuickActionName));
const titleKey = getQuickActionTitle(quickActionName ?? ('' as QuickActionName));
return titleKey ? translate(titleKey) : '';
}, [quickAction, translate, quickActionAvatars, quickActionReport]);
}, [quickActionName, translate, quickActionAvatars, quickActionReport]);

const hideQABSubtitle = useMemo(() => {
if (isEmptyObject(quickActionReport)) {
Expand All @@ -230,8 +188,8 @@ function FloatingActionButtonAndPopover(
return false;
}
const displayName = personalDetails?.[quickActionAvatars.at(0)?.id ?? -1]?.firstName ?? '';
return quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && displayName.length === 0;
}, [personalDetails, quickActionReport, quickAction?.action, quickActionAvatars]);
return quickActionName === CONST.QUICK_ACTIONS.SEND_MONEY && displayName.length === 0;
}, [personalDetails, quickActionReport, quickActionName, quickActionAvatars]);

const navigateToQuickAction = () => {
const selectOption = (onSelected: () => void, shouldRestrictAction: boolean) => {
Expand All @@ -246,7 +204,7 @@ function FloatingActionButtonAndPopover(
const isValidReport = !(isEmptyObject(quickActionReport) || ReportUtils.isArchivedRoom(quickActionReport, reportNameValuePairs));
const quickActionReportID = isValidReport ? quickActionReport?.reportID ?? '-1' : ReportUtils.generateReportID();

switch (quickAction?.action) {
switch (quickActionName) {
case CONST.QUICK_ACTIONS.REQUEST_MANUAL:
selectOption(() => IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, quickActionReportID, CONST.IOU.REQUEST_TYPE.MANUAL, true), true);
return;
Expand Down Expand Up @@ -454,7 +412,7 @@ function FloatingActionButtonAndPopover(
},
]
: []),
...(!isLoading && !Policy.hasActiveChatEnabledPolicies(allPolicies)
...(!isLoading && !Policy.hasActiveChatEnabledPolicies(policies)
? [
{
displayInDefaultIconColor: true,
Expand All @@ -468,10 +426,10 @@ function FloatingActionButtonAndPopover(
},
]
: []),
...(quickAction?.action
...(quickActionName
? [
{
icon: getQuickActionIcon(quickAction?.action),
icon: getQuickActionIcon(quickActionName),
text: quickActionTitle,
label: translate('quickAction.header'),
isLabelHoverable: false,
Expand Down Expand Up @@ -510,32 +468,4 @@ function FloatingActionButtonAndPopover(

FloatingActionButtonAndPopover.displayName = 'FloatingActionButtonAndPopover';

export default withOnyx<FloatingActionButtonAndPopoverProps & RefAttributes<FloatingActionButtonAndPopoverRef>, FloatingActionButtonAndPopoverOnyxProps>({
allPolicies: {
key: ONYXKEYS.COLLECTION.POLICY,
selector: policySelector,
},
isLoading: {
key: ONYXKEYS.IS_LOADING_APP,
},
quickAction: {
key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE,
},
quickActionReport: {
key: ({quickAction}) => `${ONYXKEYS.COLLECTION.REPORT}${quickAction?.chatReportID}`,
},
quickActionPolicy: {
key: ({quickActionReport}) => `${ONYXKEYS.COLLECTION.POLICY}${quickActionReport?.policyID}`,
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
session: {
key: ONYXKEYS.SESSION,
},
hasSeenTrackTraining: {
key: ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING,
},
})(forwardRef(FloatingActionButtonAndPopover));

export type {PolicySelector};
export default forwardRef(FloatingActionButtonAndPopover);

0 comments on commit 45dd97a

Please sign in to comment.