Compare commits
No commits in common. "5b6995d6a6897c3afd7c66faf40b19f7811bae0e" and "9d12e81e07c6181383220217895f772502b26b4b" have entirely different histories.
5b6995d6a6
...
9d12e81e07
@ -1,26 +0,0 @@
|
|||||||
import { Response } from "express";
|
|
||||||
import { getAccounts, registerAccount } from "../db/api";
|
|
||||||
import { getAddresseId } from "../db/utils/mail";
|
|
||||||
import statusCodes from "../utils/statusCodes";
|
|
||||||
|
|
||||||
export default class Account {
|
|
||||||
static async getAll(body, res: Response) {
|
|
||||||
getAccounts().then((data) => {
|
|
||||||
res.status(statusCodes.OK).json(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static async register(body, res: Response) {
|
|
||||||
const { email, pwd, xoauth, xoauth2, host, port, tls } = body;
|
|
||||||
getAddresseId(email).then((addressId) => {
|
|
||||||
registerAccount(addressId, pwd, xoauth, xoauth2, host, port, tls)
|
|
||||||
.then((mailboxId) => {
|
|
||||||
res.status(statusCodes.OK).json({ id: mailboxId });
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
res.status(statusCodes.INTERNAL_SERVER_ERROR);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// todo change mailbox to account
|
|
||||||
}
|
|
||||||
}
|
|
18
back/controllers/addAccount.ts
Normal file
18
back/controllers/addAccount.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import statusCode from "../utils/statusCodes";
|
||||||
|
import { registerAccount } from "../db/api";
|
||||||
|
import { getAddresseId } from "../db/utils/mail";
|
||||||
|
|
||||||
|
export async function addAccount(body, res) {
|
||||||
|
const { email, pwd, xoauth, xoauth2, host, port, tls } = body;
|
||||||
|
getAddresseId(email).then((addressId) => {
|
||||||
|
registerAccount(addressId, pwd, xoauth, xoauth2, host, port, tls)
|
||||||
|
.then((mailboxId) => {
|
||||||
|
res.status(statusCode.OK).json({ id: mailboxId });
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
res.status(statusCode.INTERNAL_SERVER_ERROR);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo change mailbox to account
|
@ -1,9 +1,8 @@
|
|||||||
import statusCode from "../utils/statusCodes";
|
import statusCode from "../utils/statusCodes";
|
||||||
import { getRooms } from "../db/api";
|
import { getRooms } from "../db/api";
|
||||||
import logger from "../system/Logger";
|
import logger from "../system/Logger";
|
||||||
import { Response } from "express";
|
|
||||||
|
|
||||||
export async function rooms(body, res: Response) {
|
export async function rooms(body, res) {
|
||||||
const { mailboxId, offset, limit } = body;
|
const { mailboxId, offset, limit } = body;
|
||||||
getRooms(mailboxId).then((rooms) => {
|
getRooms(mailboxId).then((rooms) => {
|
||||||
res.status(statusCode.OK).json(rooms);
|
res.status(statusCode.OK).json(rooms);
|
@ -52,7 +52,7 @@ export async function getRooms(mailboxId) {
|
|||||||
return await execQueryAsync(query, values);
|
return await execQueryAsync(query, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMessages(roomId: number) {
|
export async function getMessages(roomId) {
|
||||||
// todo attachements name
|
// todo attachements name
|
||||||
const query = `
|
const query = `
|
||||||
SELECT
|
SELECT
|
||||||
@ -62,8 +62,7 @@ export async function getMessages(roomId: number) {
|
|||||||
GROUP_CONCAT(ccT.address_id) AS ccA,
|
GROUP_CONCAT(ccT.address_id) AS ccA,
|
||||||
subjectT.value AS subject,
|
subjectT.value AS subject,
|
||||||
content.text AS content,
|
content.text AS content,
|
||||||
message.idate AS date,
|
message.idate AS date
|
||||||
GROUP_CONCAT(flagT.flag_name) AS flags
|
|
||||||
FROM app_room_message msg
|
FROM app_room_message msg
|
||||||
|
|
||||||
${queryFromId} fromT ON msg.message_id = fromT.message_id
|
${queryFromId} fromT ON msg.message_id = fromT.message_id
|
||||||
@ -89,9 +88,6 @@ export async function getMessages(roomId: number) {
|
|||||||
bodypart.bodypart_id = header_field.bodypart_id
|
bodypart.bodypart_id = header_field.bodypart_id
|
||||||
) content ON msg.message_id = content.message_id
|
) content ON msg.message_id = content.message_id
|
||||||
|
|
||||||
LEFT JOIN flag ON flag.message_id = msg.message_id
|
|
||||||
LEFT JOIN flag_name flagT ON flagT.flag_id = flag.flag_id
|
|
||||||
|
|
||||||
INNER JOIN message ON message.message_id = msg.message_id
|
INNER JOIN message ON message.message_id = msg.message_id
|
||||||
|
|
||||||
WHERE msg.room_id = ?
|
WHERE msg.room_id = ?
|
||||||
|
@ -36,6 +36,7 @@ export async function createRoom(
|
|||||||
return await execQueryAsyncWithId(query, values);
|
return await execQueryAsyncWithId(query, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo date not good
|
||||||
export async function registerMessageInRoom(messageId: number, roomId: number, idate: string | undefined | null) {
|
export async function registerMessageInRoom(messageId: number, roomId: number, idate: string | undefined | null) {
|
||||||
if (!idate) idate = new Date().toString();
|
if (!idate) idate = new Date().toString();
|
||||||
const query = `INSERT IGNORE INTO app_room_message (message_id, room_id) VALUES (?, ?)`;
|
const query = `INSERT IGNORE INTO app_room_message (message_id, room_id) VALUES (?, ?)`;
|
||||||
|
@ -164,7 +164,7 @@ CREATE TABLE app_room_member (
|
|||||||
|
|
||||||
-- 15
|
-- 15
|
||||||
create table flag_name (
|
create table flag_name (
|
||||||
flag_id INT AUTO_INCREMENT,
|
flag_id INT NOT NULL,
|
||||||
flag_name VARCHAR(255) NOT NULL,
|
flag_name VARCHAR(255) NOT NULL,
|
||||||
PRIMARY KEY (flag_id),
|
PRIMARY KEY (flag_id),
|
||||||
UNIQUE KEY (flag_name)
|
UNIQUE KEY (flag_name)
|
||||||
|
@ -2,8 +2,9 @@ const queryAddress = (type: string): string => `
|
|||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT address_field.address_id, address_field.message_id
|
SELECT address_field.address_id, address_field.message_id
|
||||||
FROM address_field
|
FROM address_field
|
||||||
INNER JOIN field_name ON field_name.field_id = address_field.field_id
|
INNER JOIN field_name
|
||||||
WHERE
|
WHERE
|
||||||
|
field_name.field_id = address_field.field_id AND
|
||||||
field_name.field_name = '${type}'
|
field_name.field_name = '${type}'
|
||||||
)
|
)
|
||||||
`;
|
`;
|
||||||
|
@ -77,7 +77,6 @@ export default class RegisterMessageInApp {
|
|||||||
|
|
||||||
async incrementNotSeen(roomId: number) {
|
async incrementNotSeen(roomId: number) {
|
||||||
// todo it appears there is an error with notifications
|
// todo it appears there is an error with notifications
|
||||||
console.log("incrementRead", roomId)
|
|
||||||
if (!this.isSeen) {
|
if (!this.isSeen) {
|
||||||
await incrementNotSeenRoom(roomId);
|
await incrementNotSeenRoom(roomId);
|
||||||
}
|
}
|
||||||
|
@ -2,76 +2,52 @@ import statusCodes from "../utils/statusCodes";
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
import { rooms } from "../abl/rooms";
|
import Ajv from "ajv";
|
||||||
import { messages } from "../abl/messages";
|
import addFormats from "ajv-formats";
|
||||||
import { members } from "../abl/members";
|
const ajv = new Ajv({ allErrors: true });
|
||||||
import {
|
addFormats(ajv);
|
||||||
validateCreateAccount,
|
import schema_account from "../schemas/account_schema.json";
|
||||||
validateGetAccounts,
|
import { addAccount } from "../controllers/addAccount";
|
||||||
validateGetMembers,
|
import { getAccounts } from "../db/api";
|
||||||
validateGetMessages,
|
import { rooms } from "../controllers/rooms";
|
||||||
validateGetRooms,
|
import { messages } from "../controllers/messages";
|
||||||
} from "../validator/validator";
|
import { members } from "../controllers/members";
|
||||||
import Account from "../abl/Account-abl";
|
|
||||||
|
const validate_account = ajv.compile(schema_account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all mailboxes and folders for an user
|
* Return all mailboxes and folders for an user
|
||||||
*/
|
*/
|
||||||
router.get("/accounts", async (req, res) => {
|
router.get("/accounts", (req, res) => {
|
||||||
const valid = validateGetAccounts(req.params);
|
getAccounts().then((data) => {
|
||||||
if (!valid) {
|
res.status(statusCodes.OK).json(data);
|
||||||
res.status(statusCodes.NOT_ACCEPTABLE).send({ error: validateGetAccounts.errors });
|
});
|
||||||
} else {
|
|
||||||
await Account.getAll(req.params, res);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all rooms from a mailbox
|
|
||||||
*/
|
|
||||||
router.get("/:mailboxId/rooms", async (req, res) => {
|
router.get("/:mailboxId/rooms", async (req, res) => {
|
||||||
// todo offet limit
|
// todo use offset limit
|
||||||
const valid = validateGetRooms(req.params);
|
await rooms(req.params, res);
|
||||||
if (!valid) {
|
|
||||||
res.status(statusCodes.NOT_ACCEPTABLE).send({ error: validateGetRooms.errors });
|
|
||||||
} else {
|
|
||||||
await rooms(req.params, res);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all messages from a room
|
|
||||||
*/
|
|
||||||
router.get("/:roomId/messages", async (req, res) => {
|
router.get("/:roomId/messages", async (req, res) => {
|
||||||
const valid = validateGetMessages(req.params);
|
const { roomId } = req.params;
|
||||||
if (!valid) {
|
await messages(req.params, res);
|
||||||
res.status(statusCodes.NOT_ACCEPTABLE).send({ error: validateGetMessages.errors });
|
|
||||||
} else {
|
|
||||||
await messages(req.params, res);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all members from a room
|
|
||||||
*/
|
|
||||||
router.get("/:roomId/members", async (req, res) => {
|
router.get("/:roomId/members", async (req, res) => {
|
||||||
const valid = validateGetMembers(req.params);
|
const { roomId } = req.params;
|
||||||
if (!valid) {
|
await members(req.params, res);
|
||||||
res.status(statusCodes.NOT_ACCEPTABLE).send({ error: validateGetMembers.errors });
|
|
||||||
} else {
|
|
||||||
await members(req.params, res);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new mailbox inside the app
|
* Register a new mailbox inside the app
|
||||||
*/
|
*/
|
||||||
router.post("/account", async (req, res) => {
|
router.post("/account", async (req, res) => {
|
||||||
const valid = validateCreateAccount(req.body);
|
const valid = validate_account(req.body);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
res.status(statusCodes.NOT_ACCEPTABLE).send({ error: validateCreateAccount.errors });
|
res.status(statusCodes.NOT_ACCEPTABLE).send({ error: validate_account.errors });
|
||||||
} else {
|
} else {
|
||||||
await Account.register(req.body, res);
|
await addAccount(req.body, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ app.use(cors());
|
|||||||
app.listen(process.env.PORT || 5500);
|
app.listen(process.env.PORT || 5500);
|
||||||
|
|
||||||
import mailRouter from "./routes/mail";
|
import mailRouter from "./routes/mail";
|
||||||
import logger from "./system/Logger";
|
|
||||||
app.use("/api/mail", mailRouter);
|
app.use("/api/mail", mailRouter);
|
||||||
|
|
||||||
const imapSync = new ImapSync();
|
const imapSync = new ImapSync();
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {},
|
|
||||||
"required": [],
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"roomId": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"roomId"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"roomId": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"roomId"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"mailboxId": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"mailboxId"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import Ajv from "ajv";
|
|
||||||
import addFormats from "ajv-formats";
|
|
||||||
const ajv = new Ajv({ allErrors: true });
|
|
||||||
addFormats(ajv);
|
|
||||||
|
|
||||||
import createAccountSchema from "./schemas/createAccount-schema.json";
|
|
||||||
import getAccountSchema from "./schemas/getAccounts-schema.json";
|
|
||||||
import getRoomSchema from "./schemas/getRooms-schema.json";
|
|
||||||
import getMessagesSchema from "./schemas/getMessages-schema.json";
|
|
||||||
import getMembersSchema from "./schemas/getMembers-schema.json";
|
|
||||||
|
|
||||||
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);
|
|
@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, PropType } from "vue";
|
import { defineProps, PropType } from "vue";
|
||||||
import { Address } from "@/store/models/model";
|
import { Address } from "@/store/models/model";
|
||||||
|
import Badge from "./Badge.vue";
|
||||||
|
|
||||||
const props = defineProps({ address: Object as PropType<Address> });
|
const props = defineProps({ address: Object as PropType<Address> });
|
||||||
const value = props.address?.name ? props.address?.name : props.address?.email;
|
const value = props.address?.name ? props.address?.name : props.address?.email;
|
||||||
|
@ -13,7 +13,6 @@ export interface Message {
|
|||||||
subject: string;
|
subject: string;
|
||||||
content: string;
|
content: string;
|
||||||
date: string;
|
date: string;
|
||||||
flags: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LoadingState {
|
export enum LoadingState {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import API from "@/services/imapAPI";
|
import API from "@/services/imapAPI";
|
||||||
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, Store } from "vuex";
|
||||||
import { Room, Account, Address, RoomType, Message, LoadingState } from "./models/model";
|
import { Room, Account, Address, RoomType, Message, LoadingState } from "./models/model";
|
||||||
|
|
||||||
interface RoomFromBack {
|
interface RoomFromBack {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, onMounted, ref, watch, PropType } from "vue";
|
import { defineProps, onMounted, ref, watch, PropType, Prop } from "vue";
|
||||||
import { decodeEmojis } from "../../utils/string";
|
import { decodeEmojis } from "../../utils/string";
|
||||||
import { removeDuplicates } from "../../utils/array";
|
import { removeDuplicates } from "../../utils/array";
|
||||||
import DOMPurify from "dompurify";
|
import DOMPurify from "dompurify";
|
||||||
@ -9,7 +9,6 @@ const props = defineProps({
|
|||||||
msg: Object as PropType<Message>,
|
msg: Object as PropType<Message>,
|
||||||
members: Array as PropType<Address[]>,
|
members: Array as PropType<Address[]>,
|
||||||
});
|
});
|
||||||
console.log(props.msg);
|
|
||||||
const iframe = ref<HTMLIFrameElement>();
|
const iframe = ref<HTMLIFrameElement>();
|
||||||
|
|
||||||
// todo dompurify
|
// todo dompurify
|
||||||
@ -63,21 +62,6 @@ const displayAddresses = (addressIds: string[] | undefined): string => {
|
|||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
const classes = (): string => {
|
|
||||||
const flags = props.msg?.flags?.split(",");
|
|
||||||
|
|
||||||
// not flags implies no seen flag
|
|
||||||
if (!flags) return "msg-notSeen";
|
|
||||||
|
|
||||||
// Important takes the priority on Seen flag
|
|
||||||
if (flags.includes("\\Important")) {
|
|
||||||
return "msg-important";
|
|
||||||
} else if (!flags.includes("\\Seen")) {
|
|
||||||
return "msg-notSeen";
|
|
||||||
}
|
|
||||||
return "msg-basic";
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
<!-- to if to is more than me
|
<!-- to if to is more than me
|
||||||
cc -->
|
cc -->
|
||||||
@ -105,7 +89,7 @@ const classes = (): string => {
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" :class="[classes()]">
|
<div class="content">
|
||||||
<iframe ref="iframe"></iframe>
|
<iframe ref="iframe"></iframe>
|
||||||
<div class="options">options</div>
|
<div class="options">options</div>
|
||||||
</div>
|
</div>
|
||||||
@ -142,18 +126,8 @@ const classes = (): string => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
/* background-color: #ec7a4342;
|
||||||
|
background-color: #353c6261; */
|
||||||
.msg-important {
|
|
||||||
background-color: #ec7a4342;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msg-notSeen {
|
|
||||||
background-color: #222b5b61;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msg-basic {
|
|
||||||
background-color: var(--tertiary-background);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
@ -161,7 +135,7 @@ iframe {
|
|||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
max-width: 640px; /* template width being 600px to 640px up to 750px (experiment and test) */
|
max-width: 600px; /* template width being 600px to 640px up to 750px (experiment and test) */
|
||||||
background-color: rgb(234, 234, 234);
|
background-color: rgb(234, 234, 234);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ const shouldDisplayComposer = () => {
|
|||||||
<Message
|
<Message
|
||||||
v-for="(message, index) in room?.messages"
|
v-for="(message, index) in room?.messages"
|
||||||
:key="index"
|
:key="index"
|
||||||
:msg="message"
|
:data="message"
|
||||||
:members="room?.members"
|
:members="room?.members"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { defineProps, PropType } from "vue";
|
import { defineProps } from "vue";
|
||||||
import BaseAvatar from "../../avatars/BaseAvatar.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 ThreadList from "./threads/ThreadList.vue";
|
||||||
import store from "@/store/store";
|
import store from "@/store/store";
|
||||||
import { Room } from "@/store/models/model";
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
room: Object as PropType<Room>,
|
data: {
|
||||||
|
id: Number,
|
||||||
|
roomName: String,
|
||||||
|
user: String,
|
||||||
|
userId: Number,
|
||||||
|
notSeen: Number,
|
||||||
|
mailboxId: Number,
|
||||||
|
threadIds: Array,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
// console.log(props.room?.threadIds);
|
// console.log(props.data.threadIds);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
</script>
|
</script>
|
||||||
@ -19,17 +26,18 @@ const router = useRouter();
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="room"
|
class="room"
|
||||||
@click="router.push(`/${props.room?.id}`)"
|
@click="router.push(`/${props.data.id}`)"
|
||||||
v-bind:class="store.state.activeRoom == props.room?.id ? 'selected' : ''"
|
v-bind:class="store.state.activeRoom == props.data.id ? 'selected' : ''"
|
||||||
>
|
>
|
||||||
<BaseAvatar url="vue.png" />
|
<BaseAvatar url="vue.png" />
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="sender">{{ props.room?.user }}</div>
|
<div class="sender">{{ props.data.user }}</div>
|
||||||
<div class="object">{{ props.room?.roomName }}</div>
|
<div class="object">{{ props.data.roomName }}</div>
|
||||||
</div>
|
</div>
|
||||||
<Badge class="badge" v-if="props.room?.notSeen ?? 0 > 0" :value="props.room?.notSeen" type="badge-number" />
|
{{ props.data.unseen }}
|
||||||
|
<Badge class="badge" v-if="props.data.notSeen > 0" :value="props.data.notSeen" type="badge-number" />
|
||||||
</div>
|
</div>
|
||||||
<ThreadList :threadIds="props.room?.threadIds" />
|
<ThreadList :threadIds="props.data.threadIds" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<Room v-for="(room, index) in rooms()" :key="index" :room="room" />
|
<Room v-for="(room, index) in rooms()" :key="index" :data="room" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user