Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
617cb12
feat: Replace Delete with Archive behind the archivePolicies beta
truph01 Aug 7, 2026
2792018
fix: conflicts
truph01 Sep 23, 2026
d1dfcaa
fix: conflicts
truph01 Sep 23, 2026
a12d77f
fix: typecheck
truph01 Sep 23, 2026
06aaeb5
fix: remove mock
truph01 Sep 23, 2026
00cd8c8
fix: lint
truph01 Sep 23, 2026
8608226
Merge branch 'Expensify:main' into feat/97123
truph01 Sep 23, 2026
12df3d9
fix: typecheck
truph01 Sep 23, 2026
ee37909
fix: address review comments on ArchiveWorkspaceFlow
truph01 Sep 23, 2026
0203ff6
fix: align ArchiveWorkspaceFlow with DeleteWorkspaceFlow pre-checks
truph01 Sep 23, 2026
b314afa
fix: remove redundant change
truph01 Sep 23, 2026
3c7bdfb
fix: remove ConfirmModal
truph01 Sep 23, 2026
943228a
Merge branch 'Expensify:main' into feat/97123
truph01 Sep 24, 2026
30fc389
fix: add icon
truph01 Sep 24, 2026
b03991f
fix: svg compress
truph01 Sep 24, 2026
45cf7b4
fix: revert redundant change
truph01 Sep 24, 2026
e3c4bbd
Merge branch 'Expensify:main' into feat/97123
truph01 Sep 29, 2026
ddc2d12
fix: update createOwnedPaidPoliciesCountsSelector
truph01 Sep 29, 2026
07865a2
fix: use archive copy in the outstanding balance guard
truph01 Sep 29, 2026
b6108aa
Merge branch 'Expensify:main' into feat/97123
truph01 Oct 1, 2026
2978fb7
fix: update locales
truph01 Oct 1, 2026
4c66fe6
Merge branch 'Expensify:main' into feat/97123
truph01 Oct 5, 2026
061dffc
fix: add errors field to failureData
truph01 Oct 5, 2026
945bbd1
Merge branch 'Expensify:main' into feat/97123
truph01 Oct 6, 2026
d493b5a
Remove Expensify Card and travel billing archive blockers
truph01 Oct 6, 2026
cd43e81
Remove billing pre-checks from the archive workspace flow
truph01 Oct 6, 2026
6c9aeac
fix: mock data
truph01 Oct 6, 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
2 changes: 1 addition & 1 deletion assets/images/box.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
import usePreferredPolicy from '@hooks/usePreferredPolicy';
import useThemeStyles from '@hooks/useThemeStyles';

Expand Down Expand Up @@ -40,6 +41,9 @@ type WorkspaceRowThreeDotsMenuProps = {
/** Called when the user picks Delete, so the page can mount the delete flow */
onDeleteWorkspace: (policyID: string) => void;

/** Called when the user picks Archive, so the page can mount the archive flow */
onArchiveWorkspace: (policyID: string) => void;

/** ID of the workspace with a deletion in progress, if any */
pendingDeletePolicyID?: string;
};
Expand All @@ -49,12 +53,14 @@ type WorkspaceRowThreeDotsMenuProps = {
* primitive-valued subscriptions, and mounts the leave/transfer flows on demand so their heavier
* subscriptions (the full policy entry) exist only while the corresponding action is in progress.
*/
function WorkspaceRowThreeDotsMenu({item, onDeleteWorkspace, pendingDeletePolicyID}: WorkspaceRowThreeDotsMenuProps) {
function WorkspaceRowThreeDotsMenu({item, onDeleteWorkspace, onArchiveWorkspace, pendingDeletePolicyID}: WorkspaceRowThreeDotsMenuProps) {
const threeDotsMenuRef = useRef<{hidePopoverMenu: () => void; isPopupMenuVisible: boolean}>(null);
const styles = useThemeStyles();
const isFocused = useIsFocused();
const {translate} = useLocalize();
const icons = useMemoizedLazyExpensifyIcons(['Building', 'Exit', 'Plus', 'Copy', 'Star', 'Trashcan', 'Transfer']);
const {isBetaEnabled} = usePermissions();
const icons = useMemoizedLazyExpensifyIcons(['Box', 'Building', 'Exit', 'Plus', 'Copy', 'Star', 'Trashcan', 'Transfer']);
const canArchivePolicies = isBetaEnabled(CONST.BETAS.ARCHIVE_POLICIES);
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
const {isRestrictedToPreferredPolicy, preferredPolicyID} = usePreferredPolicy();
Expand All @@ -66,7 +72,8 @@ function WorkspaceRowThreeDotsMenu({item, onDeleteWorkspace, pendingDeletePolicy
const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED);
const [isLoadingBill] = useOnyx(ONYXKEYS.IS_LOADING_BILL_WHEN_DOWNGRADE);
const [ownedPaidPoliciesCounts] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: createOwnedPaidPoliciesCountsSelector(currentUserPersonalDetails.accountID)});
const shouldCalculateBillNewDot = !!canDowngrade && ownedPaidPoliciesCounts?.total === 1;
// Archiving doesn't change the subscription or bill the user, so the final bill is only calculated when deleting.
const shouldCalculateBillNewDot = !canArchivePolicies && !!canDowngrade && ownedPaidPoliciesCounts?.total === 1;
const wouldBlockDeletion = (amountOwed ?? 0) > 0 && ownedPaidPoliciesCounts?.active === 1;

const [activeAction, setActiveAction] = useState<ActiveAction>();
Expand Down Expand Up @@ -140,10 +147,16 @@ function WorkspaceRowThreeDotsMenu({item, onDeleteWorkspace, pendingDeletePolicy

if (isOwner) {
menuItems.push({
icon: icons.Trashcan,
text: translate('workspace.common.delete'),
shouldShowLoadingSpinnerIcon: !!isLoadingBill && pendingDeletePolicyID === item.policyID,
icon: canArchivePolicies ? icons.Box : icons.Trashcan,
text: translate(canArchivePolicies ? 'workspace.common.archive' : 'workspace.common.delete'),
shouldShowLoadingSpinnerIcon: !canArchivePolicies && !!isLoadingBill && pendingDeletePolicyID === item.policyID,
onSelected: () => {
// The confirmation modal is handled by ArchiveWorkspaceFlow, mounted by the page.
if (canArchivePolicies) {
onArchiveWorkspace(item.policyID);
return;
}

if (isLoadingBill) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ type WorkspaceRowProps = {
/** Called when the user picks Delete in the row menu, so the page can mount the delete flow */
onDeleteWorkspace: (policyID: string) => void;

/** Called when the user picks Archive in the row menu, so the page can mount the archive flow */
onArchiveWorkspace: (policyID: string) => void;

/** ID of the workspace with a deletion in progress, if any */
pendingDeletePolicyID?: string;
};

export default function WorkspaceRow({item, shouldUseNarrowTableLayout, rowIndex, onDeleteWorkspace, pendingDeletePolicyID}: WorkspaceRowProps) {
export default function WorkspaceRow({item, shouldUseNarrowTableLayout, rowIndex, onDeleteWorkspace, onArchiveWorkspace, pendingDeletePolicyID}: WorkspaceRowProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -98,6 +101,7 @@ export default function WorkspaceRow({item, shouldUseNarrowTableLayout, rowIndex
<WorkspaceRowThreeDotsMenu
item={item}
onDeleteWorkspace={onDeleteWorkspace}
onArchiveWorkspace={onArchiveWorkspace}
pendingDeletePolicyID={pendingDeletePolicyID}
/>
</View>
Expand Down
6 changes: 5 additions & 1 deletion src/components/Tables/WorkspaceListTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@ type WorkspaceListTableProps = {
/** Called when the user picks Delete in a row menu, so the page can mount the delete flow */
onDeleteWorkspace: (policyID: string) => void;

/** Called when the user picks Archive in a row menu, so the page can mount the archive flow */
onArchiveWorkspace: (policyID: string) => void;

/** ID of the workspace with a deletion in progress, if any */
pendingDeletePolicyID?: string;
};

export default function WorkspaceListTable({ref, workspaces, headerComponent, onDeleteWorkspace, pendingDeletePolicyID}: WorkspaceListTableProps) {
export default function WorkspaceListTable({ref, workspaces, headerComponent, onDeleteWorkspace, onArchiveWorkspace, pendingDeletePolicyID}: WorkspaceListTableProps) {
const styles = useThemeStyles();
const {translate, localeCompare} = useLocalize();
const {isBetaEnabled} = usePermissions();
Expand Down Expand Up @@ -139,6 +142,7 @@ export default function WorkspaceListTable({ref, workspaces, headerComponent, on
rowIndex={index}
shouldUseNarrowTableLayout={shouldUseNarrowTableLayout}
onDeleteWorkspace={onDeleteWorkspace}
onArchiveWorkspace={onArchiveWorkspace}
pendingDeletePolicyID={pendingDeletePolicyID}
/>
);
Expand Down
6 changes: 6 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4781,6 +4781,12 @@ ${amount} für ${merchant} – ${date}`,
settlementFrequency: 'Auszahlungsfrequenz',
setAsDefault: 'Als Standard-Arbeitsbereich festlegen',
defaultNote: `Belege, die an ${CONST.EMAIL.RECEIPTS} gesendet werden, erscheinen in diesem Workspace.`,
archive: 'Workspace archivieren',
archiveConfirmation: 'Möchten Sie diesen Workspace wirklich archivieren?',
archiveWithThirdPartyCardsConfirmation:
'Möchten Sie diesen Workspace wirklich archivieren? Dadurch werden allen Benutzern die Kreditkarten entzogen und alle nicht eingereichten Kartenausgaben endgültig gelöscht.',
archiveWithExpensifyCardsConfirmation:
Comment thread
truph01 marked this conversation as resolved.
'Möchten Sie diesen Workspace wirklich archivieren? Dadurch werden alle Expensify Card-Limits auf 0 $ gesetzt und neue Kaufversuche automatisch abgelehnt.',
deleteWorkspaceTitle: (workspaceName: string) => `${workspaceName} löschen?`,
deleteConfirmation: 'Möchten Sie diesen Workspace wirklich löschen?',
deleteWithCardsConfirmation: 'Möchtest du diesen Workspace wirklich löschen? Dadurch werden alle Kartenfeeds und zugewiesenen Karten entfernt.',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4849,6 +4849,12 @@ ${amount} για ${merchant} - ${date}`,
settlementFrequency: 'Συχνότητα εκκαθάρισης',
setAsDefault: 'Ορισμός ως προεπιλεγμένου χώρου εργασίας',
defaultNote: `Οι αποδείξεις που αποστέλλονται στο ${CONST.EMAIL.RECEIPTS} θα εμφανίζονται σε αυτόν τον χώρο εργασίας.`,
archive: 'Αρχειοθέτηση χώρου εργασίας',
archiveConfirmation: 'Είστε βέβαιοι ότι θέλετε να αρχειοθετήσετε αυτόν τον χώρο εργασίας;',
archiveWithThirdPartyCardsConfirmation:
'Είστε βέβαιοι ότι θέλετε να αρχειοθετήσετε αυτόν τον χώρο εργασίας; Θα καταργηθεί η ανάθεση όλων των πιστωτικών καρτών από τους χρήστες και θα διαγραφούν οριστικά όσες δαπάνες καρτών δεν έχουν υποβληθεί.',
archiveWithExpensifyCardsConfirmation:
'Είστε βέβαιοι ότι θέλετε να αρχειοθετήσετε αυτόν τον χώρο εργασίας; Όλα τα όρια των Expensify Card θα οριστούν σε $0 και κάθε νέα απόπειρα αγοράς θα απορρίπτεται αυτόματα.',
deleteWorkspaceTitle: (workspaceName: string) => `Διαγραφή του ${workspaceName};`,
deleteConfirmation: 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον χώρο εργασίας;',
deleteWithCardsConfirmation: 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον χώρο εργασίας; Θα αφαιρεθούν όλες οι ροές καρτών και οι ανατεθειμένες κάρτες.',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4920,6 +4920,12 @@ const translations = {
settlementFrequency: 'Settlement frequency',
setAsDefault: 'Set as default workspace',
defaultNote: `Receipts sent to ${CONST.EMAIL.RECEIPTS} will appear in this workspace.`,
archive: 'Archive workspace',
archiveConfirmation: 'Are you sure you want to archive this workspace?',
archiveWithThirdPartyCardsConfirmation:
'Are you sure you want to archive this workspace? This will unassign all credit cards from users and permanently delete any unsubmitted card expenses.',
archiveWithExpensifyCardsConfirmation:
'Are you sure you want to archive this workspace? This will set all Expensify Card limits to $0 and automatically decline any new purchase attempts.',
deleteWorkspaceTitle: (workspaceName: string) => `Delete ${workspaceName}?`,
deleteConfirmation: 'Are you sure you want to delete this workspace?',
deleteWithCardsConfirmation: 'Are you sure you want to delete this workspace? This will remove all card feeds and assigned cards.',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4705,6 +4705,12 @@ ${amount} para ${merchant} - ${date}`,
settlementFrequency: 'Frecuencia de liquidación',
setAsDefault: 'Establecer como espacio de trabajo predeterminado',
defaultNote: `Los recibos enviados a ${CONST.EMAIL.RECEIPTS} aparecerán en este espacio de trabajo.`,
archive: 'Archivar espacio de trabajo',
archiveConfirmation: '¿Estás seguro de que quieres archivar este espacio de trabajo?',
archiveWithThirdPartyCardsConfirmation:
'¿Estás seguro de que quieres archivar este espacio de trabajo? Se desasignarán todas las tarjetas de crédito de los usuarios y se eliminarán permanentemente los gastos de tarjeta no enviados.',
archiveWithExpensifyCardsConfirmation:
'¿Estás seguro de que quieres archivar este espacio de trabajo? Se establecerán todos los límites de las Tarjetas Expensify a $0 y se rechazarán automáticamente los nuevos intentos de compra.',
deleteWorkspaceTitle: (workspaceName: string) => `¿Eliminar ${workspaceName}?`,
deleteConfirmation: '¿Estás seguro de que quieres eliminar este espacio de trabajo?',
deleteWithCardsConfirmation: '¿Estás seguro de que quieres eliminar este espacio de trabajo? Se eliminarán todos los datos de las tarjetas y las tarjetas asignadas.',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4788,6 +4788,12 @@ ${amount} pour ${merchant} - ${date}`,
settlementFrequency: 'Fréquence de règlement',
setAsDefault: 'Définir comme espace de travail par défaut',
defaultNote: `Les reçus envoyés à ${CONST.EMAIL.RECEIPTS} apparaîtront dans cet espace de travail.`,
archive: 'Archiver l’espace de travail',
archiveConfirmation: 'Voulez-vous vraiment archiver cet espace de travail ?',
archiveWithThirdPartyCardsConfirmation:
'Voulez-vous vraiment archiver cet espace de travail ? Cela désassignera toutes les cartes de crédit des utilisateurs et supprimera définitivement toutes les dépenses de carte non soumises.',
archiveWithExpensifyCardsConfirmation:
'Voulez-vous vraiment archiver cet espace de travail ? Cela fixera toutes les limites des Expensify Card à 0 $ et refusera automatiquement toute nouvelle tentative d’achat.',
deleteWorkspaceTitle: (workspaceName: string) => `Supprimer ${workspaceName} ?`,
deleteConfirmation: 'Voulez-vous vraiment supprimer cet espace de travail ?',
deleteWithCardsConfirmation: 'Voulez-vous vraiment supprimer cet espace de travail ? Cela supprimera tous les flux de cartes et les cartes assignées.',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4751,6 +4751,12 @@ ${amount} per ${merchant} - ${date}`,
settlementFrequency: 'Frequenza di regolamento',
setAsDefault: 'Imposta come spazio di lavoro predefinito',
defaultNote: `Le ricevute inviate a ${CONST.EMAIL.RECEIPTS} verranno visualizzate in questo workspace.`,
archive: 'Archivia spazio di lavoro',
archiveConfirmation: 'Sei sicuro di voler archiviare questo spazio di lavoro?',
archiveWithThirdPartyCardsConfirmation:
'Sei sicuro di voler archiviare questo spazio di lavoro? Questa azione annullerà l’assegnazione di tutte le carte di credito agli utenti ed eliminerà definitivamente le spese con carta non inviate.',
archiveWithExpensifyCardsConfirmation:
'Sei sicuro di voler archiviare questo spazio di lavoro? Questa azione imposterà tutti i limiti delle Expensify Card a 0 $ e rifiuterà automaticamente qualsiasi nuovo tentativo di acquisto.',
deleteWorkspaceTitle: (workspaceName: string) => `Eliminare ${workspaceName}?`,
deleteConfirmation: 'Sei sicuro di voler eliminare questo spazio di lavoro?',
deleteWithCardsConfirmation: 'Sei sicuro di voler eliminare questo spazio di lavoro? Questa azione rimuoverà tutti i feed delle carte e le carte assegnate.',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4716,6 +4716,12 @@ ${integrationName === CONST.ONBOARDING_ACCOUNTING_MAPPING.other ? 'あなたの'
settlementFrequency: '清算頻度',
setAsDefault: 'デフォルトのワークスペースに設定',
defaultNote: `${CONST.EMAIL.RECEIPTS} に送信されたレシートは、このワークスペースに表示されます。`,
archive: 'ワークスペースをアーカイブ',
archiveConfirmation: 'このワークスペースをアーカイブしてもよろしいですか?',
archiveWithThirdPartyCardsConfirmation:
'このワークスペースをアーカイブしてもよろしいですか? すべてのクレジットカードのユーザーへの割り当てが解除され、未申請のカード経費は完全に削除されます。',
archiveWithExpensifyCardsConfirmation:
'このワークスペースをアーカイブしてもよろしいですか? すべての Expensify カードの利用限度額が $0 に設定され、新しい購入はすべて自動的に拒否されます。',
deleteWorkspaceTitle: (workspaceName: string) => `${workspaceName} を削除しますか?`,
deleteConfirmation: 'このワークスペースを削除してもよろしいですか?',
deleteWithCardsConfirmation: 'このワークスペースを削除してもよろしいですか? すべてのカードフィードと割り当て済みカードが削除されます。',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4752,6 +4752,12 @@ ${amount} voor ${merchant} - ${date}`,
settlementFrequency: 'Uitbetalingsfrequentie',
setAsDefault: 'Instellen als standaardwerkruimte',
defaultNote: `Bonnetjes die naar ${CONST.EMAIL.RECEIPTS} worden gestuurd, verschijnen in deze workspace.`,
archive: 'Werkruimte archiveren',
archiveConfirmation: 'Weet je zeker dat je deze werkruimte wilt archiveren?',
archiveWithThirdPartyCardsConfirmation:
'Weet je zeker dat je deze werkruimte wilt archiveren? Hiermee worden alle creditcards van gebruikers losgekoppeld en worden alle niet-ingediende kaartuitgaven permanent verwijderd.',
archiveWithExpensifyCardsConfirmation:
'Weet je zeker dat je deze werkruimte wilt archiveren? Hiermee worden alle Expensify Card-limieten op $0 gezet en worden nieuwe aankooppogingen automatisch geweigerd.',
deleteWorkspaceTitle: (workspaceName: string) => `${workspaceName} verwijderen?`,
deleteConfirmation: 'Weet je zeker dat je deze werkruimte wilt verwijderen?',
deleteWithCardsConfirmation: 'Weet je zeker dat je deze werkruimte wilt verwijderen? Hiermee worden alle kaartfeeds en toegewezen kaarten verwijderd.',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4781,6 +4781,12 @@ ${amount} dla ${merchant} - ${date}`,
settlementFrequency: 'Częstotliwość rozliczeń',
setAsDefault: 'Ustaw jako domyślne miejsce pracy',
defaultNote: `Paragony wysłane na ${CONST.EMAIL.RECEIPTS} pojawią się w tym obszarze roboczym.`,
archive: 'Zarchiwizuj przestrzeń roboczą',
archiveConfirmation: 'Czy na pewno chcesz zarchiwizować tę przestrzeń roboczą?',
archiveWithThirdPartyCardsConfirmation:
'Czy na pewno chcesz zarchiwizować tę przestrzeń roboczą? Spowoduje to anulowanie przypisania wszystkich kart kredytowych użytkownikom i trwałe usunięcie nieprzesłanych wydatków z kart.',
archiveWithExpensifyCardsConfirmation:
'Czy na pewno chcesz zarchiwizować tę przestrzeń roboczą? Spowoduje to ustawienie wszystkich limitów Expensify Card na $0 i automatyczne odrzucanie nowych prób zakupu.',
deleteWorkspaceTitle: (workspaceName: string) => `Usunąć ${workspaceName}?`,
deleteConfirmation: 'Czy na pewno chcesz usunąć tę przestrzeń roboczą?',
deleteWithCardsConfirmation: 'Na pewno chcesz usunąć tę przestrzeń roboczą? Spowoduje to usunięcie wszystkich źródeł kart i przypisanych kart.',
Expand Down
Loading
Loading