import copy from 'copy-to-clipboard'; import { action, makeAutoObservable, observable } from 'mobx'; import { toast } from 'react-toastify'; import { userService } from 'App/services'; import User from './types/user'; export default class UserStore { list: User[] = []; instance: User | null = null; page: number = 1; pageSize: number = 10; searchQuery: string = ''; modifiedCount: number = 0; loading: boolean = false; saving: boolean = false; limits: any = {}; initialDataFetched: boolean = false; constructor() { makeAutoObservable(this, { instance: observable, updateUser: action, updateKey: action, initUser: action, setLimits: action, }); } fetchLimits(): Promise { return new Promise((resolve, reject) => { userService .getLimits() .then((response: any) => { this.setLimits(response); resolve(response); }) .catch((error: any) => { reject(error); }); }); } setLimits(limits: any) { this.limits = limits; } initUser(user?: any): Promise { return new Promise((resolve) => { if (user) { this.instance = new User().fromJson(user.toJson()); } else { this.instance = new User(); } resolve(); }); } updateKey(key: keyof this, value: any) { this[key] = value; if (key === 'searchQuery') { this.page = 1; } } updateUser(user: User) { const index = this.list.findIndex((u) => u.userId === user.userId); if (index > -1) { this.list[index] = user; } } fetchUser(userId: string): Promise { this.loading = true; return new Promise((resolve, reject) => { userService .one(userId) .then((response) => { this.instance = new User().fromJson(response.data); resolve(response); }) .catch((error) => { this.loading = false; reject(error); }) .finally(() => { this.loading = false; }); }); } fetchUsers(): Promise { this.loading = true; return new Promise((resolve, reject) => { userService .all() .then((response) => { this.list = response.map((user) => new User().fromJson(user)); resolve(response); }) .catch((error) => { this.loading = false; reject(error); }) .finally(() => { this.loading = false; }); }); } saveUser(user: User): Promise { this.saving = true; const wasCreating = !user.userId; return new Promise((resolve, reject) => { userService .save(user) .then((response) => { const newUser = new User().fromJson(response); if (wasCreating) { this.modifiedCount -= 1; this.list.push(newUser); toast.success('User created successfully'); } else { this.updateUser(newUser); toast.success('User updated successfully'); } resolve(response); }) .catch(async (e) => { const err = await e.response?.json(); this.saving = false; const errStr = err.errors[0] ? err.errors[0].includes('already exists') ? `This email is already linked to an account or team on OpenReplay and can't be used again.` : err.errors[0] : 'Error saving user'; toast.error(errStr); reject(e); }) .finally(() => { this.saving = false; }); }); } deleteUser(userId: string): Promise { this.saving = true; return new Promise((resolve, reject) => { userService .delete(userId) .then((response) => { this.modifiedCount += 1; this.list = this.list.filter((user) => user.userId !== userId); resolve(response); }) .catch((error) => { this.saving = false; toast.error('Error deleting user'); reject(error); }) .finally(() => { this.saving = false; }); }); } copyInviteCode(userId: string): void { const content = this.list.find((u) => u.userId === userId)?.invitationLink; if (content) { copy(content); toast.success('Invite code copied successfully'); } else { toast.error('Invite code not found'); } } generateInviteCode(userId: string): Promise { this.saving = true; const promise = new Promise((resolve, reject) => { userService .generateInviteCode(userId) .then((response) => { const index = this.list.findIndex((u) => u.userId === userId); if (index > -1) { this.list[index].updateKey('isExpiredInvite', false); this.list[index].updateKey( 'invitationLink', response.invitationLink ); } resolve(response); }) .catch((error) => { this.saving = false; reject(error); }) .finally(() => { this.saving = false; }); }); toast.promise(promise, { pending: 'Generating an invite code...', success: 'Invite code generated successfully', }); return promise; } }