mail/front/src/store/store.ts
2023-04-13 16:43:44 +02:00

255 lines
9.0 KiB
TypeScript

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<Store<State>> = Symbol()
const store = createStore<State>({
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;