import API from "@/services/imapAPI"; import { isSeenFc } from "@/utils/flagsUtils"; import { decodeEmojis } from "@/utils/string"; import { AxiosError, AxiosResponse } from "axios"; import { createStore } from "vuex"; import { Room, Account, Address, RoomType, Message, LoadingState } from "./models/model"; interface RoomFromBack { id: number; roomName: string; roomType: RoomType; mailboxId: number; user: string; userId: number; notSeen: number; parent_id?: number; // todo thread } interface AccountFromBack { id: number; email: string; } const buffer: RoomFromBack[] = []; function createRoom(options: RoomFromBack): Room { return { id: options.id, roomName: decodeEmojis(options.roomName), roomType: options.roomType, mailboxId: options.mailboxId, userId: options.userId, members: [], user: options.user, notSeen: options.notSeen, threadIds: [], }; } interface roomMessage { roomId: number; fetch: LoadingState; messages: Message[]; } export interface State { accounts: Account[]; activeAccount: number; rooms: Room[]; activeRoom: number; roomMessages: roomMessage[]; } const roomOnId = (state: State, roomId: number): Room | undefined => state.rooms.find((room: Room) => room.id == roomId); const msgOnRoomId = (state: State, roomId: number) => state.roomMessages.find((roomMsg) => roomMsg.roomId == roomId); function updateSeen(state: State, roomId: number, flag: string[], adding: boolean) { // if is seen flag decrement unread value if (isSeenFc(flag)) { const room = roomOnId(state, roomId); if (!room) return; if (adding) { room.notSeen--; } else { room.notSeen++; } // if is thread change seen on parent if (room.roomType == RoomType.THREAD) { const parentRoom = state.rooms.find((room) => room.threadIds.includes(roomId)); if (parentRoom) { if (adding) { parentRoom.notSeen--; } else { parentRoom.notSeen++; } } } } } // define injection key todo // export const key: InjectionKey> = Symbol() const store = createStore({ state: { accounts: [{ id: 0, email: "All", fetched: false }], activeAccount: 0, rooms: [], activeRoom: 0, roomMessages: [], }, mutations: { setActiveAccount(state, payload) { state.activeAccount = payload; const account = state.accounts.find((account) => account.id == payload); store.dispatch("fetchRooms", { accountId: payload, account: account }); }, setActiveRoom(state, payload) { state.activeRoom = payload; // todo load room on load page const room = state.rooms.find((room) => room.id == payload); if (!room) return; let roomMessage = msgOnRoomId(state, payload); if (!roomMessage) { state.roomMessages.push({ messages: [], fetch: LoadingState.notLoaded, roomId: payload }); roomMessage = msgOnRoomId(state, payload); } store.dispatch("fetchMessages", { roomId: payload, obj: roomMessage, }); }, addAccounts(state, payload) { payload.forEach((account: AccountFromBack) => { state.accounts.push({ id: account.id, email: account.email, fetched: false }); }); }, addRooms(state, payload) { // todo add if not exist payload.rooms.forEach((room: RoomFromBack) => { if (room.roomType == RoomType.THREAD) { buffer.push(room); } state.rooms.push(createRoom(room)); }); buffer.forEach((thread) => { const parentRoom = state.rooms.find((room) => room.id == thread.parent_id); // todo debug parent_id to root_id if (parentRoom) { parentRoom.threadIds.push(thread.id); } else { console.log("yep..."); } }); }, addMessages(state, payload) { // todo add if not exist const room = roomOnId(state, payload.roomId); if (!room) return; let roomMessage = msgOnRoomId(state, payload.roomId); if (!roomMessage) { state.roomMessages.push({ roomId: payload.roomId, messages: [], fetch: LoadingState.notLoaded }); roomMessage = msgOnRoomId(state, payload.roomId); } if (!roomMessage) return; payload.messages.forEach((message: any) => { message.flags = message.flags?.split(",") ?? []; roomMessage?.messages.push(message); }); }, addAddress(state, payload) { // todo add if not exist const room = roomOnId(state, payload.roomId); if (!room) return; payload.addresses.forEach((address: Address) => { room.members.push(address); }); }, addFlag(state, payload) { const msg = msgOnRoomId(state, payload.roomId)?.messages.find((msg) => msg.id == payload.messageId); if (msg) { msg.flags.push(payload.flag); updateSeen(state, payload.roomId, payload.flag, true); } }, removeFlag(state, payload) { const msg = msgOnRoomId(state, payload.roomId)?.messages.find((msg) => msg.id == payload.messageId); if (msg) { msg.flags?.splice(msg.flags?.indexOf(payload.flag), 1); updateSeen(state, payload.roomId, payload.flag, false); } }, }, getters: { rooms: (state) => (): Room[] => { if (state.activeAccount === 0) return state.rooms; return state.rooms.filter( (room) => room.mailboxId == state.activeAccount && room.roomType != RoomType.THREAD, ); }, room: (state) => (roomId: number): Room | undefined => { return roomOnId(state, roomId); }, address: (state) => (roomId: number, addressId: number): Address | undefined => { const room = roomOnId(state, roomId); const address = room?.members.find((address) => address.id == addressId); return address; }, messages: (state) => (roomId: number): Message[] => { const roomMessage = msgOnRoomId(state, roomId); if (roomMessage) return roomMessage.messages; state.roomMessages.push({ messages: [], roomId: roomId, fetch: LoadingState.notLoaded }); store.dispatch("fetchMessages", { roomId: roomId, obj: msgOnRoomId(state, roomId) }); return msgOnRoomId(state, roomId)?.messages ?? []; }, }, actions: { fetchAccounts: async (context) => { API.getAccounts() .then((res: AxiosResponse) => { context.commit("addAccounts", res.data); }) .catch((err: AxiosError) => { console.log(err); }); }, fetchRooms: async (context, data) => { if (data.account?.fetched == false) { API.getRooms(data.accountId) .then((res: AxiosResponse) => { data.account.fetched = true; context.commit("addRooms", { rooms: res.data }); }) .catch((err: AxiosError) => { console.log(err); }); } }, fetchMessages: async (context, data) => { if (data.obj.fetch === LoadingState.notLoaded) { data.obj.fetch = LoadingState.loading; store.dispatch("fetchRoomMembers", { roomId: data.roomId }); API.getMessages(data.roomId) .then((res: AxiosResponse) => { data.obj.fetch = LoadingState.loaded; context.commit("addMessages", { messages: res.data, roomId: data.roomId }); }) .catch((err: AxiosError) => { data.obj.fetch = LoadingState.notLoaded; console.log(err); }); } }, fetchRoomMembers: async (context, data) => { API.getMembers(data.roomId) .then((res: AxiosResponse) => { context.commit("addAddress", { addresses: res.data, roomId: data.roomId }); }) .catch((err: AxiosError) => { console.log(err); }); }, }, }); export default store;