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

feat: add PromotedActionsBar #41972

Merged
merged 31 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8521e75
refactor: update ChatDetailsQuickActionsBar to be generic
kosmydel May 10, 2024
4b80097
x
kosmydel May 10, 2024
2280259
Add useQuickActions hook
kosmydel May 13, 2024
abb830c
share type with ThreeDotsMenuItem
kosmydel May 13, 2024
27bb412
Merge branch 'main' into @kosmydel/details-revamp/actions-bar
kosmydel May 13, 2024
9cf7497
refactor: rename ChatDetailsQuickActionsBar to PromotedActionsBar
kosmydel May 13, 2024
08e44fc
cleanup
kosmydel May 14, 2024
7b3b2f9
feat: add CommentBubbles icon
kosmydel May 14, 2024
b0c18e5
fix: stopwatch icon color
kosmydel May 14, 2024
8ced990
fix: actions config
kosmydel May 14, 2024
902b774
fix: key
kosmydel May 14, 2024
3a4e6f4
Merge branch 'main' into @kosmydel/details-revamp/actions-bar
kosmydel May 14, 2024
5489810
fix: add medium prop
kosmydel May 14, 2024
bc6004e
fix: update icons
kosmydel May 14, 2024
dfdb1f5
fix: remove button container padding
kosmydel May 14, 2024
738075d
fix: change gap to 8px
kosmydel May 14, 2024
324080b
address review
kosmydel May 15, 2024
8fe01f8
adress review
kosmydel May 15, 2024
22ed96d
feat: add storybook
kosmydel May 15, 2024
3fafaff
fix: typo
kosmydel May 15, 2024
b8a6221
Merge branch 'main' into @kosmydel/details-revamp/actions-bar
kosmydel May 15, 2024
1e67021
fix: make the report optional
kosmydel May 15, 2024
5a86528
feat: add better styles
kosmydel May 15, 2024
8771bd6
refactor: support separate parameters for each predefined action
kosmydel May 15, 2024
5971fb3
refactor: change order of the buttons
kosmydel May 15, 2024
0f5aa5d
refactor: ReportDetailsPage
kosmydel May 15, 2024
6d1e40e
Revert "refactor: ReportDetailsPage"
kosmydel May 15, 2024
f2d0e2f
fix: do not display empty PromotedActionsBar
kosmydel May 20, 2024
cc302ff
feat: max promoted action width
kosmydel May 21, 2024
0367b26
Merge branch 'Expensify:main' into @kosmydel/actions-bar
kosmydel May 29, 2024
8431492
cleanup: remove TODO
kosmydel May 29, 2024
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
14 changes: 14 additions & 0 deletions assets/images/comment-bubbles.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion assets/images/stopwatch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 0 additions & 64 deletions src/components/ChatDetailsQuickActionsBar.tsx

This file was deleted.

2 changes: 2 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import Close from '@assets/images/close.svg';
import ClosedSign from '@assets/images/closed-sign.svg';
import Coins from '@assets/images/coins.svg';
import Collapse from '@assets/images/collapse.svg';
import CommentBubbles from '@assets/images/comment-bubbles.svg';
import Concierge from '@assets/images/concierge.svg';
import Connect from '@assets/images/connect.svg';
import ConnectionComplete from '@assets/images/connection-complete.svg';
Expand Down Expand Up @@ -203,6 +204,7 @@ export {
Close,
ClosedSign,
Collapse,
CommentBubbles,
Concierge,
ConciergeAvatar,
Connect,
Expand Down
118 changes: 118 additions & 0 deletions src/components/PromotedActionsBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React, {useState} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as HeaderUtils from '@libs/HeaderUtils';
import * as ReportActions from '@userActions/Report';
import type OnyxReport from '@src/types/onyx/Report';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import type {ThreeDotsMenuItem} from './HeaderWithBackButton/types';
import * as Expensicons from './Icon/Expensicons';

type PromotedAction = {
key: string;
} & ThreeDotsMenuItem;

type ReportPromotedAction = (report: OnyxReport) => PromotedAction;

type PromotedActionsType = {
pin: ReportPromotedAction;
};

const PromotedActions = {
pin: (report) => ({
key: 'pin',
...HeaderUtils.getPinMenuItem(report),
}),
} satisfies PromotedActionsType;

type PromotedActionsBarProps = {
/** The report of actions */
report?: OnyxReport;

/** The list of actions to show */
promotedActions: PromotedAction[];

/** The style of the container */
containerStyle?: StyleProp<ViewStyle>;

/**
* Whether to show the `Leave` button.
* @deprecated Remove this prop when @src/pages/ReportDetailsPage.tsx is updated
*/
shouldShowLeaveButton?: boolean;
};

function PromotedActionsBar({report, promotedActions, containerStyle, shouldShowLeaveButton}: PromotedActionsBarProps) {
const theme = useTheme();
const styles = useThemeStyles();
const [isLastMemberLeavingGroupModalVisible, setIsLastMemberLeavingGroupModalVisible] = useState(false);
const {translate} = useLocalize();

if (promotedActions.length === 0) {
return null;
}

return (
<View style={[styles.flexRow, styles.ph5, styles.mb5, styles.gap2, styles.mw100, styles.w100, styles.justifyContentCenter, containerStyle]}>
{/* TODO: Remove the `Leave` button when @src/pages/ReportDetailsPage.tsx is updated */}
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have a WIP PR for this yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cc @cdOut

Copy link
Contributor

Choose a reason for hiding this comment

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

I’m handling this one in my ReportDetailsPage PR, I’ll link it here after I put up a draft PR for it later in the evening.

Copy link
Contributor

Choose a reason for hiding this comment

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

Please check this PR we're already moving it there.

{shouldShowLeaveButton && report && (
// The `Leave` button is left to make the component backward compatible with the existing code.
// After the `Leave` button is moved to the `MenuItem` list, this block can be removed.
<View style={[styles.flex1]}>
<ConfirmModal
danger
title={translate('groupChat.lastMemberTitle')}
isVisible={isLastMemberLeavingGroupModalVisible}
onConfirm={() => {
setIsLastMemberLeavingGroupModalVisible(false);
ReportActions.leaveGroupChat(report.reportID);
}}
onCancel={() => setIsLastMemberLeavingGroupModalVisible(false)}
prompt={translate('groupChat.lastMemberWarning')}
confirmText={translate('common.leave')}
cancelText={translate('common.cancel')}
/>
<Button
onPress={() => {
if (Object.keys(report?.participants ?? {}).length === 1) {
setIsLastMemberLeavingGroupModalVisible(true);
return;
}

ReportActions.leaveGroupChat(report.reportID);
}}
icon={Expensicons.Exit}
style={styles.flex1}
medium
text={translate('common.leave')}
/>
</View>
)}
{promotedActions.map(({key, onSelected, ...props}) => (
<View
style={[styles.flex1, styles.mw50]}
key={key}
>
<Button
onPress={onSelected}
iconFill={theme.icon}
medium
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
/>
</View>
))}
</View>
);
}

PromotedActionsBar.displayName = 'PromotedActionsBar';

export default PromotedActionsBar;

export {PromotedActions};
export type {PromotedActionsBarProps, PromotedAction};
8 changes: 8 additions & 0 deletions src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,13 @@ function navigateToMostRecentReport(currentReport: OnyxEntry<Report>) {
}
}

function joinRoom(report: OnyxEntry<Report>) {
if (!report) {
return;
}
updateNotificationPreference(report.reportID, report.notificationPreference, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, false, report.parentReportID, report.parentReportActionID);
}

function leaveGroupChat(reportID: string) {
const report = ReportUtils.getReport(reportID);
if (!report) {
Expand Down Expand Up @@ -3814,6 +3821,7 @@ export {
showReportActionNotification,
toggleEmojiReaction,
shouldShowReportActionNotification,
joinRoom,
leaveRoom,
inviteToRoom,
inviteToGroupChat,
Expand Down
10 changes: 8 additions & 2 deletions src/pages/ReportDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {withOnyx} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import AvatarWithImagePicker from '@components/AvatarWithImagePicker';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import ChatDetailsQuickActionsBar from '@components/ChatDetailsQuickActionsBar';
import DisplayNames from '@components/DisplayNames';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
Expand All @@ -17,6 +16,7 @@ import MultipleAvatars from '@components/MultipleAvatars';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import PromotedActionsBar, {PromotedActions} from '@components/PromotedActionsBar';
import RoomHeaderAvatars from '@components/RoomHeaderAvatars';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
Expand Down Expand Up @@ -333,7 +333,13 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
/>
</OfflineWithFeedback>
)}
{isGroupChat && <ChatDetailsQuickActionsBar report={report} />}
{isGroupChat && (
<PromotedActionsBar
report={report}
promotedActions={[PromotedActions.pin(report)]}
shouldShowLeaveButton
/>
)}
{menuItems.map((item) => {
const brickRoadIndicator =
ReportUtils.hasReportNameError(report) && item.key === CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined;
Expand Down
4 changes: 1 addition & 3 deletions src/pages/home/HeaderView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,7 @@ function HeaderView({
}
}

const join = Session.checkIfActionIsAllowed(() =>
Report.updateNotificationPreference(reportID, report.notificationPreference, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, false, report.parentReportID, report.parentReportActionID),
);
const join = Session.checkIfActionIsAllowed(() => Report.joinRoom(report));

const canJoin = ReportUtils.canJoinChat(report, parentReportAction, policy);
if (canJoin) {
Expand Down
70 changes: 70 additions & 0 deletions src/stories/PromotedActionBar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import {View} from 'react-native';
import * as Expensicons from '@components/Icon/Expensicons';
import PromotedActionsBar from '@components/PromotedActionsBar';
import type {PromotedAction, PromotedActionsBarProps} from '@components/PromotedActionsBar';
import variables from '@src/styles/variables';

/**
* We use the Component Story Format for writing stories. Follow the docs here:
*
* https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
*/
const story = {
title: 'Components/PromotedActionsBar',
component: PromotedActionsBar,
};

type StoryType = typeof Template & {args?: Partial<PromotedActionsBarProps>};

function Template(args: PromotedActionsBarProps) {
return (
<View style={{maxWidth: variables.sideBarWidth}}>
<PromotedActionsBar
// eslint-disable-next-line react/jsx-props-no-spreading
{...args}
/>
</View>
);
}

const promotedActions = [
{
key: 'join',
icon: Expensicons.CommentBubbles,
text: 'Join',
onSelected: () => {},
},
{
key: 'pin',
icon: Expensicons.Pin,
text: 'Pin',
onSelected: () => {},
},
{
key: 'share',
icon: Expensicons.QrCode,
text: 'Share',
onSelected: () => {},
},
] satisfies PromotedAction[];

// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Default: StoryType = Template.bind({});
Default.args = {
promotedActions: [promotedActions[0]],
};

const TwoPromotedActions: StoryType = Template.bind({});
TwoPromotedActions.args = {
promotedActions: [promotedActions[0], promotedActions[1]],
};

const ThreePromotedActions: StoryType = Template.bind({});
ThreePromotedActions.args = {
promotedActions: [promotedActions[0], promotedActions[1], promotedActions[2]],
};

export default story;
export {Default, TwoPromotedActions, ThreePromotedActions};
Loading