2023-09-14 22:30:20 +12:00
|
|
|
<script>
|
2025-06-20 23:26:06 +12:00
|
|
|
import { mailbox } from "../stores/mailbox";
|
|
|
|
import CommonMixins from "../mixins/CommonMixins";
|
|
|
|
import dayjs from "dayjs";
|
2024-06-02 16:07:26 +12:00
|
|
|
import { pagination } from "../stores/pagination";
|
2023-09-14 22:30:20 +12:00
|
|
|
|
|
|
|
export default {
|
2025-06-20 23:26:06 +12:00
|
|
|
mixins: [CommonMixins],
|
2023-09-14 22:30:20 +12:00
|
|
|
|
2023-09-26 16:51:30 +13:00
|
|
|
props: {
|
2025-06-20 23:26:06 +12:00
|
|
|
// use different name to `loading` as that is already in use in CommonMixins
|
|
|
|
loadingMessages: {
|
|
|
|
type: Number,
|
|
|
|
default: 0,
|
|
|
|
},
|
2023-09-26 16:51:30 +13:00
|
|
|
},
|
|
|
|
|
2023-09-14 22:30:20 +12:00
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
mailbox,
|
2024-06-02 16:07:26 +12:00
|
|
|
pagination,
|
2025-06-20 23:26:06 +12:00
|
|
|
};
|
2023-09-14 22:30:20 +12:00
|
|
|
},
|
|
|
|
|
2024-07-28 10:59:02 +12:00
|
|
|
created() {
|
2025-06-20 23:26:06 +12:00
|
|
|
const relativeTime = require("dayjs/plugin/relativeTime");
|
|
|
|
dayjs.extend(relativeTime);
|
2024-07-28 10:59:02 +12:00
|
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
2025-06-20 23:26:06 +12:00
|
|
|
this.refreshUI();
|
2023-09-14 22:30:20 +12:00
|
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
2024-06-22 13:27:00 +12:00
|
|
|
refreshUI() {
|
|
|
|
window.setTimeout(() => {
|
2025-06-20 23:26:06 +12:00
|
|
|
this.$forceUpdate();
|
|
|
|
this.refreshUI();
|
|
|
|
}, 30000);
|
2024-04-24 17:44:20 +12:00
|
|
|
},
|
|
|
|
|
2024-06-22 13:27:00 +12:00
|
|
|
getRelativeCreated(message) {
|
2025-06-20 23:26:06 +12:00
|
|
|
const d = new Date(message.Created);
|
|
|
|
return dayjs(d).fromNow();
|
2023-09-14 22:30:20 +12:00
|
|
|
},
|
|
|
|
|
2024-06-22 13:27:00 +12:00
|
|
|
getPrimaryEmailTo(message) {
|
2025-06-20 23:26:06 +12:00
|
|
|
if (message.To && message.To.length > 0) {
|
|
|
|
return message.To[0].Address;
|
2023-09-14 22:30:20 +12:00
|
|
|
}
|
|
|
|
|
2025-06-20 23:26:06 +12:00
|
|
|
return "[ Undisclosed recipients ]";
|
2023-09-14 22:30:20 +12:00
|
|
|
},
|
|
|
|
|
2024-06-22 13:27:00 +12:00
|
|
|
isSelected(id) {
|
2025-06-20 23:26:06 +12:00
|
|
|
return mailbox.selected.indexOf(id) !== -1;
|
2023-09-14 22:30:20 +12:00
|
|
|
},
|
2023-09-22 15:06:03 +12:00
|
|
|
|
2024-06-22 13:27:00 +12:00
|
|
|
toggleSelected(e, id) {
|
2025-06-20 23:26:06 +12:00
|
|
|
e.preventDefault();
|
2023-09-22 15:06:03 +12:00
|
|
|
|
|
|
|
if (this.isSelected(id)) {
|
2025-06-20 23:26:06 +12:00
|
|
|
mailbox.selected = mailbox.selected.filter((ele) => {
|
|
|
|
return ele !== id;
|
|
|
|
});
|
2023-09-22 15:06:03 +12:00
|
|
|
} else {
|
2025-06-20 23:26:06 +12:00
|
|
|
mailbox.selected.push(id);
|
2023-09-22 15:06:03 +12:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2024-06-22 13:27:00 +12:00
|
|
|
selectRange(e, id) {
|
2025-06-20 23:26:06 +12:00
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
let selecting = false;
|
|
|
|
const lastSelected = mailbox.selected.length > 0 && mailbox.selected[mailbox.selected.length - 1];
|
|
|
|
if (lastSelected === id) {
|
|
|
|
mailbox.selected = mailbox.selected.filter((ele) => {
|
|
|
|
return ele !== id;
|
|
|
|
});
|
|
|
|
return;
|
2023-09-22 15:06:03 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lastSelected === false) {
|
2025-06-20 23:26:06 +12:00
|
|
|
mailbox.selected.push(id);
|
|
|
|
return;
|
2023-09-22 15:06:03 +12:00
|
|
|
}
|
|
|
|
|
2025-06-20 23:26:06 +12:00
|
|
|
for (const d of mailbox.messages) {
|
2023-09-22 15:06:03 +12:00
|
|
|
if (selecting) {
|
|
|
|
if (!this.isSelected(d.ID)) {
|
2025-06-20 23:26:06 +12:00
|
|
|
mailbox.selected.push(d.ID);
|
2023-09-22 15:06:03 +12:00
|
|
|
}
|
2025-06-20 23:26:06 +12:00
|
|
|
if (d.ID === lastSelected || d.ID === id) {
|
2023-09-22 15:06:03 +12:00
|
|
|
// reached backwards select
|
2025-06-20 23:26:06 +12:00
|
|
|
break;
|
2023-09-22 15:06:03 +12:00
|
|
|
}
|
2025-06-20 23:26:06 +12:00
|
|
|
} else if (d.ID === id || d.ID === lastSelected) {
|
2023-09-22 15:06:03 +12:00
|
|
|
if (!this.isSelected(d.ID)) {
|
2025-06-20 23:26:06 +12:00
|
|
|
mailbox.selected.push(d.ID);
|
2023-09-22 15:06:03 +12:00
|
|
|
}
|
2025-06-20 23:26:06 +12:00
|
|
|
selecting = true;
|
2023-09-22 15:06:03 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2024-06-01 20:32:11 +09:00
|
|
|
|
2024-06-22 13:27:00 +12:00
|
|
|
toTagUrl(t) {
|
2024-06-02 16:07:26 +12:00
|
|
|
if (t.match(/ /)) {
|
2025-06-20 23:26:06 +12:00
|
|
|
t = `"${t}"`;
|
2024-06-02 16:07:26 +12:00
|
|
|
}
|
|
|
|
const p = {
|
2025-06-20 23:26:06 +12:00
|
|
|
q: "tag:" + t,
|
|
|
|
};
|
|
|
|
if (pagination.limit !== pagination.defaultLimit) {
|
|
|
|
p.limit = pagination.limit.toString();
|
2024-06-02 16:07:26 +12:00
|
|
|
}
|
2025-06-20 23:26:06 +12:00
|
|
|
const params = new URLSearchParams(p);
|
|
|
|
return "/search?" + params.toString();
|
2024-06-01 20:32:11 +09:00
|
|
|
},
|
2025-06-20 23:26:06 +12:00
|
|
|
},
|
|
|
|
};
|
2023-09-14 22:30:20 +12:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<template v-if="mailbox.messages && mailbox.messages.length">
|
|
|
|
<div class="list-group my-2">
|
2025-06-20 23:26:06 +12:00
|
|
|
<RouterLink
|
|
|
|
v-for="message in mailbox.messages"
|
2024-04-24 17:45:17 +12:00
|
|
|
:id="message.ID"
|
2025-06-20 23:26:06 +12:00
|
|
|
:key="'message_' + message.ID"
|
|
|
|
:to="'/view/' + message.ID"
|
2023-09-14 22:30:20 +12:00
|
|
|
class="row gx-1 message d-flex small list-group-item list-group-item-action border-start-0 border-end-0"
|
2025-06-20 23:26:06 +12:00
|
|
|
:class="[message.Read ? 'read' : '', isSelected(message.ID) ? ' selected' : '']"
|
|
|
|
@click.meta="toggleSelected($event, message.ID)"
|
|
|
|
@click.ctrl="toggleSelected($event, message.ID)"
|
|
|
|
@click.shift="selectRange($event, message.ID)"
|
|
|
|
>
|
2023-09-14 22:30:20 +12:00
|
|
|
<div class="col-lg-3">
|
|
|
|
<div class="d-lg-none float-end text-muted text-nowrap small">
|
2025-06-20 23:26:06 +12:00
|
|
|
<i v-if="message.Attachments" class="bi bi-paperclip h6 me-1"></i>
|
2023-09-14 22:30:20 +12:00
|
|
|
{{ getRelativeCreated(message) }}
|
|
|
|
</div>
|
2024-12-10 22:00:36 +13:00
|
|
|
<div v-if="message.From" class="overflow-x-hidden">
|
|
|
|
<div class="text-truncate privacy">
|
|
|
|
<b :title="'From: ' + message.From.Address">
|
|
|
|
{{ message.From.Name ? message.From.Name : message.From.Address }}
|
|
|
|
</b>
|
|
|
|
</div>
|
2023-09-14 22:30:20 +12:00
|
|
|
</div>
|
2024-12-10 22:00:36 +13:00
|
|
|
<div class="overflow-x-hidden">
|
|
|
|
<div class="text-truncate text-muted small privacy">
|
|
|
|
To: {{ getPrimaryEmailTo(message) }}
|
2025-06-20 23:26:06 +12:00
|
|
|
<span v-if="message.To && message.To.length > 1"> [+{{ message.To.length - 1 }}] </span>
|
2024-12-10 22:00:36 +13:00
|
|
|
</div>
|
2023-09-14 22:30:20 +12:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="col-lg-6 col-xxl-7 mt-2 mt-lg-0">
|
2024-01-20 12:29:28 +13:00
|
|
|
<div class="subject text-truncate text-spaces-nowrap">
|
2025-06-20 23:26:06 +12:00
|
|
|
<b>{{ message.Subject !== "" ? message.Subject : "[ no subject ]" }}</b>
|
2023-10-05 17:01:13 +13:00
|
|
|
</div>
|
2025-06-20 23:26:06 +12:00
|
|
|
<div v-if="message.Snippet !== ''" class="small text-muted text-truncate">
|
2023-10-06 17:04:03 +13:00
|
|
|
{{ message.Snippet }}
|
|
|
|
</div>
|
|
|
|
<div v-if="message.Tags.length">
|
2025-06-20 23:26:06 +12:00
|
|
|
<RouterLink
|
|
|
|
v-for="t in message.Tags"
|
|
|
|
:key="t"
|
|
|
|
class="badge me-1"
|
|
|
|
:to="toTagUrl(t)"
|
|
|
|
:style="
|
|
|
|
mailbox.showTagColors
|
|
|
|
? { backgroundColor: colorHash(t) }
|
|
|
|
: { backgroundColor: '#6c757d' }
|
|
|
|
"
|
|
|
|
:title="'Filter messages tagged with ' + t"
|
|
|
|
@click="pagination.start = 0"
|
|
|
|
>
|
2023-09-14 22:30:20 +12:00
|
|
|
{{ t }}
|
|
|
|
</RouterLink>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="d-none d-lg-block col-1 small text-end text-muted">
|
2025-06-20 23:26:06 +12:00
|
|
|
<i v-if="message.Attachments" class="bi bi-paperclip float-start h6"></i>
|
2023-09-14 22:30:20 +12:00
|
|
|
{{ getFileSize(message.Size) }}
|
|
|
|
</div>
|
|
|
|
<div class="d-none d-lg-block col-2 col-xxl-1 small text-end text-muted">
|
|
|
|
{{ getRelativeCreated(message) }}
|
|
|
|
</div>
|
|
|
|
</RouterLink>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<template v-else>
|
2023-09-22 15:06:03 +12:00
|
|
|
<p class="text-center mt-5">
|
2025-06-20 23:26:06 +12:00
|
|
|
<span v-if="loadingMessages > 0" class="text-muted"> Loading messages... </span>
|
|
|
|
<template v-else-if="getSearch()"
|
|
|
|
>No results for <code>{{ getSearch() }}</code></template
|
|
|
|
>
|
2023-09-22 15:06:03 +12:00
|
|
|
<template v-else>No messages in your mailbox</template>
|
|
|
|
</p>
|
2023-09-14 22:30:20 +12:00
|
|
|
</template>
|
|
|
|
</template>
|