1// Copyright (C) 2019 Storj Labs, Inc.
2// See LICENSE for copying information.
3
4import { StoreModule } from '@/store';
5import { SortDirection } from '@/types/common';
6import {
7    ProjectMember,
8    ProjectMemberCursor,
9    ProjectMemberOrderBy,
10    ProjectMembersApi,
11    ProjectMembersPage,
12} from '@/types/projectMembers';
13
14export const PROJECT_MEMBER_MUTATIONS = {
15    FETCH: 'fetchProjectMembers',
16    TOGGLE_SELECTION: 'toggleSelection',
17    CLEAR_SELECTION: 'clearSelection',
18    CLEAR: 'clearProjectMembers',
19    CHANGE_SORT_ORDER: 'changeProjectMembersSortOrder',
20    CHANGE_SORT_ORDER_DIRECTION: 'changeProjectMembersSortOrderDirection',
21    SET_SEARCH_QUERY: 'setProjectMembersSearchQuery',
22    SET_PAGE: 'setProjectMembersPage',
23};
24
25const {
26    FETCH,
27    TOGGLE_SELECTION,
28    CLEAR_SELECTION,
29    CLEAR,
30    CHANGE_SORT_ORDER,
31    CHANGE_SORT_ORDER_DIRECTION,
32    SET_SEARCH_QUERY,
33    SET_PAGE,
34} = PROJECT_MEMBER_MUTATIONS;
35
36export class ProjectMembersState {
37    public cursor: ProjectMemberCursor = new ProjectMemberCursor();
38    public page: ProjectMembersPage = new ProjectMembersPage();
39    public selectedProjectMembersEmails: string[] = [];
40}
41
42interface ProjectMembersContext {
43    state: ProjectMembersState
44    commit: (string, ...unknown) => void
45    rootGetters: {
46        selectedProject: {
47            id: string
48        }
49    }
50}
51
52export function makeProjectMembersModule(api: ProjectMembersApi): StoreModule<ProjectMembersState, ProjectMembersContext> {
53    return {
54        state: new ProjectMembersState(),
55        mutations: {
56            [FETCH](state: ProjectMembersState, page: ProjectMembersPage) {
57                state.page = page;
58                state.page.projectMembers = state.page.projectMembers.map(member => {
59                    if (state.selectedProjectMembersEmails.includes(member.user.email)) {
60                        member.isSelected = true;
61                    }
62
63                    return member;
64                });
65            },
66            [SET_PAGE](state: ProjectMembersState, page: number) {
67                state.cursor.page = page;
68            },
69            [SET_SEARCH_QUERY](state: ProjectMembersState, search: string) {
70                state.cursor.search = search;
71            },
72            [CHANGE_SORT_ORDER](state: ProjectMembersState, order: ProjectMemberOrderBy) {
73                state.cursor.order = order;
74            },
75            [CHANGE_SORT_ORDER_DIRECTION](state: ProjectMembersState, direction: SortDirection) {
76                state.cursor.orderDirection = direction;
77            },
78            [CLEAR](state: ProjectMembersState) {
79                state.cursor = new ProjectMemberCursor();
80                state.page = new ProjectMembersPage();
81                state.selectedProjectMembersEmails = [];
82            },
83            [TOGGLE_SELECTION](state: ProjectMembersState, projectMember: ProjectMember) {
84                if (!state.selectedProjectMembersEmails.includes(projectMember.user.email)) {
85                    projectMember.isSelected = true;
86                    state.selectedProjectMembersEmails.push(projectMember.user.email);
87
88                    return;
89                }
90
91                projectMember.isSelected = false;
92                state.selectedProjectMembersEmails = state.selectedProjectMembersEmails.filter(projectMemberEmail => {
93                    return projectMemberEmail !== projectMember.user.email;
94                });
95            },
96            [CLEAR_SELECTION](state: ProjectMembersState) {
97                state.selectedProjectMembersEmails = [];
98                state.page.projectMembers = state.page.projectMembers.map((projectMember: ProjectMember) => {
99                    projectMember.isSelected = false;
100
101                    return projectMember;
102                });
103            },
104        },
105        actions: {
106            addProjectMembers: async function ({rootGetters}: ProjectMembersContext, emails: string[]): Promise<void> {
107                const projectId = rootGetters.selectedProject.id;
108
109                await api.add(projectId, emails);
110            },
111            deleteProjectMembers: async function ({rootGetters, state, commit}: ProjectMembersContext): Promise<void> {
112                const projectId = rootGetters.selectedProject.id;
113
114                await api.delete(projectId, state.selectedProjectMembersEmails);
115
116                commit(CLEAR_SELECTION);
117            },
118            fetchProjectMembers: async function ({commit, rootGetters, state}: ProjectMembersContext, page: number): Promise<ProjectMembersPage> {
119                const projectID = rootGetters.selectedProject.id;
120
121                commit(SET_PAGE, page);
122
123                const projectMembersPage: ProjectMembersPage = await api.get(projectID, state.cursor);
124
125                commit(FETCH, projectMembersPage);
126
127                return projectMembersPage;
128            },
129            setProjectMembersSearchQuery: function ({commit}: ProjectMembersContext, search: string) {
130                commit(SET_SEARCH_QUERY, search);
131            },
132            setProjectMembersSortingBy: function ({commit}: ProjectMembersContext, order: ProjectMemberOrderBy) {
133                commit(CHANGE_SORT_ORDER, order);
134            },
135            setProjectMembersSortingDirection: function ({commit}: ProjectMembersContext, direction: SortDirection) {
136                commit(CHANGE_SORT_ORDER_DIRECTION, direction);
137            },
138            clearProjectMembers: function ({commit}: ProjectMembersContext) {
139                commit(CLEAR);
140                commit(CLEAR_SELECTION);
141            },
142            toggleProjectMemberSelection: function ({commit}: ProjectMembersContext, projectMember: ProjectMember) {
143                commit(TOGGLE_SELECTION, projectMember);
144            },
145            clearProjectMemberSelection: function ({commit}: ProjectMembersContext) {
146                commit(CLEAR_SELECTION);
147            },
148        },
149        getters: {
150            selectedProjectMembers: (state: ProjectMembersState) =>
151                state.page.projectMembers.filter((member: ProjectMember) =>
152                    state.selectedProjectMembersEmails.includes(member.user.email)),
153        },
154    };
155}
156