Compare commits
3 Commits
e43ab6cfe1
...
b48c834d36
Author | SHA1 | Date | |
---|---|---|---|
|
b48c834d36 | ||
|
8cb1271f9a | ||
|
0b950ba7a7 |
@ -13,29 +13,38 @@ import { Request, Response } from "express";
|
|||||||
import statusCodes from "../utils/statusCodes";
|
import statusCodes from "../utils/statusCodes";
|
||||||
import logger from "../system/Logger";
|
import logger from "../system/Logger";
|
||||||
|
|
||||||
export const validateCreateAccount = ajv.compile(createAccountSchema);
|
|
||||||
export const validateGetAccounts = ajv.compile(getAccountSchema);
|
|
||||||
export const validateGetRooms = ajv.compile(getRoomSchema);
|
|
||||||
export const validateGetMessages = ajv.compile(getMessagesSchema);
|
|
||||||
export const validateGetMembers = ajv.compile(getMembersSchema);
|
|
||||||
export const validateSetFlag = ajv.compile(setFlagSchema);
|
|
||||||
|
|
||||||
class Validator {
|
class Validator {
|
||||||
|
validateCreateAccount: any;
|
||||||
|
validateGetAccounts: any;
|
||||||
|
validateGetRooms: any;
|
||||||
|
validateGetMessages: any;
|
||||||
|
validateGetMembers: any;
|
||||||
|
validateSetFlag: any;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.validateCreateAccount = ajv.compile(createAccountSchema);
|
||||||
|
this.validateGetAccounts = ajv.compile(getAccountSchema);
|
||||||
|
this.validateGetRooms = ajv.compile(getRoomSchema);
|
||||||
|
this.validateGetMessages = ajv.compile(getMessagesSchema);
|
||||||
|
this.validateGetMembers = ajv.compile(getMembersSchema);
|
||||||
|
this.validateSetFlag = ajv.compile(setFlagSchema);
|
||||||
|
}
|
||||||
|
|
||||||
_getSchema(name: string): any {
|
_getSchema(name: string): any {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "createAccount":
|
case "createAccount":
|
||||||
return validateCreateAccount;
|
return this.validateCreateAccount;
|
||||||
case "getAccounts":
|
case "getAccounts":
|
||||||
return validateGetAccounts;
|
return this.validateGetAccounts;
|
||||||
case "getRooms":
|
case "getRooms":
|
||||||
return validateGetRooms;
|
return this.validateGetRooms;
|
||||||
case "getMessages":
|
case "getMessages":
|
||||||
return validateGetMessages;
|
return this.validateGetMessages;
|
||||||
case "getMembers":
|
case "getMembers":
|
||||||
return validateGetMembers;
|
return this.validateGetMembers;
|
||||||
case "addFlag":
|
case "addFlag":
|
||||||
case "removeFlag":
|
case "removeFlag":
|
||||||
return validateSetFlag;
|
return this.validateSetFlag;
|
||||||
default:
|
default:
|
||||||
logger.err(`Schema ${name} not found`);
|
logger.err(`Schema ${name} not found`);
|
||||||
break;
|
break;
|
||||||
@ -59,4 +68,4 @@ class Validator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const validator = new Validator();
|
const validator = new Validator();
|
||||||
export default validator;
|
export default validator;
|
||||||
|
@ -110,7 +110,7 @@ function mailChange() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<button @click="modal = true">Open Modal!</button>
|
<button @click="modal = true">Add Account</button>
|
||||||
<Modal v-if="modal" title="Add new account" @close-modal="modal = false">
|
<Modal v-if="modal" title="Add new account" @close-modal="modal = false">
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
@ -10,8 +10,6 @@ import { isSeenFc } from "@/utils/flagsUtils";
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
msg: Object as PropType<Message>,
|
msg: Object as PropType<Message>,
|
||||||
members: Array as PropType<Address[]>,
|
members: Array as PropType<Address[]>,
|
||||||
mailboxId: Number,
|
|
||||||
roomId: Number,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayAddresses = (addressIds: string[] | undefined): string => {
|
const displayAddresses = (addressIds: string[] | undefined): string => {
|
||||||
@ -66,7 +64,7 @@ const classes = (): string => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="content" :class="[classes()]">
|
<div class="content" :class="[classes()]">
|
||||||
<Content :content="props.msg?.content" />
|
<Content :content="props.msg?.content" />
|
||||||
<Options class="options" :mailboxId="props.mailboxId" :roomId="props.roomId" :msg="props.msg" />
|
<Options class="options" :msg="props.msg" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, PropType } from "vue";
|
import { defineProps, inject, PropType } from "vue";
|
||||||
import { Message } from "@/store/models/model";
|
import { Message } from "@/store/models/model";
|
||||||
import API from "@/services/imapAPI";
|
import API from "@/services/imapAPI";
|
||||||
import store from "@/store/store";
|
import store from "@/store/store";
|
||||||
@ -7,24 +7,24 @@ import { isSeenFc } from "@/utils/flagsUtils";
|
|||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
msg: Object as PropType<Message>,
|
msg: Object as PropType<Message>,
|
||||||
mailboxId: Number,
|
|
||||||
roomId: Number,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const room: any = inject("room");
|
||||||
|
|
||||||
const setFlag = (flag: string) => {
|
const setFlag = (flag: string) => {
|
||||||
// todo loading
|
// todo loading
|
||||||
if (!props.mailboxId || !props.msg) return;
|
if (!room?.value || !props.msg) return;
|
||||||
let apiCall = isSeenFc(props.msg?.flags) ? API.removeFlag : API.addFlag;
|
let apiCall = isSeenFc(props.msg?.flags) ? API.removeFlag : API.addFlag;
|
||||||
apiCall({
|
apiCall({
|
||||||
mailboxId: props.mailboxId,
|
mailboxId: room.value?.mailboxId,
|
||||||
messageId: props.msg?.id,
|
messageId: props.msg?.id,
|
||||||
flag: flag,
|
flag: flag,
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (isSeenFc(props.msg?.flags)) {
|
if (isSeenFc(props.msg?.flags)) {
|
||||||
store.commit("removeFlag", { roomId: props.roomId, messageId: props.msg?.id, flag: flag });
|
store.commit("removeFlag", { roomId: room.value?.id, messageId: props.msg?.id, flag: flag });
|
||||||
} else {
|
} else {
|
||||||
store.commit("addFlag", { roomId: props.roomId, messageId: props.msg?.id, flag: flag });
|
store.commit("addFlag", { roomId: room.value?.id, messageId: props.msg?.id, flag: flag });
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -23,7 +23,6 @@ export enum LoadingState {
|
|||||||
loaded = 2,
|
loaded = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo store messages outside of the room
|
|
||||||
export interface Room {
|
export interface Room {
|
||||||
id: number;
|
id: number;
|
||||||
roomName: string;
|
roomName: string;
|
||||||
@ -33,8 +32,6 @@ export interface Room {
|
|||||||
userId: number;
|
userId: number;
|
||||||
members: Address[];
|
members: Address[];
|
||||||
notSeen: number;
|
notSeen: number;
|
||||||
messages: Message[];
|
|
||||||
messageLoading: LoadingState;
|
|
||||||
threadIds: number[];
|
threadIds: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import API from "@/services/imapAPI";
|
import API from "@/services/imapAPI";
|
||||||
|
import { isSeenFc } from "@/utils/flagsUtils";
|
||||||
import { decodeEmojis } from "@/utils/string";
|
import { decodeEmojis } from "@/utils/string";
|
||||||
import { AxiosError, AxiosResponse } from "axios";
|
import { AxiosError, AxiosResponse } from "axios";
|
||||||
import { createStore } from "vuex";
|
import { createStore } from "vuex";
|
||||||
@ -33,30 +34,61 @@ function createRoom(options: RoomFromBack): Room {
|
|||||||
members: [],
|
members: [],
|
||||||
user: options.user,
|
user: options.user,
|
||||||
notSeen: options.notSeen,
|
notSeen: options.notSeen,
|
||||||
messages: [],
|
|
||||||
messageLoading: LoadingState.notLoaded,
|
|
||||||
threadIds: [],
|
threadIds: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface State {
|
interface roomMessage {
|
||||||
rooms: Room[];
|
roomId: number;
|
||||||
accounts: Account[];
|
fetch: LoadingState;
|
||||||
activeAccount: number;
|
messages: Message[];
|
||||||
activeRoom: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const roomOnId = (state: State, roomId: number) => state.rooms.find((room: Room) => room.id == roomId);
|
export interface State {
|
||||||
|
accounts: Account[];
|
||||||
|
activeAccount: number;
|
||||||
|
rooms: Room[];
|
||||||
|
activeRoom: number;
|
||||||
|
roomMessages: roomMessage[];
|
||||||
|
}
|
||||||
|
|
||||||
// // define injection key todo
|
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()
|
// export const key: InjectionKey<Store<State>> = Symbol()
|
||||||
|
|
||||||
const store = createStore<State>({
|
const store = createStore<State>({
|
||||||
state: {
|
state: {
|
||||||
rooms: [], //createRoom({ id: 12, userId: 1, user: "user", roomName: "room name", mailboxId: 2, roomType: 1 })
|
|
||||||
accounts: [{ id: 0, email: "All", fetched: false }],
|
accounts: [{ id: 0, email: "All", fetched: false }],
|
||||||
activeAccount: 0,
|
activeAccount: 0,
|
||||||
|
rooms: [],
|
||||||
activeRoom: 0,
|
activeRoom: 0,
|
||||||
|
roomMessages: [],
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setActiveAccount(state, payload) {
|
setActiveAccount(state, payload) {
|
||||||
@ -69,7 +101,15 @@ const store = createStore<State>({
|
|||||||
// todo load room on load page
|
// todo load room on load page
|
||||||
const room = state.rooms.find((room) => room.id == payload);
|
const room = state.rooms.find((room) => room.id == payload);
|
||||||
if (!room) return;
|
if (!room) return;
|
||||||
store.dispatch("fetchMessages", { roomId: payload, room: room });
|
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) {
|
addAccounts(state, payload) {
|
||||||
payload.forEach((account: AccountFromBack) => {
|
payload.forEach((account: AccountFromBack) => {
|
||||||
@ -98,9 +138,16 @@ const store = createStore<State>({
|
|||||||
// todo add if not exist
|
// todo add if not exist
|
||||||
const room = roomOnId(state, payload.roomId);
|
const room = roomOnId(state, payload.roomId);
|
||||||
if (!room) return;
|
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) => {
|
payload.messages.forEach((message: any) => {
|
||||||
message.flags = message.flags?.split(",") ?? [];
|
message.flags = message.flags?.split(",") ?? [];
|
||||||
room.messages.push(message);
|
roomMessage?.messages.push(message);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
addAddress(state, payload) {
|
addAddress(state, payload) {
|
||||||
@ -112,16 +159,17 @@ const store = createStore<State>({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
addFlag(state, payload) {
|
addFlag(state, payload) {
|
||||||
// todo if seen notif
|
const msg = msgOnRoomId(state, payload.roomId)?.messages.find((msg) => msg.id == payload.messageId);
|
||||||
const msg = roomOnId(state, payload.roomId)?.messages.find((msg) => msg.id == payload.messageId);
|
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg.flags.push(payload.flag);
|
msg.flags.push(payload.flag);
|
||||||
|
updateSeen(state, payload.roomId, payload.flag, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeFlag(state, payload) {
|
removeFlag(state, payload) {
|
||||||
const msg = roomOnId(state, payload.roomId)?.messages.find((msg) => msg.id == payload.messageId);
|
const msg = msgOnRoomId(state, payload.roomId)?.messages.find((msg) => msg.id == payload.messageId);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg.flags?.splice(msg.flags?.indexOf(payload.flag), 1);
|
msg.flags?.splice(msg.flags?.indexOf(payload.flag), 1);
|
||||||
|
updateSeen(state, payload.roomId, payload.flag, false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -147,12 +195,11 @@ const store = createStore<State>({
|
|||||||
messages:
|
messages:
|
||||||
(state) =>
|
(state) =>
|
||||||
(roomId: number): Message[] => {
|
(roomId: number): Message[] => {
|
||||||
const room = roomOnId(state, roomId);
|
const roomMessage = msgOnRoomId(state, roomId);
|
||||||
if (!room) return [];
|
if (roomMessage) return roomMessage.messages;
|
||||||
if (room.messageLoading === LoadingState.notLoaded) {
|
state.roomMessages.push({ messages: [], roomId: roomId, fetch: LoadingState.notLoaded });
|
||||||
store.dispatch("fetchMessages", { roomId: room.id, room: room });
|
store.dispatch("fetchMessages", { roomId: roomId, obj: msgOnRoomId(state, roomId) });
|
||||||
}
|
return msgOnRoomId(state, roomId)?.messages ?? [];
|
||||||
return room.messages;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -178,16 +225,16 @@ const store = createStore<State>({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchMessages: async (context, data) => {
|
fetchMessages: async (context, data) => {
|
||||||
if (!data.room || data.room.messageLoading === LoadingState.notLoaded) {
|
if (data.obj.fetch === LoadingState.notLoaded) {
|
||||||
data.room.messageLoading = LoadingState.loading;
|
data.obj.fetch = LoadingState.loading;
|
||||||
store.dispatch("fetchRoomMembers", { roomId: data.roomId });
|
store.dispatch("fetchRoomMembers", { roomId: data.roomId });
|
||||||
API.getMessages(data.roomId)
|
API.getMessages(data.roomId)
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
data.room.messageLoading = LoadingState.loaded;
|
data.obj.fetch = LoadingState.loaded;
|
||||||
context.commit("addMessages", { messages: res.data, roomId: data.roomId });
|
context.commit("addMessages", { messages: res.data, roomId: data.roomId });
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
data.room.messageLoading = LoadingState.notLoaded;
|
data.obj.fetch = LoadingState.notLoaded;
|
||||||
console.log(err);
|
console.log(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import { useRoute, onBeforeRouteUpdate } from "vue-router";
|
import { useRoute, onBeforeRouteUpdate } from "vue-router";
|
||||||
import { onBeforeMount, ref } from "vue";
|
import { onBeforeMount, provide, ref } from "vue";
|
||||||
|
import { RoomType } from "@/store/models/model";
|
||||||
import Header from "./Header.vue";
|
import Header from "./Header.vue";
|
||||||
import Message from "../../components/structure/message/Message.vue";
|
import Message from "../../components/structure/message/Message.vue";
|
||||||
import { Room, RoomType } from "@/store/models/model";
|
|
||||||
import MessageViewModal from "@/components/modals/MessageViewModal.vue";
|
import MessageViewModal from "@/components/modals/MessageViewModal.vue";
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@ -12,29 +12,34 @@ const route = useRoute();
|
|||||||
const messageIdView = ref(-1);
|
const messageIdView = ref(-1);
|
||||||
const message = ref(undefined);
|
const message = ref(undefined);
|
||||||
const id = ref(parseInt(route.params.id));
|
const id = ref(parseInt(route.params.id));
|
||||||
let room;
|
let room = ref();
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
store.commit("setActiveRoom", id.value);
|
store.commit("setActiveRoom", id.value);
|
||||||
room = store.getters.room(id.value);
|
room.value = store.getters.room(id.value);
|
||||||
|
console.log(room.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeRouteUpdate(async (to, from) => {
|
onBeforeRouteUpdate(async (to, from) => {
|
||||||
if (to.params.id !== from.params.id) {
|
if (to.params.id !== from.params.id) {
|
||||||
id.value = parseInt(to.params.id);
|
id.value = parseInt(to.params.id);
|
||||||
store.commit("setActiveRoom", id.value);
|
store.commit("setActiveRoom", id.value);
|
||||||
room = await store.getters.room(id.value);
|
room.value = await store.getters.room(id.value);
|
||||||
|
console.log(room.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const shouldDisplayComposer = () => {
|
const shouldDisplayComposer = () => {
|
||||||
if (!room) return false;
|
if (!room?.value) return false;
|
||||||
return room.roomType == RoomType.THREAD || room.roomType == RoomType.GROUP;
|
return room.value.roomType == RoomType.THREAD || room.value.roomType == RoomType.GROUP;
|
||||||
};
|
};
|
||||||
|
|
||||||
function openMessageView(id) {
|
function openMessageView(id) {
|
||||||
messageIdView.value = id;
|
messageIdView.value = id;
|
||||||
message.value = room?.messages.find((message) => message.id == id);
|
message.value = room.value?.messages.find((message) => message.id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
provide("room", room);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -43,12 +48,10 @@ function openMessageView(id) {
|
|||||||
<div id="RoomViewBody">
|
<div id="RoomViewBody">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<Message
|
<Message
|
||||||
v-for="(message, index) in room?.messages"
|
v-for="(message, index) in store.getters.messages(room?.id)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:msg="message"
|
:msg="message"
|
||||||
:members="room?.members"
|
:members="room?.members"
|
||||||
:mailboxId="room.mailboxId"
|
|
||||||
:roomId="room.id"
|
|
||||||
@open-message-view="(id) => openMessageView(id)"
|
@open-message-view="(id) => openMessageView(id)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user