Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
aab897c
add the ShareReport write command
allgandalf Oct 6, 2026
ba6f4c7
add the share secondary action and its sentry labels
allgandalf Oct 6, 2026
351aace
add the shareReport action
allgandalf Oct 6, 2026
0f20077
add canShareReport
allgandalf Oct 6, 2026
3cb981c
register the share report route
allgandalf Oct 6, 2026
dd7f4ac
add the share report copy
allgandalf Oct 6, 2026
a365ef0
add the share report page
allgandalf Oct 6, 2026
be9620c
translate the share report copy
allgandalf Oct 6, 2026
7324bb5
use report in the italian share report copy
allgandalf Oct 6, 2026
957821c
add useShareActions
allgandalf Oct 6, 2026
e3c852e
place share between download and print in the more menu
allgandalf Oct 6, 2026
fe3cecc
list share in the report secondary actions
allgandalf Oct 6, 2026
5c618ba
show share in the report more menu
allgandalf Oct 6, 2026
5ec1c24
use the refer a friend header copy
allgandalf Oct 6, 2026
b3c9a37
expect share in the default secondary actions
allgandalf Oct 6, 2026
794ce69
test the share options
allgandalf Oct 6, 2026
c7210af
test the shareReport request
allgandalf Oct 6, 2026
91e199d
use the composed header on the share report page
allgandalf Oct 6, 2026
1338e69
Merge remote-tracking branch 'upstream/main' into share-report-more-menu
allgandalf Oct 8, 2026
2d26b72
Merge remote-tracking branch 'upstream/main' into share-report-more-menu
allgandalf Oct 10, 2026
0f009fb
restore the action bundles from main
allgandalf Oct 10, 2026
012eb97
add the report shared copy
allgandalf Oct 13, 2026
93a387f
translate the report shared copy
allgandalf Oct 13, 2026
f3c63a2
match the share report wording in german and chinese
allgandalf Oct 13, 2026
46078de
show a growl after sharing a report
allgandalf Oct 13, 2026
9268036
let the share code route show only the QR code
allgandalf Oct 14, 2026
2f31ee0
add shouldShowQRCodeOnly to the share code params
allgandalf Oct 14, 2026
a6f7e36
hide the rows under the QR code when asked
allgandalf Oct 14, 2026
7a3a1a3
pass shouldShowQRCodeOnly to the share code page
allgandalf Oct 14, 2026
e8abfb6
open share code with only the QR code from the share menu
allgandalf Oct 14, 2026
41198bf
test share code opens with only the QR code
allgandalf Oct 14, 2026
e045091
test the share code page with only the QR code
allgandalf Oct 14, 2026
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
6 changes: 6 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,7 @@ const CONST = {
HOLD: 'hold',
DOWNLOAD_PDF: 'downloadPDF',
DOWNLOAD_RECEIPTS: 'downloadReceipts',
SHARE: 'share',
PRINT: 'print',
CHANGE_WORKSPACE: 'changeWorkspace',
CHANGE_APPROVER: 'changeApprover',
Expand Down Expand Up @@ -9760,6 +9761,11 @@ const CONST = {
EXPORT_FILE: 'MoreMenu-ExportFile',
DOWNLOAD_PDF: 'MoreMenu-DownloadPDF',
DOWNLOAD_RECEIPTS: 'MoreMenu-DownloadReceipts',
SHARE: 'MoreMenu-Share',
SHARE_REPORT: 'MoreMenu-ShareReport',
SHARE_CODE: 'MoreMenu-ShareCode',
REFER_FRIEND: 'MoreMenu-ReferFriend',
COPY_URL: 'MoreMenu-CopyURL',
PRINT: 'MoreMenu-Print',
CLOSE_PDF_MODAL: 'MoreMenu-ClosePDFModal',
SUBMIT: 'MoreMenu-Submit',
Expand Down
6 changes: 6 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,8 @@ const DYNAMIC_ROUTES = {
SCREENS.SEARCH.ROOT,
SCREENS.REPORT_DETAILS.DYNAMIC_ROOT,
],
getRoute: (shouldShowQRCodeOnly?: boolean) => getUrlWithParams('share-code', {shouldShowQRCodeOnly: shouldShowQRCodeOnly ? 'true' : undefined}),
queryParams: ['shouldShowQRCodeOnly'],
},
REFERRAL_DETAILS: {
path: 'referral/:contentType',
Expand All @@ -1594,6 +1596,10 @@ const DYNAMIC_ROUTES = {
entryScreens: [SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, SCREENS.SEARCH.ROOT],
getRoute: (connectionName: ConnectionName) => `details/export/${connectionName as string}` as const,
},
REPORT_DETAILS_SHARE_REPORT: {
path: 'share-report',
entryScreens: [SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, SCREENS.SEARCH.ROOT],
},
REPORT_CHANGE_WORKSPACE: {
path: 'change-workspace',
entryScreens: [SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, SCREENS.SEARCH.ROOT],
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ const SCREENS = {
DYNAMIC_ROOT: 'Dynamic_Report_Details_Root',
DYNAMIC_SHARE_CODE: 'Dynamic_Report_Details_Share_Code',
DYNAMIC_EXPORT: 'Dynamic_Report_Details_Export',
DYNAMIC_SHARE_REPORT: 'Dynamic_Report_Details_Share_Report',
},

REPORT_CHANGE_WORKSPACE: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import usePolicy from '@hooks/usePolicy';
import useReportIsArchived from '@hooks/useReportIsArchived';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSearchShouldCalculateTotals from '@hooks/useSearchShouldCalculateTotals';
import useShareActions from '@hooks/useShareActions';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useTransactionsAndViolationsForReport from '@hooks/useTransactionsAndViolationsForReport';
Expand Down Expand Up @@ -388,6 +389,8 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo
onPDFModalOpen: openPDFDownload,
});

const shareActions = useShareActions({reportID, policy});

// Compute list of applicable secondary action keys
const secondaryActions = moneyRequestReport
? getSecondaryReportActions({
Expand Down Expand Up @@ -425,6 +428,7 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo
},
},
...exportActionEntries,
...shareActions,
...lifecycleActionEntries,
...expenseActions,
...holdRejectActions,
Expand Down
91 changes: 91 additions & 0 deletions src/hooks/useShareActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Builds the Share option of the report More menu and the options under it.
*/
import type {SecondaryActionEntry} from '@components/MoneyReportHeaderActions/types';
import type {PopoverMenuItem} from '@components/PopoverMenu';

import Clipboard from '@libs/Clipboard';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
import Navigation from '@libs/Navigation/Navigation';
import {canShareReport} from '@libs/ReportUtils';
import addTrailingForwardSlash from '@libs/UrlUtils';

import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';

import type {OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';

import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
import useEnvironment from './useEnvironment';
import {useMemoizedLazyExpensifyIcons} from './useLazyAsset';
import useLocalize from './useLocalize';
import useOnyx from './useOnyx';

type UseShareActionsParams = {
reportID: string | undefined;
policy?: OnyxEntry<OnyxTypes.Policy>;
};

type UseShareActionsReturn = Pick<Record<ValueOf<typeof CONST.REPORT.SECONDARY_ACTIONS>, SecondaryActionEntry>, typeof CONST.REPORT.SECONDARY_ACTIONS.SHARE>;

function useShareActions({reportID, policy}: UseShareActionsParams): UseShareActionsReturn {
const {translate} = useLocalize();
const {environmentURL} = useEnvironment();
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Mail', 'QrCode', 'Cash', 'Copy', 'ArrowRight'] as const);

const [moneyRequestReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(reportID)}`);

const shareSubMenuItems: PopoverMenuItem[] = [
{
text: translate('common.shareCode'),
icon: expensifyIcons.QrCode,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.SHARE_CODE,
onSelected: () => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.REPORT_DETAILS_SHARE_CODE.getRoute(true))),
},
{
text: translate(`referralProgram.${CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND}.header`),
icon: expensifyIcons.Cash,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.REFER_FRIEND,
onSelected: () => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.REFERRAL_DETAILS.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND))),
},
{
text: translate('qrCodes.copy'),
icon: expensifyIcons.Copy,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.COPY_URL,
onSelected: () => {
if (!moneyRequestReport?.reportID) {
return;
}
Clipboard.setString(`${addTrailingForwardSlash(environmentURL)}${ROUTES.REPORT_WITH_ID.getRoute(moneyRequestReport.reportID)}`);
},
},
];

if (canShareReport(moneyRequestReport, policy, currentUserAccountID)) {
shareSubMenuItems.unshift({
text: translate('common.shareReport'),
icon: expensifyIcons.Mail,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.SHARE_REPORT,
onSelected: () => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.REPORT_DETAILS_SHARE_REPORT.path)),
});
}

return {
[CONST.REPORT.SECONDARY_ACTIONS.SHARE]: {
value: CONST.REPORT.SECONDARY_ACTIONS.SHARE,
text: translate('common.share'),
backButtonText: translate('common.share'),
icon: expensifyIcons.Mail,
rightIcon: expensifyIcons.ArrowRight,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.SHARE,
subMenuItems: shareSubMenuItems,
},
};
}

export default useShareActions;
2 changes: 2 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: 'Das Diagramm konnte nicht geladen werden. Bitte aktualisieren Sie die Seite und versuchen Sie es erneut.',
apiKey: 'API-Schlüssel',
exportsTo: 'Exportiert nach',
shareReport: 'Bericht teilen',
reportShared: 'Bericht geteilt',
},
socials: {
podcast: 'Folgen Sie uns auf Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,8 @@ const translations: TranslationDeepObject<typeof en> = {
other: 'Λήψη αποδείξεων',
}),
commuter: 'επιβάτης καθημερινών μετακινήσεων',
shareReport: 'Κοινοποιήστε την αναφορά',
reportShared: 'Η αναφορά κοινοποιήθηκε',
},
socials: {
podcast: 'Ακολουθήστε μας στο Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ const translations = {
assignee: 'Assignee',
with: 'with',
shareCode: 'Share code',
shareReport: 'Share report',
reportShared: 'Report shared',
share: 'Share',
per: 'per',
// @context Unit label for “mile.” Should be treated as a measurement unit and may require capitalization depending on locale conventions.
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,8 @@ const translations: TranslationDeepObject<typeof en> = {
commuter: 'viajero diario',
noResultsFoundSubtitle: 'Sin resultados. Intenta ajustar tus filtros o la búsqueda.',
exportsTo: 'Exporta a',
shareReport: 'Compartir informe',
reportShared: 'Informe compartido',
},
socials: {
podcast: 'Síguenos en Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: 'Le graphique n’a pas pu être chargé. Veuillez actualiser la page et réessayer.',
apiKey: 'Clé API',
exportsTo: 'Exports vers',
shareReport: 'Partager la note de frais',
reportShared: 'Note de frais partagée',
},
socials: {
podcast: 'Suivez-nous sur Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: 'Impossibile caricare il grafico. Aggiorna la pagina e riprova.',
apiKey: 'Chiave API',
exportsTo: 'Esporta in',
shareReport: 'Condividi report',
reportShared: 'Report condiviso',
},
socials: {
podcast: 'Seguici su Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: 'グラフを読み込めませんでした。ページを再読み込みして、もう一度お試しください。',
apiKey: 'API キー',
exportsTo: 'エクスポート先',
shareReport: 'レポートを共有',
reportShared: 'レポートを共有しました',
},
socials: {
podcast: 'ポッドキャストでフォロー',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: 'De grafiek kon niet worden geladen. Vernieuw de pagina en probeer het opnieuw.',
apiKey: 'API-sleutel',
exportsTo: 'Exporteert naar',
shareReport: 'Rapport delen',
reportShared: 'Rapport gedeeld',
},
socials: {
podcast: 'Volg ons op Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: 'Nie udało się załadować wykresu. Odśwież stronę i spróbuj ponownie.',
apiKey: 'Klucz API',
exportsTo: 'Eksporty do',
shareReport: 'Udostępnij raport',
reportShared: 'Udostępniono raport',
},
socials: {
podcast: 'Śledź nas na Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: 'Não foi possível carregar o gráfico. Atualize a página e tente novamente.',
apiKey: 'Chave de API',
exportsTo: 'Exportações para',
shareReport: 'Compartilhar relatório',
reportShared: 'Relatório compartilhado',
},
socials: {
podcast: 'Siga-nos no Podcast',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ const translations: TranslationDeepObject<typeof en> = {
chartFailedToLoad: '无法加载图表。请刷新页面后重试。',
apiKey: 'API 密钥',
exportsTo: '导出到',
shareReport: '分享报表',
reportShared: '报表已分享',
},
socials: {
podcast: '在播客上关注我们',
Expand Down
7 changes: 7 additions & 0 deletions src/libs/API/parameters/ShareReportParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type ShareReportParams = {
reportID: string;
shareToEmail: string;
permissions: string;
};

export default ShareReportParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ export type {default as ImportPerDiemRatesParams} from './ImportPerDiemRatesPara
export type {default as ExportPerDiemCSVParams} from './ExportPerDiemCSVParams';
export type {default as ExportReportPDFParams} from './ExportReportPDFParams';
export type {default as ExportReportsToPDFParams} from './ExportReportsToPDFParams';
export type {default as ShareReportParams} from './ShareReportParams';
export type {default as ExportReceiptsToZipParams} from './ExportReceiptsToZipParams';
export type {default as UpdateWorkspaceCustomUnitParams} from './UpdateWorkspaceCustomUnitParams';
export type {default as DismissProductTrainingParams} from './DismissProductTraining';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ const WRITE_COMMANDS = {
MOVE_IOU_REPORT_TO_EXISTING_POLICY: 'MoveIOUReportToExistingPolicy',
EXPORT_REPORT_TO_PDF: 'ExportReportToPDF',
EXPORT_REPORTS_TO_PDF: 'ExportReportsToPDF',
SHARE_REPORT: 'ShareReport',
EXPORT_RECEIPTS_TO_ZIP: 'ExportReceiptsToZip',
RENAME_WORKSPACE_CATEGORY: 'RenameWorkspaceCategory',
CREATE_POLICY_TAG: 'CreatePolicyTag',
Expand Down Expand Up @@ -954,6 +955,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.EXPORT_PER_DIEM_CSV]: Parameters.ExportPerDiemCSVParams;
[WRITE_COMMANDS.EXPORT_REPORT_TO_PDF]: Parameters.ExportReportPDFParams;
[WRITE_COMMANDS.EXPORT_REPORTS_TO_PDF]: Parameters.ExportReportsToPDFParams;
[WRITE_COMMANDS.SHARE_REPORT]: Parameters.ShareReportParams;
[WRITE_COMMANDS.EXPORT_RECEIPTS_TO_ZIP]: Parameters.ExportReceiptsToZipParams;
[WRITE_COMMANDS.RENAME_WORKSPACE_CATEGORY]: Parameters.RenameWorkspaceCategoriesParams;
[WRITE_COMMANDS.SET_WORKSPACE_REQUIRES_CATEGORY]: Parameters.SetWorkspaceRequiresCategoryParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ const ReportDetailsModalStackNavigator = createModalStackNavigator<ReportDetails
[SCREENS.REPORT_DETAILS.DYNAMIC_ROOT]: () => require<ReactComponentModule>('../../../../pages/DynamicReportDetailsPage').default,
[SCREENS.REPORT_DETAILS.DYNAMIC_SHARE_CODE]: () => require<ReactComponentModule>('../../../../pages/inbox/report/DynamicReportDetailsShareCodePage').default,
[SCREENS.REPORT_DETAILS.DYNAMIC_EXPORT]: () => require<ReactComponentModule>('../../../../pages/inbox/report/DynamicReportDetailsExportPage').default,
[SCREENS.REPORT_DETAILS.DYNAMIC_SHARE_REPORT]: () => require<ReactComponentModule>('../../../../pages/inbox/report/DynamicReportDetailsShareReportPage').default,
});

const ReportCardActivateStackNavigator = createModalStackNavigator<ReportCardActivateNavigatorParamList>({
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1697,6 +1697,7 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
[SCREENS.REPORT_DETAILS.DYNAMIC_ROOT]: DYNAMIC_ROUTES.REPORT_DETAILS.path,
[SCREENS.REPORT_DETAILS.DYNAMIC_SHARE_CODE]: DYNAMIC_ROUTES.REPORT_DETAILS_SHARE_CODE.path,
[SCREENS.REPORT_DETAILS.DYNAMIC_EXPORT]: DYNAMIC_ROUTES.REPORT_DETAILS_EXPORT.path,
[SCREENS.REPORT_DETAILS.DYNAMIC_SHARE_REPORT]: DYNAMIC_ROUTES.REPORT_DETAILS_SHARE_REPORT.path,
},
},
[SCREENS.RIGHT_MODAL.REPORT_CARD_ACTIVATE]: {
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2285,12 +2285,16 @@ type ReportDetailsNavigatorParamList = {
};
[SCREENS.REPORT_DETAILS.DYNAMIC_SHARE_CODE]: {
reportID: string;
shouldShowQRCodeOnly?: string;
};
[SCREENS.REPORT_DETAILS.DYNAMIC_EXPORT]: {
reportID: string;
policyID: string;
connectionName: ConnectionName;
};
[SCREENS.REPORT_DETAILS.DYNAMIC_SHARE_REPORT]: {
reportID: string;
};
};

type ReportCardActivateNavigatorParamList = {
Expand Down
2 changes: 1 addition & 1 deletion src/libs/PopoverMenuSections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const REPORT_MORE_MENU_SECTIONS = [
],
[REPORT_SECONDARY_ACTIONS.SPLIT, REPORT_SECONDARY_ACTIONS.MERGE, REPORT_SECONDARY_ACTIONS.DUPLICATE_EXPENSE, REPORT_SECONDARY_ACTIONS.MOVE_EXPENSE],
[REPORT_SECONDARY_ACTIONS.DUPLICATE_REPORT, REPORT_SECONDARY_ACTIONS.CHANGE_WORKSPACE, REPORT_SECONDARY_ACTIONS.CHANGE_APPROVER],
[REPORT_SECONDARY_ACTIONS.EXPORT, REPORT_SECONDARY_ACTIONS.DOWNLOAD_PDF, REPORT_SECONDARY_ACTIONS.DOWNLOAD_RECEIPTS, REPORT_SECONDARY_ACTIONS.PRINT],
[REPORT_SECONDARY_ACTIONS.EXPORT, REPORT_SECONDARY_ACTIONS.DOWNLOAD_PDF, REPORT_SECONDARY_ACTIONS.DOWNLOAD_RECEIPTS, REPORT_SECONDARY_ACTIONS.SHARE, REPORT_SECONDARY_ACTIONS.PRINT],
[REPORT_SECONDARY_ACTIONS.VIEW_DETAILS, REPORT_SECONDARY_ACTIONS.DELETE],
];

Expand Down
2 changes: 2 additions & 0 deletions src/libs/ReportSecondaryActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,8 @@ function getSecondaryReportActions({
options.push(CONST.REPORT.SECONDARY_ACTIONS.DOWNLOAD_RECEIPTS);
}

options.push(CONST.REPORT.SECONDARY_ACTIONS.SHARE);

if (!isOpenReportUtils(report)) {
options.push(CONST.REPORT.SECONDARY_ACTIONS.PRINT);
}
Expand Down
11 changes: 11 additions & 0 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13918,6 +13918,16 @@ function canBeExported(report: OnyxEntry<Report>) {
return isExpenseReport(report) && isCorrectState;
}

/**
* Whether the current user can email the report to someone. The submitter, the approver and workspace admins can once the report is submitted.
*/
function canShareReport(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>, currentUserAccountID: number): boolean {
if (!isExpenseReport(report) || isOpenReport(report)) {
return false;
}
return isCurrentUserSubmitter(report, currentUserAccountID) || report?.managerID === currentUserAccountID || isPolicyAdmin(policy);
}

function getIntegrationNameFromExportMessage(reportActions: OnyxEntry<ReportActions> | ReportAction[]) {
if (!reportActions) {
return '';
Expand Down Expand Up @@ -15316,6 +15326,7 @@ export {
findPolicyExpenseChatByPolicyID,
getIntegrationIcon,
canBeExported,
canShareReport,
isExported,
hasExpensifyGuidesEmails,
hasExportError,
Expand Down
Loading
Loading