-
{{ email.date }}
+
+ {{ getEmailDate(email) }}
+
+
+ {{ getEmailDate(email) }}
+
@@ -170,6 +207,28 @@
variant="tonal"
/>
+
+
+
+
+
+
+
+
+
+
@@ -178,6 +237,10 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useGettext } from 'vue3-gettext'
import { useBusStore, useWebmailStore } from '@/stores'
+import { DateTime } from 'luxon'
+import EmailAddressList from './EmailAddressList.vue'
+import EmailSchedulingForm from './EmailSchedulingForm.vue'
+import MenuItems from '@/components/tools/MenuItems.vue'
import api from '@/api/webmail'
const props = defineProps({
@@ -193,11 +256,15 @@ const webmailStore = useWebmailStore()
const router = useRouter()
const route = useRoute()
+const selectedScheduledEmail = ref(null)
const loading = ref(false)
const emails = ref({})
const page = ref(1)
+const schedulingError = ref('')
const search = ref('')
const selectAll = ref(false)
+const showSchedulingError = ref(false)
+const showSchedulingForm = ref(false)
const working = ref(false)
let intervalId = null
@@ -206,6 +273,79 @@ const currentMailbox = computed(() => {
return route.query.mailbox || 'INBOX'
})
+const inScheduledView = computed(() => props.mailbox === 'Scheduled')
+
+const getScheduledMessageActions = () => {
+ return [
+ {
+ label: $gettext('Reschedule'),
+ icon: 'mdi-send-clock-outline',
+ onClick: reScheduleMessage,
+ },
+ {
+ label: $gettext('Delete'),
+ icon: 'mdi-delete-outline',
+ onClick: deleteScheduledMessage,
+ color: 'red',
+ },
+ ]
+}
+
+const getEmailAddresses = (email) => {
+ if (inScheduledView.value) {
+ return email.recipients
+ }
+ return [email.from_address]
+}
+
+const getEmailDate = (email) => {
+ if (inScheduledView.value) {
+ return email.scheduled_datetime
+ }
+ return email.date
+}
+
+const isScheduledDateOver = (email) => {
+ if (!inScheduledView.value || !email.scheduled_datetime_raw) return false
+ const date = DateTime.fromISO(email.scheduled_datetime_raw)
+ return date < DateTime.now()
+}
+
+const reScheduleMessage = (email) => {
+ selectedScheduledEmail.value = email
+ showSchedulingForm.value = true
+}
+
+const updateScheduledEmail = async (datetime) => {
+ const data = {
+ scheduled_datetime: datetime,
+ }
+ await api.updateScheduledMessage(
+ selectedScheduledEmail.value.scheduled_id,
+ data
+ )
+ fetchEmails()
+ displayNotification({ msg: $gettext('Scheduling updated') })
+}
+
+const closeSchedulingForm = () => {
+ showSchedulingForm.value = false
+}
+
+const deleteScheduledMessage = async (email) => {
+ await api.deleteScheduledMessage(email.scheduled_id)
+ fetchEmails()
+ displayNotification({
+ msg: $gettext('Scheduled canceled and message move to trash folder'),
+ })
+}
+
+const displaySchedulingError = async (email) => {
+ const resp = await api.getScheduledMessage(email.scheduled_id)
+ schedulingError.value = resp.data.error
+ showSchedulingError.value = true
+}
+
const openEmail = (emailid) => {
router.push({
name: 'EmailView',
@@ -380,4 +520,7 @@ watch(page, () => {
.clickable {
cursor: pointer;
}
+.scheduling-top {
+ top: 45px;
+}
diff --git a/frontend/src/components/webmail/EmailSchedulingForm.vue b/frontend/src/components/webmail/EmailSchedulingForm.vue
new file mode 100644
index 000000000..68b06da00
--- /dev/null
+++ b/frontend/src/components/webmail/EmailSchedulingForm.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/webmail/MailboxList.vue b/frontend/src/components/webmail/MailboxList.vue
index 6fb7d58f1..bdc9a60a5 100644
--- a/frontend/src/components/webmail/MailboxList.vue
+++ b/frontend/src/components/webmail/MailboxList.vue
@@ -106,6 +106,7 @@ const iconByMailboxType = {
draft: 'mdi-file',
junk: 'mdi-fire',
sent: 'mdi-email-fast-outline',
+ scheduled: 'mdi-send-clock-outline',
trash: 'mdi-trash-can-outline',
normal: 'mdi-folder-outline',
}
diff --git a/frontend/src/plugins/rules.js b/frontend/src/plugins/rules.js
index b8231f5ee..c1bf084a7 100644
--- a/frontend/src/plugins/rules.js
+++ b/frontend/src/plugins/rules.js
@@ -22,6 +22,13 @@ function samePassword(value, confirmation) {
return value === confirmation
}
+function validateTime(value) {
+ if (!/^([01]\d|2[0-3]):?([0-5]\d)$/.test(value)) {
+ return $gettext('Not a valid time')
+ }
+ return true
+}
+
export default {
required: (value) =>
(value !== '' &&
@@ -43,4 +50,5 @@ export default {
samePassword(value, confirmation) || $gettext('Passwords mismatch'),
portNumber: (value) =>
(value > 0 && value < 65536) || $gettext('Invalid port number'),
+ time: (value) => validateTime(value),
}
diff --git a/frontend/src/views/webmail/EmailView.vue b/frontend/src/views/webmail/EmailView.vue
index 9261b70c3..4646ff3f2 100644
--- a/frontend/src/views/webmail/EmailView.vue
+++ b/frontend/src/views/webmail/EmailView.vue
@@ -3,63 +3,57 @@
- replyToEmail()"
- >
- {{ $gettext('Reply') }}
-
-
-
-
-
- replyToEmail(true)"
- />
-
-
-
-
-
-
-
-
-
-
-
-
+
+ replyToEmail()">
+ {{ $gettext('Reply') }}
+
+
+
+
+
+ replyToEmail(true)"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -140,6 +134,17 @@