707 lines
24 KiB
Vue
707 lines
24 KiB
Vue
<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> |