Update various configuration files, components, and assets; enhance notification system and API endpoints; improve documentation and styles across the application.
This commit is contained in:
707
pages/notification/queue/timezone.vue
Normal file
707
pages/notification/queue/timezone.vue
Normal file
@@ -0,0 +1,707 @@
|
||||
<template>
|
||||
<div>
|
||||
<LayoutsBreadcrumb />
|
||||
|
||||
<!-- Header Section -->
|
||||
<rs-card class="mb-6">
|
||||
<template #header>
|
||||
<div class="flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-schedule"></Icon>
|
||||
<h1 class="text-xl font-bold text-primary">Timezone Handling</h1>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<p class="text-gray-600">
|
||||
Ensures messages are delivered at the right local time for each recipient.
|
||||
Schedule birthday messages at 9AM local time and avoid 2AM push alerts across timezones.
|
||||
</p>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Current Time Display -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
|
||||
<rs-card
|
||||
v-for="(timezone, index) in majorTimezones"
|
||||
:key="index"
|
||||
class="transition-all duration-300 hover:shadow-lg"
|
||||
>
|
||||
<div class="pt-5 pb-3 px-5 text-center">
|
||||
<div class="mb-2">
|
||||
<Icon class="text-primary text-2xl" name="ic:outline-access-time"></Icon>
|
||||
</div>
|
||||
<h3 class="font-semibold text-lg">{{ timezone.name }}</h3>
|
||||
<p class="text-2xl font-bold text-primary">{{ timezone.time }}</p>
|
||||
<p class="text-sm text-gray-600">{{ timezone.zone }}</p>
|
||||
</div>
|
||||
</rs-card>
|
||||
</div>
|
||||
|
||||
<!-- Timezone Statistics -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-4 gap-6 mb-6">
|
||||
<rs-card
|
||||
v-for="(stat, index) in timezoneStats"
|
||||
:key="index"
|
||||
class="transition-all duration-300 hover:shadow-lg"
|
||||
>
|
||||
<div class="pt-5 pb-3 px-5 flex items-center gap-4">
|
||||
<div
|
||||
class="p-4 flex justify-center items-center rounded-2xl"
|
||||
:class="stat.bgColor"
|
||||
>
|
||||
<Icon class="text-2xl" :class="stat.iconColor" :name="stat.icon"></Icon>
|
||||
</div>
|
||||
<div class="flex-1 truncate">
|
||||
<span class="block font-bold text-xl leading-tight" :class="stat.textColor">
|
||||
{{ stat.value }}
|
||||
</span>
|
||||
<span class="text-sm font-medium text-gray-600">
|
||||
{{ stat.title }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</rs-card>
|
||||
</div>
|
||||
|
||||
<!-- Timezone Configuration -->
|
||||
<rs-card class="mb-6">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-lg font-semibold text-primary">Timezone Configuration</h3>
|
||||
<rs-button variant="outline" size="sm" @click="showConfigModal = true">
|
||||
<Icon class="mr-1" name="ic:outline-settings"></Icon>
|
||||
Configure
|
||||
</rs-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div class="border border-gray-200 rounded-lg p-4">
|
||||
<h4 class="font-semibold mb-3 flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-schedule"></Icon>
|
||||
Default Delivery Times
|
||||
</h4>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Morning Messages:</span>
|
||||
<span class="font-medium">{{ config.morningTime }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Afternoon Messages:</span>
|
||||
<span class="font-medium">{{ config.afternoonTime }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Evening Messages:</span>
|
||||
<span class="font-medium">{{ config.eveningTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4">
|
||||
<h4 class="font-semibold mb-3 flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-block"></Icon>
|
||||
Quiet Hours
|
||||
</h4>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Start Time:</span>
|
||||
<span class="font-medium">{{ config.quietHours.start }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">End Time:</span>
|
||||
<span class="font-medium">{{ config.quietHours.end }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Emergency Override:</span>
|
||||
<span class="font-medium">{{ config.quietHours.allowEmergency ? 'Enabled' : 'Disabled' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4">
|
||||
<h4 class="font-semibold mb-3 flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-public"></Icon>
|
||||
Timezone Detection
|
||||
</h4>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Auto-detect:</span>
|
||||
<span class="font-medium">{{ config.autoDetect ? 'Enabled' : 'Disabled' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Fallback Timezone:</span>
|
||||
<span class="font-medium">{{ config.fallbackTimezone }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Update Frequency:</span>
|
||||
<span class="font-medium">{{ config.updateFrequency }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Scheduled Messages by Timezone -->
|
||||
<rs-card class="mb-6">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-lg font-semibold text-primary">Scheduled Messages by Timezone</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<select v-model="selectedTimezone" class="p-2 border border-gray-300 rounded-md text-sm">
|
||||
<option value="">All Timezones</option>
|
||||
<option v-for="tz in availableTimezones" :key="tz.value" :value="tz.value">
|
||||
{{ tz.label }}
|
||||
</option>
|
||||
</select>
|
||||
<rs-button variant="outline" size="sm" @click="refreshScheduledMessages">
|
||||
<Icon class="mr-1" name="ic:outline-refresh"></Icon>
|
||||
Refresh
|
||||
</rs-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<rs-table
|
||||
:field="scheduledMessagesFields"
|
||||
:data="filteredScheduledMessages"
|
||||
:options="{ striped: true, hover: true }"
|
||||
:optionsAdvanced="{ sortable: true, filterable: false }"
|
||||
advanced
|
||||
/>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Timezone Distribution Chart -->
|
||||
<rs-card class="mb-6">
|
||||
<template #header>
|
||||
<h3 class="text-lg font-semibold text-primary">User Distribution by Timezone</h3>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- Chart would go here in a real implementation -->
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="(distribution, index) in timezoneDistribution"
|
||||
:key="index"
|
||||
class="flex items-center justify-between p-3 bg-gray-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<div class="w-4 h-4 rounded mr-3" :style="{ backgroundColor: distribution.color }"></div>
|
||||
<div>
|
||||
<p class="font-medium">{{ distribution.timezone }}</p>
|
||||
<p class="text-sm text-gray-600">{{ distribution.users }} users</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="font-medium">{{ distribution.percentage }}%</p>
|
||||
<p class="text-sm text-gray-600">{{ distribution.currentTime }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-semibold">Delivery Optimization</h4>
|
||||
<div class="space-y-3">
|
||||
<div class="bg-green-50 border border-green-200 rounded p-3">
|
||||
<div class="flex items-center mb-2">
|
||||
<Icon class="mr-2 text-green-600" name="ic:outline-check-circle"></Icon>
|
||||
<span class="font-medium text-green-800">Optimal Delivery Windows</span>
|
||||
</div>
|
||||
<p class="text-sm text-green-700">
|
||||
{{ optimizationStats.optimalWindows }} messages scheduled during optimal hours
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded p-3">
|
||||
<div class="flex items-center mb-2">
|
||||
<Icon class="mr-2 text-yellow-600" name="ic:outline-warning"></Icon>
|
||||
<span class="font-medium text-yellow-800">Quiet Hours Conflicts</span>
|
||||
</div>
|
||||
<p class="text-sm text-yellow-700">
|
||||
{{ optimizationStats.quietHoursConflicts }} messages would be sent during quiet hours
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-blue-50 border border-blue-200 rounded p-3">
|
||||
<div class="flex items-center mb-2">
|
||||
<Icon class="mr-2 text-blue-600" name="ic:outline-info"></Icon>
|
||||
<span class="font-medium text-blue-800">Timezone Coverage</span>
|
||||
</div>
|
||||
<p class="text-sm text-blue-700">
|
||||
Messages will be delivered across {{ optimizationStats.timezoneCoverage }} timezones
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Timezone Testing Tool -->
|
||||
<rs-card>
|
||||
<template #header>
|
||||
<h3 class="text-lg font-semibold text-primary">Timezone Testing Tool</h3>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Test Message</label>
|
||||
<textarea
|
||||
v-model="testMessage.content"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
rows="3"
|
||||
placeholder="Enter test message content"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Scheduled Time (UTC)</label>
|
||||
<input
|
||||
v-model="testMessage.scheduledTime"
|
||||
type="datetime-local"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Message Type</label>
|
||||
<select v-model="testMessage.type" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
<option value="email">Email</option>
|
||||
<option value="sms">SMS</option>
|
||||
<option value="push">Push Notification</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<rs-button @click="testTimezoneDelivery" variant="primary" class="w-full">
|
||||
<Icon class="mr-1" name="ic:outline-play-arrow"></Icon>
|
||||
Test Timezone Delivery
|
||||
</rs-button>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-semibold">Delivery Preview</h4>
|
||||
<div v-if="deliveryPreview.length > 0" class="space-y-2 max-h-60 overflow-y-auto">
|
||||
<div
|
||||
v-for="(preview, index) in deliveryPreview"
|
||||
:key="index"
|
||||
class="border border-gray-200 rounded p-3"
|
||||
>
|
||||
<div class="flex justify-between items-start mb-1">
|
||||
<span class="font-medium">{{ preview.timezone }}</span>
|
||||
<span class="text-sm text-gray-600">{{ preview.users }} users</span>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<p class="text-gray-600">Local delivery time: <span class="font-medium">{{ preview.localTime }}</span></p>
|
||||
<p class="text-gray-600">Status:
|
||||
<span :class="{
|
||||
'text-green-600': preview.status === 'optimal',
|
||||
'text-yellow-600': preview.status === 'suboptimal',
|
||||
'text-red-600': preview.status === 'blocked'
|
||||
}" class="font-medium">{{ preview.status }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-center text-gray-500 py-8">
|
||||
<Icon class="text-4xl mb-2" name="ic:outline-schedule"></Icon>
|
||||
<p>Run a test to see delivery preview</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Configuration Modal -->
|
||||
<rs-modal v-model="showConfigModal" size="lg">
|
||||
<template #header>
|
||||
<h3 class="text-lg font-semibold">Timezone Configuration</h3>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<h4 class="font-semibold mb-3">Default Delivery Times</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Morning Messages</label>
|
||||
<input
|
||||
v-model="config.morningTime"
|
||||
type="time"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Afternoon Messages</label>
|
||||
<input
|
||||
v-model="config.afternoonTime"
|
||||
type="time"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Evening Messages</label>
|
||||
<input
|
||||
v-model="config.eveningTime"
|
||||
type="time"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 class="font-semibold mb-3">Quiet Hours</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Start Time</label>
|
||||
<input
|
||||
v-model="config.quietHours.start"
|
||||
type="time"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">End Time</label>
|
||||
<input
|
||||
v-model="config.quietHours.end"
|
||||
type="time"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<label class="flex items-center">
|
||||
<input
|
||||
v-model="config.quietHours.allowEmergency"
|
||||
type="checkbox"
|
||||
class="mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-gray-700">Allow emergency messages during quiet hours</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 class="font-semibold mb-3">Timezone Detection</h4>
|
||||
<div class="space-y-4">
|
||||
<label class="flex items-center">
|
||||
<input
|
||||
v-model="config.autoDetect"
|
||||
type="checkbox"
|
||||
class="mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-gray-700">Auto-detect user timezones</span>
|
||||
</label>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Fallback Timezone</label>
|
||||
<select v-model="config.fallbackTimezone" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
<option value="UTC">UTC</option>
|
||||
<option value="America/New_York">America/New_York</option>
|
||||
<option value="Europe/London">Europe/London</option>
|
||||
<option value="Asia/Tokyo">Asia/Tokyo</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Update Frequency</label>
|
||||
<select v-model="config.updateFrequency" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
<option value="daily">Daily</option>
|
||||
<option value="weekly">Weekly</option>
|
||||
<option value="monthly">Monthly</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
<rs-button variant="outline" @click="showConfigModal = false">Cancel</rs-button>
|
||||
<rs-button @click="saveConfiguration" variant="primary">Save Configuration</rs-button>
|
||||
</div>
|
||||
</template>
|
||||
</rs-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
title: "Timezone Handling",
|
||||
middleware: ["auth"],
|
||||
requiresAuth: true,
|
||||
breadcrumb: [
|
||||
{
|
||||
name: "Notification",
|
||||
path: "/notification",
|
||||
},
|
||||
{
|
||||
name: "Queue & Scheduler",
|
||||
path: "/notification/queue-scheduler",
|
||||
},
|
||||
{
|
||||
name: "Timezone Handling",
|
||||
path: "/notification/queue-scheduler/timezone",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Reactive data
|
||||
const showConfigModal = ref(false);
|
||||
const selectedTimezone = ref('');
|
||||
const deliveryPreview = ref([]);
|
||||
|
||||
// Current time for major timezones
|
||||
const majorTimezones = ref([
|
||||
{
|
||||
name: 'New York',
|
||||
zone: 'America/New_York',
|
||||
time: new Date().toLocaleTimeString('en-US', { timeZone: 'America/New_York' })
|
||||
},
|
||||
{
|
||||
name: 'London',
|
||||
zone: 'Europe/London',
|
||||
time: new Date().toLocaleTimeString('en-US', { timeZone: 'Europe/London' })
|
||||
},
|
||||
{
|
||||
name: 'Tokyo',
|
||||
zone: 'Asia/Tokyo',
|
||||
time: new Date().toLocaleTimeString('en-US', { timeZone: 'Asia/Tokyo' })
|
||||
}
|
||||
]);
|
||||
|
||||
// Update times every second
|
||||
setInterval(() => {
|
||||
majorTimezones.value.forEach(tz => {
|
||||
tz.time = new Date().toLocaleTimeString('en-US', { timeZone: tz.zone });
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// Statistics
|
||||
const timezoneStats = ref([
|
||||
{
|
||||
title: "Active Timezones",
|
||||
value: "24",
|
||||
icon: "ic:outline-public",
|
||||
bgColor: "bg-blue-100",
|
||||
iconColor: "text-blue-600",
|
||||
textColor: "text-blue-600"
|
||||
},
|
||||
{
|
||||
title: "Scheduled Messages",
|
||||
value: "1,847",
|
||||
icon: "ic:outline-schedule",
|
||||
bgColor: "bg-green-100",
|
||||
iconColor: "text-green-600",
|
||||
textColor: "text-green-600"
|
||||
},
|
||||
{
|
||||
title: "Optimal Deliveries",
|
||||
value: "94.2%",
|
||||
icon: "ic:outline-trending-up",
|
||||
bgColor: "bg-purple-100",
|
||||
iconColor: "text-purple-600",
|
||||
textColor: "text-purple-600"
|
||||
},
|
||||
{
|
||||
title: "Quiet Hours Respected",
|
||||
value: "99.8%",
|
||||
icon: "ic:outline-nights-stay",
|
||||
bgColor: "bg-orange-100",
|
||||
iconColor: "text-orange-600",
|
||||
textColor: "text-orange-600"
|
||||
}
|
||||
]);
|
||||
|
||||
// Configuration
|
||||
const config = ref({
|
||||
morningTime: '09:00',
|
||||
afternoonTime: '14:00',
|
||||
eveningTime: '18:00',
|
||||
quietHours: {
|
||||
start: '22:00',
|
||||
end: '07:00',
|
||||
allowEmergency: true
|
||||
},
|
||||
autoDetect: true,
|
||||
fallbackTimezone: 'UTC',
|
||||
updateFrequency: 'daily'
|
||||
});
|
||||
|
||||
// Available timezones
|
||||
const availableTimezones = ref([
|
||||
{ value: 'America/New_York', label: 'America/New_York (EST/EDT)' },
|
||||
{ value: 'America/Los_Angeles', label: 'America/Los_Angeles (PST/PDT)' },
|
||||
{ value: 'Europe/London', label: 'Europe/London (GMT/BST)' },
|
||||
{ value: 'Europe/Paris', label: 'Europe/Paris (CET/CEST)' },
|
||||
{ value: 'Asia/Tokyo', label: 'Asia/Tokyo (JST)' },
|
||||
{ value: 'Asia/Shanghai', label: 'Asia/Shanghai (CST)' },
|
||||
{ value: 'Asia/Kolkata', label: 'Asia/Kolkata (IST)' },
|
||||
{ value: 'Australia/Sydney', label: 'Australia/Sydney (AEST/AEDT)' }
|
||||
]);
|
||||
|
||||
// Table fields for scheduled messages
|
||||
const scheduledMessagesFields = ref([
|
||||
{ key: 'id', label: 'Message ID', sortable: true },
|
||||
{ key: 'type', label: 'Type', sortable: true },
|
||||
{ key: 'timezone', label: 'Timezone', sortable: true },
|
||||
{ key: 'scheduledUTC', label: 'Scheduled (UTC)', sortable: true },
|
||||
{ key: 'localTime', label: 'Local Time', sortable: true },
|
||||
{ key: 'recipients', label: 'Recipients', sortable: true },
|
||||
{ key: 'status', label: 'Status', sortable: true }
|
||||
]);
|
||||
|
||||
// Mock scheduled messages data
|
||||
const scheduledMessages = ref([
|
||||
{
|
||||
id: 'msg_001',
|
||||
type: 'email',
|
||||
timezone: 'America/New_York',
|
||||
scheduledUTC: '2024-01-15 14:00:00',
|
||||
localTime: '2024-01-15 09:00:00',
|
||||
recipients: 1250,
|
||||
status: 'scheduled'
|
||||
},
|
||||
{
|
||||
id: 'msg_002',
|
||||
type: 'push',
|
||||
timezone: 'Europe/London',
|
||||
scheduledUTC: '2024-01-15 09:00:00',
|
||||
localTime: '2024-01-15 09:00:00',
|
||||
recipients: 890,
|
||||
status: 'scheduled'
|
||||
},
|
||||
{
|
||||
id: 'msg_003',
|
||||
type: 'sms',
|
||||
timezone: 'Asia/Tokyo',
|
||||
scheduledUTC: '2024-01-15 00:00:00',
|
||||
localTime: '2024-01-15 09:00:00',
|
||||
recipients: 2100,
|
||||
status: 'scheduled'
|
||||
}
|
||||
]);
|
||||
|
||||
// Timezone distribution
|
||||
const timezoneDistribution = ref([
|
||||
{
|
||||
timezone: 'America/New_York',
|
||||
users: 15420,
|
||||
percentage: 32.5,
|
||||
color: '#3B82F6',
|
||||
currentTime: new Date().toLocaleTimeString('en-US', { timeZone: 'America/New_York' })
|
||||
},
|
||||
{
|
||||
timezone: 'Europe/London',
|
||||
users: 12890,
|
||||
percentage: 27.2,
|
||||
color: '#10B981',
|
||||
currentTime: new Date().toLocaleTimeString('en-US', { timeZone: 'Europe/London' })
|
||||
},
|
||||
{
|
||||
timezone: 'Asia/Tokyo',
|
||||
users: 9650,
|
||||
percentage: 20.3,
|
||||
color: '#F59E0B',
|
||||
currentTime: new Date().toLocaleTimeString('en-US', { timeZone: 'Asia/Tokyo' })
|
||||
},
|
||||
{
|
||||
timezone: 'Australia/Sydney',
|
||||
users: 5840,
|
||||
percentage: 12.3,
|
||||
color: '#EF4444',
|
||||
currentTime: new Date().toLocaleTimeString('en-US', { timeZone: 'Australia/Sydney' })
|
||||
},
|
||||
{
|
||||
timezone: 'Others',
|
||||
users: 3700,
|
||||
percentage: 7.7,
|
||||
color: '#8B5CF6',
|
||||
currentTime: '-'
|
||||
}
|
||||
]);
|
||||
|
||||
// Optimization stats
|
||||
const optimizationStats = ref({
|
||||
optimalWindows: 1654,
|
||||
quietHoursConflicts: 23,
|
||||
timezoneCoverage: 18
|
||||
});
|
||||
|
||||
// Test message
|
||||
const testMessage = ref({
|
||||
content: '',
|
||||
scheduledTime: '',
|
||||
type: 'email'
|
||||
});
|
||||
|
||||
// Computed filtered scheduled messages
|
||||
const filteredScheduledMessages = computed(() => {
|
||||
let filtered = scheduledMessages.value;
|
||||
|
||||
if (selectedTimezone.value) {
|
||||
filtered = filtered.filter(msg => msg.timezone === selectedTimezone.value);
|
||||
}
|
||||
|
||||
return filtered.map(msg => ({
|
||||
...msg,
|
||||
status: h('span', {
|
||||
class: `px-2 py-1 rounded text-xs font-medium ${
|
||||
msg.status === 'scheduled' ? 'bg-blue-100 text-blue-800' :
|
||||
msg.status === 'sent' ? 'bg-green-100 text-green-800' :
|
||||
'bg-gray-100 text-gray-800'
|
||||
}`
|
||||
}, msg.status)
|
||||
}));
|
||||
});
|
||||
|
||||
// Methods
|
||||
function refreshScheduledMessages() {
|
||||
// Mock refresh
|
||||
console.log('Refreshing scheduled messages...');
|
||||
}
|
||||
|
||||
function testTimezoneDelivery() {
|
||||
if (!testMessage.value.content || !testMessage.value.scheduledTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mock delivery preview generation
|
||||
deliveryPreview.value = [
|
||||
{
|
||||
timezone: 'America/New_York',
|
||||
users: 1250,
|
||||
localTime: '09:00 AM',
|
||||
status: 'optimal'
|
||||
},
|
||||
{
|
||||
timezone: 'Europe/London',
|
||||
localTime: '02:00 AM',
|
||||
users: 890,
|
||||
status: 'blocked'
|
||||
},
|
||||
{
|
||||
timezone: 'Asia/Tokyo',
|
||||
localTime: '11:00 AM',
|
||||
users: 2100,
|
||||
status: 'optimal'
|
||||
},
|
||||
{
|
||||
timezone: 'Australia/Sydney',
|
||||
localTime: '01:00 AM',
|
||||
users: 580,
|
||||
status: 'blocked'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
function saveConfiguration() {
|
||||
// Mock save
|
||||
console.log('Saving timezone configuration...');
|
||||
showConfigModal.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
Reference in New Issue
Block a user