1 import type { Selector } from '@reduxjs/toolkit';
2 import { createSelector } from '@reduxjs/toolkit';
4 import { isActive } from '@proton/pass/lib/items/item.predicates';
5 import { isVaultShare } from '@proton/pass/lib/shares/share.predicates';
7 hasNewUserInvitesReady,
11 } from '@proton/pass/lib/vaults/vault.predicates';
12 import type { Maybe, MaybeNull, ShareType } from '@proton/pass/types';
13 import { first } from '@proton/pass/utils/array/first';
14 import { prop } from '@proton/pass/utils/fp/lens';
15 import { and, not } from '@proton/pass/utils/fp/predicates';
16 import { sortOn } from '@proton/pass/utils/fp/sort';
18 import type { ShareItem, VaultShareItem } from '../reducers';
19 import type { State } from '../types';
20 import { SelectorError } from './errors';
21 import { selectAllItems, selectItems } from './items';
23 export const selectShares = ({ shares }: State) => shares;
25 export const selectAllShares = createSelector(selectShares, (shares) => Object.values(shares));
27 /* vaults returned from this selector are always
28 * sorted alphabetically by ascending vault name */
29 export const selectAllVaults = createSelector([selectAllShares], (shares) =>
30 shares.filter(isVaultShare).sort((a, b) => a.content.name.localeCompare(b.content.name))
33 export const selectWritableVaults = createSelector([selectAllVaults], (vaults) => vaults.filter(isWritableVault));
34 export const selectNonOwnedVaults = createSelector([selectAllVaults], (vaults) => vaults.filter(not(isOwnVault)));
35 export const selectOwnWritableVaults = createSelector([selectAllVaults], (vaults) =>
36 vaults.filter(and(isWritableVault, isOwnVault))
38 export const selectOwnReadOnlyVaults = createSelector([selectAllVaults], (vaults) =>
39 vaults.filter(and(not(isWritableVault), isOwnVault))
42 export const selectWritableSharedVaults = createSelector([selectAllVaults], (vaults) =>
43 vaults.filter(and(isWritableVault, isSharedVault))
46 const createVaultsWithItemsCountSelector = (vaultSelector: Selector<State, VaultShareItem[]>) =>
47 createSelector([vaultSelector, selectItems], (shares, itemsByShareId) =>
48 shares.map((share) => ({
50 count: Object.values(itemsByShareId?.[share.shareId] ?? {}).filter(isActive).length,
54 export const selectVaultsWithItemsCount = createVaultsWithItemsCountSelector(selectAllVaults);
55 export const selectWritableVaultsWithItemsCount = createVaultsWithItemsCountSelector(selectWritableVaults);
56 export const selectWritableSharedVaultsWithItemsCount = createVaultsWithItemsCountSelector(selectWritableSharedVaults);
58 export const selectShare =
59 <T extends ShareType = ShareType>(shareId?: MaybeNull<string>) =>
60 ({ shares }: State) =>
61 (shareId ? shares?.[shareId] : undefined) as Maybe<ShareItem<T>>;
63 export const selectIsWritableShare =
65 (state: State): boolean => {
66 const share = selectShare(shareId)(state);
67 return Boolean(share && isWritableVault(share));
70 export const selectShareOrThrow =
71 <T extends ShareType = ShareType>(shareId: string) =>
72 (state: State): ShareItem<T> => {
73 const share = selectShare<T>(shareId)(state);
74 if (!share) throw new SelectorError(`Share ${shareId} not found`);
79 export const selectVaultItemsCount = (shareId: MaybeNull<string>) =>
81 selectShare<ShareType.Vault>(shareId),
83 (share, itemsByShareId): MaybeNull<number> =>
84 share ? Object.values(itemsByShareId?.[share?.shareId] ?? {}).filter(isActive).length : null
87 export const selectVaultSharedWithEmails = (shareId: string) =>
89 selectShare<ShareType.Vault>(shareId),
90 (vault): Set<string> =>
92 (vault?.members?.map(prop('email')) ?? [])
93 .concat(vault?.invites?.map(prop('invitedEmail')) ?? [])
94 .concat(vault?.newUserInvites?.map(prop('invitedEmail')) ?? [])
98 /* The default vault should be the oldest vault I own and can write to */
99 export const selectDefaultVault = createSelector(
100 selectOwnWritableVaults,
101 (ownWritableVaults): Maybe<VaultShareItem> => first(ownWritableVaults.sort(sortOn('createTime', 'ASC')))
104 /** Resolves the most recently used vault:
105 * - Returns shareId of the latest item in user's writable vaults, sorted by creation time
106 * - Falls back to user's default vault shareId if no writable items found */
107 export const selectMostRecentVaultShareID = createSelector(
108 [selectOwnWritableVaults, selectAllItems, selectDefaultVault],
109 (vaults, items, defaultVault): Maybe<string> => {
110 const shareIds = new Set(vaults.map(prop('shareId')));
112 items.filter((item) => shareIds.has(item.shareId)).sort(sortOn('createTime'))?.[0]?.shareId ??
113 defaultVault?.shareId
118 export const selectVaultsWithNewUserInvites = createSelector([selectOwnWritableVaults], (vaults) =>
119 vaults.filter(hasNewUserInvitesReady)