import { action, computed, observable, makeObservable, runInAction } from "mobx"; import { RootStore } from "../root"; // types import { IWorkspaceMember, IWorkspaceMemberInvitation, IWorkspaceBulkInviteFormData } from "types"; // services import { WorkspaceService } from "services/workspace.service"; export interface IWorkspaceMemberStore { // states loader: boolean; error: any | null; // observables members: { [workspaceSlug: string]: IWorkspaceMember[] }; // workspaceSlug: members[] memberInvitations: { [workspaceSlug: string]: IWorkspaceMemberInvitation[] }; // actions fetchWorkspaceMembers: (workspaceSlug: string) => Promise; fetchWorkspaceMemberInvitations: (workspaceSlug: string) => Promise; updateMember: (workspaceSlug: string, memberId: string, data: Partial) => Promise; removeMember: (workspaceSlug: string, memberId: string) => Promise; inviteMembersToWorkspace: (workspaceSlug: string, data: IWorkspaceBulkInviteFormData) => Promise; deleteWorkspaceInvitation: (workspaceSlug: string, memberId: string) => Promise; // computed workspaceMembers: IWorkspaceMember[] | null; workspaceMemberInvitations: IWorkspaceMemberInvitation[] | null; workspaceMembersWithInvitations: any[] | null; } export class WorkspaceMemberStore implements IWorkspaceMemberStore { // states loader: boolean = false; error: any | null = null; // observables members: { [workspaceSlug: string]: IWorkspaceMember[] } = {}; memberInvitations: { [workspaceSlug: string]: IWorkspaceMemberInvitation[] } = {}; // services workspaceService; // root store rootStore; constructor(_rootStore: RootStore) { makeObservable(this, { // states loader: observable.ref, error: observable.ref, // observables members: observable.ref, memberInvitations: observable.ref, // actions fetchWorkspaceMembers: action, fetchWorkspaceMemberInvitations: action, updateMember: action, removeMember: action, inviteMembersToWorkspace: action, deleteWorkspaceInvitation: action, // computed workspaceMembers: computed, workspaceMemberInvitations: computed, workspaceMembersWithInvitations: computed, }); this.rootStore = _rootStore; this.workspaceService = new WorkspaceService(); } /** * computed value of workspace members using the workspace slug from the store */ get workspaceMembers() { if (!this.rootStore.workspace.workspaceSlug) return null; const members = this.members?.[this.rootStore.workspace.workspaceSlug]; if (!members) return null; return members; } /** * Computed value of workspace member invitations using workspace slug from store */ get workspaceMemberInvitations() { if (!this.rootStore.workspace.workspaceSlug) return null; const invitations = this.memberInvitations?.[this.rootStore.workspace.workspaceSlug]; if (!invitations) return null; return invitations; } /** * computed value provides the members information including the invitations. */ get workspaceMembersWithInvitations() { if (!this.workspaceMembers || !this.workspaceMemberInvitations) return null; return [ ...(this.workspaceMemberInvitations?.map((item) => ({ id: item.id, memberId: item.id, avatar: "", first_name: item.email, last_name: "", email: item.email, display_name: item.email, role: item.role, status: item.accepted, member: false, accountCreated: item.accepted, })) || []), ...(this.workspaceMembers?.map((item) => ({ id: item.id, memberId: item.member?.id, avatar: item.member?.avatar, first_name: item.member?.first_name, last_name: item.member?.last_name, email: item.member?.email, display_name: item.member?.display_name, role: item.role, status: true, member: true, accountCreated: true, })) || []), ]; } /** * fetch workspace members using workspace slug * @param workspaceSlug */ fetchWorkspaceMembers = async (workspaceSlug: string) => { try { runInAction(() => { this.loader = true; this.error = null; }); const membersResponse = await this.workspaceService.fetchWorkspaceMembers(workspaceSlug); runInAction(() => { this.members = { ...this.members, [workspaceSlug]: membersResponse, }; this.loader = false; this.error = null; }); } catch (error) { runInAction(() => { this.loader = false; this.error = error; }); } }; /** * fetching workspace member invitations * @param workspaceSlug * @returns */ fetchWorkspaceMemberInvitations = async (workspaceSlug: string) => { try { const membersInvitations = await this.workspaceService.workspaceInvitations(workspaceSlug); runInAction(() => { this.memberInvitations = { ...this.memberInvitations, [workspaceSlug]: membersInvitations, }; }); return membersInvitations; } catch (error) { throw error; } }; /** * invite members to the workspace using emails * @param workspaceSlug * @param data */ inviteMembersToWorkspace = async (workspaceSlug: string, data: IWorkspaceBulkInviteFormData) => { try { await this.workspaceService.inviteWorkspace(workspaceSlug, data); await this.fetchWorkspaceMemberInvitations(workspaceSlug); } catch (error) { throw error; } }; /** * delete the workspace invitation * @param workspaceSlug * @param memberId */ deleteWorkspaceInvitation = async (workspaceSlug: string, memberId: string) => { try { runInAction(() => { this.memberInvitations = { ...this.memberInvitations, [workspaceSlug]: [...this.memberInvitations[workspaceSlug].filter((inv) => inv.id !== memberId)], }; }); await this.workspaceService.deleteWorkspaceInvitations(workspaceSlug.toString(), memberId); } catch (error) { throw error; } }; /** * update workspace member using workspace slug and member id and data * @param workspaceSlug * @param memberId * @param data */ updateMember = async (workspaceSlug: string, memberId: string, data: Partial) => { const originalMembers = [...this.members?.[workspaceSlug]]; // in case of error, we will revert back to original members const members = [...this.members?.[workspaceSlug]]; const index = members.findIndex((m) => m.id === memberId); members[index] = { ...members[index], ...data }; // optimistic update runInAction(() => { this.loader = true; this.error = null; this.members = { ...this.members, [workspaceSlug]: members, }; }); try { await this.workspaceService.updateWorkspaceMember(workspaceSlug, memberId, data); runInAction(() => { this.loader = false; this.error = null; }); } catch (error) { runInAction(() => { this.loader = false; this.error = error; this.members = { ...this.members, [workspaceSlug]: originalMembers, }; }); throw error; } }; /** * remove workspace member using workspace slug and member id * @param workspaceSlug * @param memberId */ removeMember = async (workspaceSlug: string, memberId: string) => { const members = [...this.members?.[workspaceSlug]]; const originalMembers = this.members?.[workspaceSlug]; // in case of error, we will revert back to original members // removing member from the array const index = members.findIndex((m) => m.id === memberId); members.splice(index, 1); // optimistic update runInAction(() => { this.members = { ...this.members, [workspaceSlug]: members, }; }); try { runInAction(() => { this.loader = true; this.error = null; }); await this.workspaceService.deleteWorkspaceMember(workspaceSlug, memberId); runInAction(() => { this.loader = false; this.error = null; }); } catch (error) { runInAction(() => { this.loader = false; this.error = error; this.members = { ...this.members, [workspaceSlug]: originalMembers, }; }); throw error; } }; }