Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Comment thread
shawnborton marked this conversation as resolved.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,8 @@ const CONST = {
BULK_EDIT: 'bulkEdit',
NEW_MANUAL_EXPENSE_FLOW: 'newManualExpenseFlow',
SUBMIT_2026: 'submit2026',
BULK_SUBMIT_APPROVE_PAY: 'bulkSubmitApprovePay',
WORKSPACE_ROOMS_PAGE: 'workspaceRoomsPage',
CERTINIA: 'financialForceNewDot',
},
BUTTON_STATES: {
Expand Down Expand Up @@ -9464,6 +9466,7 @@ const CONST = {
INITIAL: {
PROFILE: 'WorkspaceInitial-Profile',
MEMBERS: 'WorkspaceInitial-Members',
ROOMS: 'WorkspaceInitial-Rooms',
REPORTS: 'WorkspaceInitial-Reports',
ACCOUNTING: 'WorkspaceInitial-Accounting',
HR: 'WorkspaceInitial-HR',
Expand Down
9 changes: 9 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2293,6 +2293,15 @@ const ROUTES = {
return `workspaces/${policyID}/members` as const;
},
},
WORKSPACE_ROOMS: {
route: 'workspaces/:policyID/rooms',
getRoute: (policyID: string | undefined) => {
if (!policyID) {
Log.warn('Invalid policyID is used to build the WORKSPACE_ROOMS route');
}
return `workspaces/${policyID}/rooms` as const;
},
},
WORKSPACE_MEMBERS_IMPORT: {
route: 'workspaces/:policyID/members/import',
getRoute: (policyID: string) => `workspaces/${policyID}/members/import` 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 @@ -752,6 +752,7 @@ const SCREENS = {
INVOICES_COMPANY_NAME: 'Workspace_Invoices_Company_Name',
INVOICES_COMPANY_WEBSITE: 'Workspace_Invoices_Company_Website',
MEMBERS: 'Workspace_Members',
ROOMS: 'Workspace_Rooms',
MEMBERS_IMPORT: 'Members_Import',
MEMBERS_IMPORTED: 'Members_Imported',
MEMBERS_IMPORTED_CONFIRMATION: 'Members_Imported_Confirmation',
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/chunks/illustrations.chunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ import FolderOpen from '@assets/images/simple-illustrations/simple-illustration_
import FoodTruck from '@assets/images/simple-illustrations/simple-illustration__foodtruck-tacos.svg';
import Gears from '@assets/images/simple-illustrations/simple-illustration__gears.svg';
import HandCard from '@assets/images/simple-illustrations/simple-illustration__handcard.svg';
import Hashtag from '@assets/images/simple-illustrations/simple-illustration__hashtag.svg';
import HeadSet from '@assets/images/simple-illustrations/simple-illustration__headset.svg';
import Hourglass from '@assets/images/simple-illustrations/simple-illustration__hourglass.svg';
import House from '@assets/images/simple-illustrations/simple-illustration__house.svg';
Expand Down Expand Up @@ -316,6 +317,7 @@ const Illustrations = {
CreditCardsNew,
FolderOpen,
HandCard,
Hashtag,
InvoiceBlue,
MagnifyingGlassMoney,
MagnifyingGlassReceipt,
Expand Down
1 change: 1 addition & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4355,6 +4355,7 @@ ${amount} für ${merchant} – ${date}`,
travelInvoicingVendor: 'Reiseanbieter',
travelInvoicingPayableAccount: 'Reiseverbindlichkeitskonto',
hr: 'Personalwesen',
rooms: 'Räume',
},
createdForClient: {
title: 'Du hast einen Workspace für deinen Kunden erstellt!',
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4317,6 +4317,7 @@ const translations = {
perDiem: 'Per diem',
travel: 'Travel',
members: 'Members',
rooms: 'Rooms',
accounting: 'Accounting',
hr: 'HR',
receiptPartners: 'Receipt partners',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4119,6 +4119,7 @@ ${amount} para ${merchant} - ${date}`,
perDiem: 'Per diem',
travel: 'Viajes',
members: 'Miembros',
rooms: 'Salas',
accounting: 'Contabilidad',
hr: 'HR',
receiptPartners: 'Socios de recibos',
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4364,6 +4364,7 @@ ${amount} pour ${merchant} - ${date}`,
travelInvoicingVendor: 'Fournisseur de voyages',
travelInvoicingPayableAccount: 'Compte fournisseur déplacements',
hr: 'RH',
rooms: 'Salons',
},
createdForClient: {
title: 'Vous avez créé un espace de travail pour votre client !',
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4341,6 +4341,7 @@ ${amount} per ${merchant} - ${date}`,
travelInvoicingVendor: 'Fornitore di viaggi',
travelInvoicingPayableAccount: 'Conto debiti per viaggi',
hr: 'Risorse umane',
rooms: 'Stanze',
},
createdForClient: {
title: 'Hai creato uno spazio di lavoro per il tuo cliente!',
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4308,6 +4308,7 @@ ${integrationName === CONST.ONBOARDING_ACCOUNTING_MAPPING.other ? 'あなたの'
travelInvoicingVendor: '出張ベンダー',
travelInvoicingPayableAccount: '旅費未払金勘定',
hr: '人事',
rooms: 'ルーム',
},
createdForClient: {
title: 'クライアントのワークスペースを作成しました!',
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4336,6 +4336,7 @@ ${amount} voor ${merchant} - ${date}`,
travelInvoicingVendor: 'Reisaanbieder',
travelInvoicingPayableAccount: 'Reiscrediteurenrekening',
hr: 'HR',
rooms: 'Kamers',
},
createdForClient: {
title: 'Je hebt een werkruimte voor je klant aangemaakt!',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4329,6 +4329,7 @@ ${amount} dla ${merchant} - ${date}`,
travelInvoicingVendor: 'Dostawca usług turystycznych',
travelInvoicingPayableAccount: 'Konto zobowiązań z tytułu podróży',
hr: 'HR',
rooms: 'Pokoje',
},
createdForClient: {
title: 'Utworzyłeś przestrzeń roboczą dla swojego klienta!',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4331,6 +4331,7 @@ ${amount} para ${merchant} - ${date}`,
travelInvoicingVendor: 'Fornecedor de viagem',
travelInvoicingPayableAccount: 'Conta a pagar de viagens',
hr: 'RH',
rooms: 'Salas',
},
createdForClient: {
title: 'Você criou um espaço de trabalho para seu cliente!',
Expand Down
1 change: 1 addition & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4239,6 +4239,7 @@ ${amount},商户:${merchant} - 日期:${date}`,
travelInvoicingVendor: '差旅供应商',
travelInvoicingPayableAccount: '差旅应付账户',
hr: '人力资源',
rooms: '房间',
},
createdForClient: {
title: '您已为客户创建了工作区!',
Expand Down
5 changes: 5 additions & 0 deletions src/libs/API/parameters/OpenWorkspaceRoomsPageParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type OpenWorkspaceRoomsPageParams = {
policyID: string;
};

export default OpenWorkspaceRoomsPageParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export type {default as ConnectPolicyToFinancialForceParams} from './ConnectPoli
export type {default as UpdateFinancialForceGenericTypeParams} from './UpdateFinancialForceGenericTypeParams';
export type {default as OpenWorkspaceInvitePageParams} from './OpenWorkspaceInvitePageParams';
export type {default as OpenWorkspaceMembersPageParams} from './OpenWorkspaceMembersPageParams';
export type {default as OpenWorkspaceRoomsPageParams} from './OpenWorkspaceRoomsPageParams';
export type {default as OpenPolicyCategoriesPageParams} from './OpenPolicyCategoriesPageParams';
export type {default as OpenPolicyTagsPageParams} from './OpenPolicyTagsPageParams';
export type {default as VerifyAddSecondaryLoginCodeParams} from './VerifyAddSecondaryLoginCodeParams';
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 @@ -1291,6 +1291,7 @@ const READ_COMMANDS = {
GET_POLICY_CATEGORIES: 'GetPolicyCategories',
OPEN_WORKSPACE: 'OpenWorkspace',
OPEN_WORKSPACE_MEMBERS_PAGE: 'OpenWorkspaceMembersPage',
OPEN_WORKSPACE_ROOMS_PAGE: 'OpenWorkspaceRoomsPage',
OPEN_POLICY_MEMBER_PROFILE_PAGE: 'OpenPolicyMemberProfilePage',
OPEN_POLICY_CATEGORIES_PAGE: 'OpenPolicyCategoriesPage',
OPEN_POLICY_TAGS_PAGE: 'OpenPolicyTagsPage',
Expand Down Expand Up @@ -1391,6 +1392,7 @@ type ReadCommandParameters = {
[READ_COMMANDS.GET_POLICY_CATEGORIES]: Parameters.GetPolicyCategoriesParams;
[READ_COMMANDS.OPEN_WORKSPACE]: Parameters.OpenWorkspaceParams;
[READ_COMMANDS.OPEN_WORKSPACE_MEMBERS_PAGE]: Parameters.OpenWorkspaceMembersPageParams;
[READ_COMMANDS.OPEN_WORKSPACE_ROOMS_PAGE]: Parameters.OpenWorkspaceRoomsPageParams;
[READ_COMMANDS.OPEN_POLICY_MEMBER_PROFILE_PAGE]: Parameters.OpenPolicyMemberProfilePageParams;
[READ_COMMANDS.OPEN_POLICY_CATEGORIES_PAGE]: Parameters.OpenPolicyCategoriesPageParams;
[READ_COMMANDS.OPEN_POLICY_TAGS_PAGE]: Parameters.OpenPolicyTagsPageParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = {
[SCREENS.WORKSPACE.WORKFLOWS]: () => require<ReactComponentModule>('../../../../pages/workspace/workflows/WorkspaceWorkflowsPage').default,
[SCREENS.WORKSPACE.INVOICES]: () => require<ReactComponentModule>('../../../../pages/workspace/invoices/WorkspaceInvoicesPage').default,
[SCREENS.WORKSPACE.MEMBERS]: () => require<ReactComponentModule>('../../../../pages/workspace/WorkspaceMembersPage').default,
[SCREENS.WORKSPACE.ROOMS]: () => require<ReactComponentModule>('../../../../pages/workspace/rooms/WorkspaceRoomsPage').default,
[SCREENS.WORKSPACE.ACCOUNTING.ROOT]: () => require<ReactComponentModule>('../../../../pages/workspace/accounting/PolicyAccountingPage').default,
[SCREENS.WORKSPACE.HR]: () => require<ReactComponentModule>('../../../../pages/workspace/hr/WorkspaceHRPage').default,
[SCREENS.WORKSPACE.CATEGORIES]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/WorkspaceCategoriesPage').default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const WORKSPACE_TO_RHP: Partial<Record<keyof WorkspaceSplitNavigatorParamList, s
SCREENS.WORKSPACE.MEMBERS_IMPORTED,
SCREENS.WORKSPACE.MEMBERS_IMPORTED_CONFIRMATION,
],
[SCREENS.WORKSPACE.ROOMS]: [],
[SCREENS.WORKSPACE.WORKFLOWS]: [
SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW,
SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT,
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 @@ -2340,6 +2340,9 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
[SCREENS.WORKSPACE.MEMBERS]: {
path: ROUTES.WORKSPACE_MEMBERS.route,
},
[SCREENS.WORKSPACE.ROOMS]: {
path: ROUTES.WORKSPACE_ROOMS.route,
},
[SCREENS.WORKSPACE.ACCOUNTING.ROOT]: {
path: ROUTES.POLICY_ACCOUNTING.route,
},
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2776,6 +2776,9 @@ type WorkspaceSplitNavigatorParamList = {
[SCREENS.WORKSPACE.MEMBERS]: {
policyID: string;
};
[SCREENS.WORKSPACE.ROOMS]: {
policyID: string;
};
[SCREENS.WORKSPACE.CATEGORIES]: {
policyID: string;
// eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md
Expand Down
15 changes: 15 additions & 0 deletions src/libs/actions/Policy/Room.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {read} from '@libs/API';
import type {OpenWorkspaceRoomsPageParams} from '@libs/API/parameters';
import {READ_COMMANDS} from '@libs/API/types';
import Log from '@libs/Log';

export default function openWorkspaceRoomsPage(policyID: string) {
if (!policyID) {
Log.warn('openWorkspaceRoomsPage invalid params', {policyID});
return;
}

const params: OpenWorkspaceRoomsPageParams = {policyID};

read(READ_COMMANDS.OPEN_WORKSPACE_ROOMS_PAGE, params);
}
11 changes: 11 additions & 0 deletions src/pages/workspace/WorkspaceInitialPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
'Feed',
'Folder',
'Gear',
'Hashtag',
'InvoiceGeneric',
'Receipt',
'Sync',
Expand Down Expand Up @@ -231,6 +232,16 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
},
];

if (isBetaEnabled(CONST.BETAS.WORKSPACE_ROOMS_PAGE)) {
workspaceMenuItems.push({
translationKey: 'workspace.common.rooms',
icon: expensifyIcons.Hashtag,
action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_ROOMS.getRoute(policyID)))),
screenName: SCREENS.WORKSPACE.ROOMS,
sentryLabel: CONST.SENTRY_LABEL.WORKSPACE.INITIAL.ROOMS,
});
}

if (isGroupPolicy(policy) && shouldShowProtectedItems) {
workspaceMenuItems.push({
translationKey: 'common.reports',
Expand Down
72 changes: 72 additions & 0 deletions src/pages/workspace/rooms/WorkspaceRoomsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {useFocusEffect} from '@react-navigation/native';
import React from 'react';
import Button from '@components/Button';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import usePermissions from '@hooks/usePermissions';
import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import useWorkspaceDocumentTitle from '@hooks/useWorkspaceDocumentTitle';
import openWorkspaceRoomsPage from '@libs/actions/Policy/Room';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {WorkspaceSplitNavigatorParamList} from '@navigation/types';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import CONST from '@src/CONST';
import type SCREENS from '@src/SCREENS';

type WorkspaceRoomsPageProps = PlatformStackScreenProps<WorkspaceSplitNavigatorParamList, typeof SCREENS.WORKSPACE.ROOMS>;

function WorkspaceRoomsPage({route}: WorkspaceRoomsPageProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {isBetaEnabled} = usePermissions();
const icons = useMemoizedLazyExpensifyIcons(['Plus']);
const illustrations = useMemoizedLazyIllustrations(['Hashtag']);
const policyID = route.params.policyID;
const policy = usePolicy(policyID);
useWorkspaceDocumentTitle(policy?.name, 'workspace.common.rooms');

useFocusEffect(() => {
openWorkspaceRoomsPage(policyID);
});
Comment on lines +34 to +36
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wrap rooms focus effect in useCallback

useFocusEffect is being passed an inline function, so while this screen is focused the effect is re-registered on every render and openWorkspaceRoomsPage(policyID) is called repeatedly. Any normal re-render trigger (Onyx updates, layout changes, permission changes) can therefore fire multiple redundant OpenWorkspaceRoomsPage reads instead of one per focus, which adds unnecessary API traffic and can cause noisy loading behavior.

Useful? React with 👍 / 👎.


return (
<AccessOrNotFoundWrapper
policyID={policyID}
shouldBeBlocked={!isBetaEnabled(CONST.BETAS.WORKSPACE_ROOMS_PAGE)}
>
<ScreenWrapper
testID={WorkspaceRoomsPage.displayName}
style={[styles.defaultModalContainer]}
shouldEnableMaxHeight
shouldShowOfflineIndicatorInWideScreen
enableEdgeToEdgeBottomSafeAreaPadding
>
Comment on lines +43 to +49
Copy link
Copy Markdown
Contributor

@jakubstec jakubstec May 13, 2026

Choose a reason for hiding this comment

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

i think we should add shouldShowOfflineIndicatorInWideScreen here, as well as enableEdgeToEdgeBottomSafeAreaPadding, like the rest of the workspace related pages do

<HeaderWithBackButton
title={translate('workspace.common.rooms')}
icon={illustrations.Hashtag}
shouldUseHeadlineHeader
shouldShowBackButton={shouldUseNarrowLayout}
onBackButtonPress={Navigation.goBack}
shouldDisplayHelpButton
>
<Button
success
onPress={() => {}}
icon={icons.Plus}
text={translate('common.create')}
/>
Comment on lines +58 to +63
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wire or hide the Create button

When beta users open the new Rooms page, the visible Create button is wired to an empty handler, so pressing it appears broken and gives no navigation or feedback. Either connect this to the existing create-room flow described for the page or hide/disable the button until that flow exists.

Useful? React with 👍 / 👎.

</HeaderWithBackButton>
</ScreenWrapper>
</AccessOrNotFoundWrapper>
);
}

WorkspaceRoomsPage.displayName = 'WorkspaceRoomsPage';

export default WorkspaceRoomsPage;
Loading