Compare commits

...

3 Commits

Author SHA1 Message Date
grimhilt
7e0e27c2b6 show members in a room 2023-04-07 00:50:59 +02:00
grimhilt
7c98c1eb0c restructure members storage in rooms store 2023-04-06 20:24:11 +02:00
grimhilt
8c6a2bcfd7 show notifications front 2023-04-06 13:09:47 +02:00
14 changed files with 119 additions and 86 deletions

View File

@ -103,10 +103,13 @@ export async function getMembers(roomId) {
SELECT
address.address_id AS id,
address.address_name AS name,
address.email AS email
FROM app_room_member
INNER JOIN address ON address.address_id = app_room_member.member_id
WHERE app_room_member.room_id = ?
address.email AS email,
field_name.field_name as type
FROM app_room
INNER JOIN address_field ON address_field.message_id = app_room.message_id
INNER JOIN address ON address.address_id = address_field.address_id
INNER JOIN field_name ON field_name.field_id = address_field.field_id
WHERE app_room.room_id = ?;
`;
const values = [roomId];
return await execQueryAsync(query, values);

View File

@ -153,6 +153,7 @@ CREATE TABLE app_room_message (
);
-- 14
-- todo needed ?
CREATE TABLE app_room_member (
room_id INT NOT NULL,
member_id INT NOT NULL,

View File

@ -76,6 +76,7 @@ export default class RegisterMessageInApp {
}
async incrementNotSeen(roomId: number) {
// todo it appears there is an error with notifications
if (!this.isSeen) {
await incrementNotSeenRoom(roomId);
}

View File

@ -13,11 +13,11 @@ export default {
},
color: {
type: String,
default: "#007bff",
},
type: {
type: String,
default: "badge-primary",
number: "badge-number",
},
},
};
@ -41,5 +41,8 @@ export default {
background-color: #007bff;
}
/* add more type classes for other types/colors */
.badge-number {
color: var(--primary-text);
background-color: #4d5970;
}
</style>

View File

@ -7,7 +7,10 @@ export enum RoomType {
}
export interface Message {
todo: true;
fromA: string;
subject: string;
content: string;
date: string;
}
export enum LoadingState {
@ -23,7 +26,8 @@ export interface Room {
mailboxId: number;
user: string;
userId: number;
unseen: number;
members: Address[];
notSeen: number;
messages: Message[];
messageLoading: LoadingState;
threadIds: number[];
@ -39,4 +43,5 @@ export interface Address {
id: number;
name: string | null;
email: string;
type: string;
}

View File

@ -11,7 +11,7 @@ interface RoomFromBack {
mailboxId: number;
user: string;
userId: number;
unseen: number;
notSeen: number;
parent_id?: number;
// todo thread
}
@ -30,8 +30,9 @@ function createRoom(options: RoomFromBack): Room {
roomType: options.roomType,
mailboxId: options.mailboxId,
userId: options.userId,
members: [],
user: options.user,
unseen: 0,
notSeen: options.notSeen,
messages: [],
messageLoading: LoadingState.notLoaded,
threadIds: [],
@ -41,7 +42,6 @@ function createRoom(options: RoomFromBack): Room {
export interface State {
rooms: Room[];
accounts: Account[];
addresses: Address[];
activeAccount: number;
activeRoom: number;
}
@ -53,12 +53,11 @@ const store = createStore<State>({
state: {
rooms: [], //createRoom({ id: 12, userId: 1, user: "user", roomName: "room name", mailboxId: 2, roomType: 1 })
accounts: [{ id: 0, email: "All", fetched: false }],
addresses: [],
activeAccount: 0,
activeRoom: 0,
},
mutations: {
setactiveAccount(state, payload) {
setActiveAccount(state, payload) {
state.activeAccount = payload;
const account = state.accounts.find((account) => account.id == payload);
store.dispatch("fetchRooms", { accountId: payload, account: account });
@ -66,18 +65,9 @@ const store = createStore<State>({
setActiveRoom(state, payload) {
state.activeRoom = payload;
// todo load room on load page
// let room;
// // const room = state.rooms.find((room) => room.id == payload);
// console.log(state.rooms.length);
// for (let i = 0; i < state.rooms.length; i++) {
// console.log(state.rooms[i].id, payload.value);
// if (state.rooms[i].id == payload.value) {
// room = state.rooms[i];
// break;
// }
// }
// console.log(room);
// store.dispatch("fetchMessages", { roomId: payload, room: room });
const room = state.rooms.find((room) => room.id == payload);
if (!room) return;
store.dispatch("fetchMessages", { roomId: payload, room: room });
},
addAccounts(state, payload) {
payload.forEach((account: AccountFromBack) => {
@ -97,7 +87,6 @@ const store = createStore<State>({
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);
console.log(parentRoom);
} else {
console.log("yep...");
}
@ -113,8 +102,10 @@ const store = createStore<State>({
},
addAddress(state, payload) {
// todo add if not exist
const room = state.rooms.find((room) => room.id == payload.roomId);
if (!room) return;
payload.addresses.forEach((address: Address) => {
state.addresses.push(address);
room.members.push(address);
});
},
},
@ -133,8 +124,9 @@ const store = createStore<State>({
},
address:
(state) =>
(addressId: number): Address | undefined => {
const address = state.addresses.find((address) => address.id == addressId);
(roomId: number, addressId: number): Address | undefined => {
const room = state.rooms.find((room) => room.id == roomId);
const address = room?.members.find((address) => address.id == addressId);
return address;
},
messages:

View File

@ -1,47 +1,54 @@
<script setup lang="ts">
import store from "../../store/store";
import { defineProps, ref, watch } from "vue";
import { defineProps } from "vue";
import Badge from "@/components/Badge.vue";
import { RoomType } from "@/store/models/model";
import { RoomType, Address } from "@/store/models/model";
import MemberList from "./MemberList.vue";
const props = defineProps({ id: Number });
const room = ref(store.getters.room(props.id));
// todo auto load
watch(
() => props.id,
(newId) => {
room.value = store.getters.room(newId);
},
);
const props = defineProps({ id: Number, room: Object });
const roomTitle = () => {
const type = room.value?.roomType;
const type = props.room?.roomType;
if (type === RoomType.DM || type == RoomType.CHANNEL || type == RoomType.ROOM) {
return room.value?.user;
return props.room?.user;
}
return room.value?.roomName;
return props.room?.roomName;
};
const to = () => props.room?.members.filter((member: Address) => member.type == "to");
const cc = () => props.room?.members.filter((member: Address) => member.type == "cc");
</script>
<template>
<div class="main">
<div class="context">
<div class="infos">
<Badge :value="RoomType[room?.roomType]" />
{{ roomTitle() }}
</div>
<div class="action">action: threads message important</div>
</div>
<div class="members" v-if="room?.roomType != RoomType.DM">
<MemberList v-if="to()?.length > 0" type="to" :members="to()" />
<MemberList v-if="cc()?.length > 0" type="cc" :members="cc()" />
</div>
</div>
</template>
<style scoped>
.main {
border-bottom: 1px solid #505050;
}
.context {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #505050;
align-items: center;
width: 100%;
height: 51px;
height: 35px;
}
.members {
}
.infos {

View File

@ -0,0 +1,19 @@
<script setup lang="ts">
import { Address } from "@/store/models/model";
import { defineProps } from "vue";
const props = defineProps({ type: String, members: Object });
let emails = "";
props.members?.forEach((member: Address) => {
emails += member.email + "; ";
});
</script>
<template>
<div class="main">
{{ props.type }}:
{{ emails }}
</div>
</template>
<style scoped></style>

View File

@ -3,9 +3,16 @@ import { defineProps, onMounted, ref, watch } from "vue";
import { decodeEmojis } from "../../utils/string";
import { removeDuplicates } from "../../utils/array";
import DOMPurify from "dompurify";
import store from "@/store/store";
const props = defineProps({ data: Object });
const props = defineProps({
data: {
fromA: String,
subject: String,
content: String,
date: String,
},
members: Array,
});
const iframe = ref(null);
// todo dompurify
@ -47,11 +54,10 @@ onMounted(() => {
});
const displayAddresses = (addressesId) => {
// todo store members in rooms ?
addressesId = removeDuplicates(addressesId);
let res = "";
addressesId.forEach((addressId) => {
const address = store.getters.address(addressId);
const address = props.members.find((member) => member.id == addressId);
if (address) res += address.email;
});
return res;
@ -98,17 +104,18 @@ const displayAddresses = (addressesId) => {
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: blue;
padding: 3px;
background-color: var(--quaternary-background);
padding: 3px 10px;
margin-bottom: 6px;
border-radius: 4px;
}
iframe {
overflow-y: auto;
max-height: 300px;
width: 100%;
padding: 2px 10px;
max-width: 750px; /* template width being 600px to 640px up to 750px (experiment and test) */
border: none;
max-width: 600px; /* template width being 600px to 640px up to 750px (experiment and test) */
background-color: rgb(234, 234, 234);
}

View File

@ -9,30 +9,21 @@ import { RoomType } from "@/store/models/model";
const store = useStore();
const route = useRoute();
const id = ref(parseInt(route.params?.id));
// let room;
let room;
onBeforeMount(async () => {
// get data
// room = store.getters.room(id);
// if (!room || room?.fetched === false) {
// // todo
// // await store.dispatch("fetchMessages", );
// }
store.commit("setActiveRoom", id);
store.commit("setActiveRoom", id.value);
room = store.getters.room(id.value);
});
onBeforeRouteUpdate(async (to, from) => {
if (to.params.id !== from.params.id) {
id.value = parseInt(to.params.id);
console.log(id);
// room = store.getters.room(id);
// console.log(room);
store.commit("setActiveRoom", id);
store.commit("setActiveRoom", id.value);
room = await store.getters.room(id.value);
}
});
const shouldDisplayComposer = () => {
if (!id.value) return false;
const room = store.getters.room(id.value);
if (!room) return false;
return room.roomType == RoomType.THREAD || room.roomType == RoomType.GROUP;
};
@ -40,12 +31,16 @@ const shouldDisplayComposer = () => {
<template>
<div id="main">
<Header :id="id"></Header>
<Header :id="id" :room="room"></Header>
<div id="RoomViewBody">
<div class="content">
<Message v-for="(message, index) in store.getters.messages(id)" :key="index" :data="message" />
<Message
v-for="(message, index) in room?.messages"
:key="index"
:data="message"
:members="room?.members"
/>
</div>
{{ room?.roomType }}
<div id="composer" v-if="shouldDisplayComposer()">COMPOSER</div>
</div>
</div>

View File

@ -1,5 +1,5 @@
<template>
<div class="container" @click="setactiveAccount(data.id)" :class="activeAccount == data.id && 'active'">
<div class="container" @click="setActiveAccount(data.id)" :class="activeAccount == data.id && 'active'">
{{ data.email }}
</div>
</template>
@ -17,7 +17,7 @@ export default {
...mapState(["activeAccount"]),
},
methods: {
...mapMutations(["setactiveAccount"]),
...mapMutations(["setActiveAccount"]),
},
};
</script>

View File

@ -2,7 +2,7 @@
import { useRouter } from "vue-router";
import { defineProps } from "vue";
import BaseAvatar from "../../avatars/BaseAvatar.vue";
import Badge from "../../../components/Badge.vue";
import Badge from "@/components/Badge.vue";
import ThreadList from "./threads/ThreadList.vue";
import store from "@/store/store";
@ -14,10 +14,10 @@ const props = defineProps({
userId: Number,
notSeen: Number,
mailboxId: Number,
threadIds: [Number],
threadIds: Array,
},
});
console.log(props.data.threadIds);
// console.log(props.data.threadIds);
const router = useRouter();
</script>
@ -34,9 +34,8 @@ const router = useRouter();
<div class="sender">{{ props.data.user }}</div>
<div class="object">{{ props.data.roomName }}</div>
</div>
<Badge class="badge" v-if="props.data.unseen > 0"
><template v-slot:body>{{ props.data.unseen }}</template>
</Badge>
{{ props.data.unseen }}
<Badge class="badge" v-if="props.data.notSeen > 0" :value="props.data.notSeen" type="badge-number" />
</div>
<ThreadList :threadIds="props.data.threadIds" />
</div>

View File

@ -2,12 +2,12 @@
import store from "@/store/store";
import { defineProps } from "vue";
import { useRouter } from "vue-router";
import Badge from "@/components/Badge.vue";
const props = defineProps({
threadId: Number,
});
const room = store.getters.room(props.threadId);
console.log(props.thread);
const router = useRouter();
</script>
@ -18,6 +18,7 @@ const router = useRouter();
class="room"
>
{{ room.roomName }}
<Badge class="badge" v-if="room.notSeen > 0" :value="room.notSeen" type="badge-number" />
</div>
</template>

View File

@ -1,7 +1,7 @@
<script setup>
import Thread from "./Thread.vue";
import { defineProps } from "vue";
const props = defineProps({ threadIds: [Number] });
const props = defineProps({ threadIds: Array });
</script>
<template>