Update selected item color in Pass menu
[ProtonMail-WebClient.git] / packages / pass / store / reducers / shares.ts
blob0a18f875df8f9827d8d37e34efebc01e349c2594
1 import type { Action, Reducer } from 'redux';
3 import {
4     bootSuccess,
5     getShareAccessOptions,
6     inviteAcceptSuccess,
7     inviteBatchCreateSuccess,
8     inviteRemoveSuccess,
9     newUserInvitePromoteSuccess,
10     newUserInviteRemoveSuccess,
11     shareAccessChange,
12     shareDeleteSync,
13     shareEditMemberAccessSuccess,
14     shareEditSync,
15     shareEvent,
16     shareLeaveSuccess,
17     shareRemoveMemberAccessSuccess,
18     sharedVaultCreated,
19     sharesSync,
20     syncSuccess,
21     vaultCreationSuccess,
22     vaultDeleteSuccess,
23     vaultEditSuccess,
24     vaultTransferOwnershipSuccess,
25 } from '@proton/pass/store/actions';
26 import type { Share } from '@proton/pass/types';
27 import { NewUserInviteState, ShareRole, type ShareType } from '@proton/pass/types';
28 import type { NewUserPendingInvite, PendingInvite, ShareMember } from '@proton/pass/types/data/invites';
29 import { or } from '@proton/pass/utils/fp/predicates';
30 import { objectDelete } from '@proton/pass/utils/object/delete';
31 import { fullMerge, partialMerge } from '@proton/pass/utils/object/merge';
33 export type ShareItem<T extends ShareType = ShareType> = Share<T> & {
34     invites?: PendingInvite[];
35     newUserInvites?: NewUserPendingInvite[];
36     members?: ShareMember[];
39 export type WithItemCount<T> = T & { count: number };
40 export type VaultShareItem = ShareItem<ShareType.Vault>;
42 export type SharesState = { [shareId: string]: ShareItem };
44 export const shares: Reducer<SharesState> = (state = {}, action: Action) => {
45     if (bootSuccess.match(action) && action.payload?.shares !== undefined) return action.payload.shares;
46     if (syncSuccess.match(action)) return action.payload.shares;
47     if (sharesSync.match(action)) return fullMerge(state, action.payload.shares);
49     if (shareEvent.match(action) && state !== null) {
50         const { shareId, Events } = action.payload;
51         const currentEventId = state[shareId].eventId;
53         return Events.LatestEventID === currentEventId
54             ? state
55             : partialMerge(state, {
56                   [action.payload.shareId]: { eventId: action.payload.Events.LatestEventID },
57               });
58     }
60     if (vaultCreationSuccess.match(action)) {
61         const { share } = action.payload;
62         return fullMerge(state, { [share.shareId]: share });
63     }
65     if (vaultEditSuccess.match(action)) {
66         const { share } = action.payload;
67         return partialMerge(state, { [share.shareId]: share });
68     }
70     if (shareEditSync.match(action)) {
71         const { id, share } = action.payload;
72         return fullMerge(state, { [id]: share });
73     }
75     if (or(vaultDeleteSuccess.match, shareDeleteSync.match, shareLeaveSuccess.match)(action)) {
76         return objectDelete(state, action.payload.shareId);
77     }
79     if (vaultTransferOwnershipSuccess.match(action)) {
80         const { shareId, userShareId } = action.payload;
81         const members = (state[shareId].members ?? []).map((member) => {
82             if (member.owner) return { ...member, owner: false };
83             if (member.shareId === userShareId) return { ...member, owner: true };
84             return member;
85         });
87         return partialMerge(state, { [shareId]: { owner: false, shareRoleId: ShareRole.ADMIN, members } });
88     }
90     if (sharedVaultCreated.match(action)) {
91         const { share } = action.payload;
92         return partialMerge(state, { [share.shareId]: share });
93     }
95     if (inviteBatchCreateSuccess.match(action)) partialMerge(state, { [action.payload.shareId]: { shared: true } });
97     if (newUserInvitePromoteSuccess.match(action)) {
98         const { shareId, invites, newUserInvites } = action.payload;
99         const { newUserInvitesReady } = state[shareId];
100         return partialMerge(state, {
101             [shareId]: {
102                 invites,
103                 newUserInvites,
104                 newUserInvitesReady: Math.max(newUserInvitesReady - 1, 0),
105             },
106         });
107     }
109     if (inviteRemoveSuccess.match(action)) {
110         const { shareId, inviteId } = action.payload;
111         const { members = [], invites = [], newUserInvites = [] } = state[shareId];
113         const update = invites.filter((invite) => invite.inviteId !== inviteId);
114         const shared = members.length > 1 || update.length > 0 || newUserInvites.length > 0;
116         return partialMerge(state, { [shareId]: { invites: update, shared } });
117     }
119     if (newUserInviteRemoveSuccess.match(action)) {
120         const { shareId, newUserInviteId } = action.payload;
121         const { members = [], invites = [], newUserInvites = [], newUserInvitesReady } = state[shareId];
123         const update = newUserInvites.filter((invite) => invite.newUserInviteId !== newUserInviteId);
124         const shared = members.length > 1 || invites.length > 0 || update.length > 0;
126         return partialMerge(state, {
127             [shareId]: {
128                 newUserInvites: update,
129                 newUserInvitesReady: Math.max(newUserInvitesReady - 1, 0),
130                 shared,
131             },
132         });
133     }
135     if (shareAccessChange.match(action)) {
136         const { shareId, ...shareAccessOptions } = action.payload;
137         return partialMerge(state, { [shareId]: shareAccessOptions });
138     }
140     if (getShareAccessOptions.success.match(action)) {
141         const { shareId, invites = [], newUserInvites = [], members } = action.payload;
142         const shared = invites.length > 0 || newUserInvites.length > 0 || members.length > 1;
143         const newUserInvitesReady = newUserInvites.filter((invite) => invite.state === NewUserInviteState.READY).length;
145         return partialMerge(state, {
146             [shareId]: {
147                 invites,
148                 members,
149                 newUserInvites,
150                 shared,
151                 newUserInvitesReady,
152             },
153         });
154     }
156     if (shareEditMemberAccessSuccess.match(action)) {
157         const { shareId, userShareId, shareRoleId } = action.payload;
158         const members = state[shareId].members ?? [];
160         return partialMerge(state, {
161             [shareId]: {
162                 members: members.map<ShareMember>((member) =>
163                     member.shareId === userShareId ? { ...member, shareRoleId } : member
164                 ),
165             },
166         });
167     }
169     if (shareRemoveMemberAccessSuccess.match(action)) {
170         const { shareId, userShareId } = action.payload;
171         return partialMerge(state, {
172             [shareId]: {
173                 members: (state[shareId]?.members ?? []).filter(({ shareId }) => shareId !== userShareId),
174             },
175         });
176     }
178     if (inviteAcceptSuccess.match(action)) {
179         return partialMerge(state, { [action.payload.share.shareId]: action.payload.share });
180     }
182     return state;
185 export default shares;