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

Add Share page for Workspace Profile #36907

Merged
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,10 @@ const ROUTES = {
route: 'workspace/:policyID/profile/description',
getRoute: (policyID: string) => `workspace/${policyID}/profile/description` as const,
},
WORKSPACE_PROFILE_SHARE: {
route: 'workspace/:policyID/profile/share',
getRoute: (policyID: string) => `workspace/${policyID}/profile/share` as const,
},
WORKSPACE_AVATAR: {
route: 'workspace/:policyID/avatar',
getRoute: (policyID: string) => `workspace/${policyID}/avatar` as const,
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ const SCREENS = {
INVITE_MESSAGE: 'Workspace_Invite_Message',
CURRENCY: 'Workspace_Profile_Currency',
DESCRIPTION: 'Workspace_Profile_Description',
SHARE: 'Workspace_Profile_Share',
NAME: 'Workspace_Profile_Name',
},

Expand Down
6 changes: 5 additions & 1 deletion src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ type ButtonProps = (ButtonWithText | ChildrenProps) & {
/** The fill color to pass into the icon. */
iconFill?: string;

/** Indicates whether the icon should be small. */
isIconSmall?: boolean;

/** Any additional styles to pass to the left icon container. */
iconStyles?: StyleProp<ViewStyle>;

Expand Down Expand Up @@ -164,6 +167,7 @@ function Button(
iconFill,
iconStyles = [],
iconRightStyles = [],
isIconSmall = false,

small = false,
large = false,
Expand Down Expand Up @@ -241,7 +245,7 @@ function Button(
<Icon
src={icon}
fill={iconFill ?? (success || danger ? theme.textLight : theme.icon)}
small={small}
small={isIconSmall}
Copy link
Contributor

Choose a reason for hiding this comment

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

Visual regression can happen when small button + icon because isIconSmall is not passed

<Button
small
innerStyles={[styles.arrowIcon]}
icon={Expensicons.BackArrow}
iconFill={theme.text}

Please test arrow buttons in attachment carousel

Copy link
Contributor

Choose a reason for hiding this comment

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

I left this comment elsewhere but I don't think we want this kind of prop here... we just want to globally change the size of icons in these buttons, I think at least... Danny will confirm!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will rollback that

/>
</View>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.INVITE_MESSAGE]: () => require('../../../pages/workspace/WorkspaceInviteMessagePage').default as React.ComponentType,
[SCREENS.WORKSPACE.NAME]: () => require('../../../pages/workspace/WorkspaceNamePage').default as React.ComponentType,
[SCREENS.WORKSPACE.DESCRIPTION]: () => require('../../../pages/workspace/WorkspaceProfileDescriptionPage').default as React.ComponentType,
[SCREENS.WORKSPACE.SHARE]: () => require('../../../pages/workspace/WorkspaceProfileSharePage').default as React.ComponentType,
[SCREENS.WORKSPACE.CURRENCY]: () => require('../../../pages/workspace/WorkspaceProfileCurrencyPage').default as React.ComponentType,
[SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType,
[SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {CentralPaneName} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';

const CENTRAL_PANE_TO_RHP_MAPPING: Partial<Record<CentralPaneName, string[]>> = {
[SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION],
[SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE],
[SCREENS.WORKSPACE.REIMBURSE]: [SCREENS.WORKSPACE.RATE_AND_UNIT, SCREENS.WORKSPACE.RATE_AND_UNIT_RATE, SCREENS.WORKSPACE.RATE_AND_UNIT_UNIT],
[SCREENS.WORKSPACE.MEMBERS]: [SCREENS.WORKSPACE.INVITE, SCREENS.WORKSPACE.INVITE_MESSAGE],
};
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.DESCRIPTION]: {
path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route,
},
[SCREENS.WORKSPACE.SHARE]: {
path: ROUTES.WORKSPACE_PROFILE_SHARE.route,
},
[SCREENS.WORKSPACE.RATE_AND_UNIT]: {
path: ROUTES.WORKSPACE_RATE_AND_UNIT.route,
},
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.CURRENCY]: undefined;
[SCREENS.WORKSPACE.NAME]: undefined;
[SCREENS.WORKSPACE.DESCRIPTION]: undefined;
[SCREENS.WORKSPACE.SHARE]: undefined;
[SCREENS.WORKSPACE.RATE_AND_UNIT]: {
policyID: string;
};
Expand Down
5 changes: 5 additions & 0 deletions src/libs/shouldAllowDownloadQRCode/index.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type ShouldAllowDownloadQRCode from './types';

const shouldAllowDownloadQRCode: ShouldAllowDownloadQRCode = true;

export default shouldAllowDownloadQRCode;
5 changes: 5 additions & 0 deletions src/libs/shouldAllowDownloadQRCode/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type ShouldAllowDownloadQRCode from './types';

const shouldAllowDownloadQRCode: ShouldAllowDownloadQRCode = false;

export default shouldAllowDownloadQRCode;
3 changes: 3 additions & 0 deletions src/libs/shouldAllowDownloadQRCode/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type ShouldAllowDownloadQRCode = boolean;

export default ShouldAllowDownloadQRCode;
15 changes: 15 additions & 0 deletions src/pages/workspace/WorkspaceProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {withOnyx} from 'react-native-onyx';
import WorkspaceProfile from '@assets/images/workspace-profile.png';
import Avatar from '@components/Avatar';
import AvatarWithImagePicker from '@components/AvatarWithImagePicker';
import Button from '@components/Button';
import * as Expensicons from '@components/Icon/Expensicons';
import * as Illustrations from '@components/Icon/Illustrations';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
Expand Down Expand Up @@ -50,6 +51,7 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi
const onPressCurrency = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_CURRENCY.getRoute(policy?.id ?? '')), [policy?.id]);
const onPressName = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_NAME.getRoute(policy?.id ?? '')), [policy?.id]);
const onPressDescription = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_DESCRIPTION.getRoute(policy?.id ?? '')), [policy?.id]);
const onPressShare = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_SHARE.getRoute(policy?.id ?? '')), [policy?.id]);

const policyName = policy?.name ?? '';
const policyDescription = policy?.description ?? '';
Expand Down Expand Up @@ -158,6 +160,19 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi
</Text>
</View>
</OfflineWithFeedback>
{!readOnly && (
<View style={[styles.flexRow, styles.mnw120]}>
<Button
accessibilityLabel={translate('common.share')}
icon={Expensicons.QrCode}
style={styles.mt6}
text={translate('common.share')}
onPress={onPressShare}
medium
isIconSmall
/>
</View>
)}
</Section>
</View>
</ScrollView>
Expand Down
88 changes: 88 additions & 0 deletions src/pages/workspace/WorkspaceProfileSharePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, {useRef} from 'react';
import {ScrollView, View} from 'react-native';
import type {ImageSourcePropType} from 'react-native';
import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png';
import ContextMenuItem from '@components/ContextMenuItem';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
import MenuItem from '@components/MenuItem';
import QRShareWithDownload from '@components/QRShare/QRShareWithDownload';
import type QRShareWithDownloadHandle from '@components/QRShare/QRShareWithDownload/types';
import ScreenWrapper from '@components/ScreenWrapper';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import Clipboard from '@libs/Clipboard';
import Navigation from '@libs/Navigation/Navigation';
import shouldAllowDownloadQRCode from '@libs/shouldAllowDownloadQRCode';
import * as Url from '@libs/Url';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import withPolicy from './withPolicy';
import type {WithPolicyProps} from './withPolicy';

function WorkspaceProfileSharePage({policy}: WithPolicyProps) {
const themeStyles = useThemeStyles();
const {translate} = useLocalize();
const {environmentURL} = useEnvironment();
const qrCodeRef = useRef<QRShareWithDownloadHandle>(null);
const {isSmallScreenWidth} = useWindowDimensions();

const policyName = policy?.name ?? '';
const id = policy?.id ?? '';
const urlWithTrailingSlash = Url.addTrailingForwardSlash(environmentURL);

const url = `${urlWithTrailingSlash}${ROUTES.WORKSPACE_PROFILE.getRoute(id)}`;
return (
<ScreenWrapper
testID={WorkspaceProfileSharePage.displayName}
shouldShowOfflineIndicatorInWideScreen
>
<HeaderWithBackButton
title={translate('common.share')}
onBackButtonPress={Navigation.goBack}
/>
<ScrollView style={[themeStyles.flex1, themeStyles.pt2]}>
<View style={[themeStyles.flex1, isSmallScreenWidth ? themeStyles.workspaceSectionMobile : themeStyles.workspaceSection]}>
<View style={[themeStyles.workspaceSectionMobile, themeStyles.ph9]}>
<QRShareWithDownload
ref={qrCodeRef}
url={url}
title={policyName}
logo={(policy?.avatar ? policy.avatar : expensifyLogo) as ImageSourcePropType}
logoRatio={CONST.QR.DEFAULT_LOGO_SIZE_RATIO}
logoMarginRatio={CONST.QR.DEFAULT_LOGO_MARGIN_RATIO}
/>
</View>

<View style={[themeStyles.mt3, themeStyles.ph4]}>
<ContextMenuItem
isAnonymousAction
text={translate('qrCodes.copy')}
icon={Expensicons.Copy}
successIcon={Expensicons.Checkmark}
successText={translate('qrCodes.copied')}
onPress={() => Clipboard.setString(url)}
shouldLimitWidth={false}
wrapperStyle={themeStyles.sectionMenuItemTopDescription}
/>
{shouldAllowDownloadQRCode && (
<MenuItem
isAnonymousAction
title={translate('common.download')}
icon={Expensicons.Download}
onPress={() => qrCodeRef.current?.download?.()}
wrapperStyle={themeStyles.sectionMenuItemTopDescription}
/>
)}
</View>
</View>
</ScrollView>
</ScreenWrapper>
);
}

WorkspaceProfileSharePage.displayName = 'WorkspaceProfileSharePage';

export default withPolicy(WorkspaceProfileSharePage);
Loading