Spaces:
Paused
Paused
File size: 5,171 Bytes
076c536 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | <template>
<div class="space-y-2 rounded-lg border border-[var(--border)] bg-[var(--bg)] p-3">
<div class="flex items-center justify-between gap-3">
<div class="min-w-0">
<p class="text-[12px] font-semibold text-[var(--ink)]">Push notification</p>
<p class="mt-0.5 text-[11px] text-[var(--ink3)]">{{ statusText }}</p>
</div>
<span
class="shrink-0 rounded-md px-2 py-1 text-[10px] font-semibold"
:class="badgeClass"
>
{{ badgeText }}
</span>
</div>
<div class="flex gap-2">
<button
type="button"
class="ct-btn flex-1 px-3 py-2 text-[12px]"
:disabled="primaryDisabled"
@click="handlePrimary"
>
<svg v-if="loading" class="mr-1.5 inline h-3.5 w-3.5 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>
{{ primaryLabel }}
</button>
<button
type="button"
class="btn btn-primary flex-1 text-[12px]"
:disabled="!enabled || loading || testing"
@click="handleTest"
>
<svg v-if="testing" class="mr-1.5 inline h-3.5 w-3.5 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>
Kiểm tra
</button>
</div>
<p v-if="message" class="text-[11px]" :class="messageClass">{{ message }}</p>
</div>
</template>
<script setup>
import { computed, onMounted, ref, watch } from 'vue'
import { useAuthStore } from '@/stores/auth.js'
import {
getCurrentSubscription,
isPushNotificationSupported,
sendTestPushNotification,
subscribeUserToPush,
unsubscribeUserFromPush,
} from '@/services/pushNotification.js'
const emit = defineEmits(['changed'])
const auth = useAuthStore()
const loading = ref(false)
const testing = ref(false)
const supported = ref(true)
const enabled = ref(false)
const permission = ref(typeof Notification !== 'undefined' ? Notification.permission : 'default')
const message = ref('')
const messageType = ref('success')
const isAuthenticated = computed(() => auth.isAuthenticated)
const statusText = computed(() => {
if (!supported.value) return 'Trình duyệt này chưa hỗ trợ Web Push.'
if (!isAuthenticated.value) return 'Đăng nhập để bật thông báo.'
if (permission.value === 'denied') return 'Bạn đã chặn quyền thông báo trong trình duyệt.'
if (enabled.value) return 'Đã bật cho trình duyệt hiện tại.'
return 'Chưa bật cho trình duyệt hiện tại.'
})
const badgeText = computed(() => {
if (!supported.value) return 'Không hỗ trợ'
if (!isAuthenticated.value) return 'Chưa đăng nhập'
if (permission.value === 'denied') return 'Bị chặn'
return enabled.value ? 'Đã bật' : 'Chưa bật'
})
const badgeClass = computed(() => {
if (enabled.value) return 'bg-[#dcfce7] text-[#047857]'
if (!supported.value || permission.value === 'denied') return 'bg-[#fee2e2] text-[#b91c1c]'
return 'bg-[#fef3c7] text-[#92400e]'
})
const primaryLabel = computed(() => {
if (loading.value) return 'Đang xử lý'
return enabled.value ? 'Tắt' : 'Bật thông báo'
})
const primaryDisabled = computed(() => (
loading.value ||
!supported.value ||
!isAuthenticated.value ||
permission.value === 'denied'
))
const messageClass = computed(() => (
messageType.value === 'error' ? 'text-[#b91c1c]' : 'text-[#047857]'
))
async function refreshState() {
supported.value = isPushNotificationSupported()
permission.value = typeof Notification !== 'undefined' ? Notification.permission : 'default'
if (!supported.value || !isAuthenticated.value) {
enabled.value = false
return
}
enabled.value = !!(await getCurrentSubscription())
}
async function handlePrimary() {
loading.value = true
message.value = ''
try {
if (enabled.value) {
await unsubscribeUserFromPush()
enabled.value = false
message.value = 'Đã tắt push notification.'
} else {
await subscribeUserToPush()
permission.value = Notification.permission
enabled.value = true
message.value = 'Đã bật push notification.'
}
messageType.value = 'success'
emit('changed')
} catch (err) {
permission.value = typeof Notification !== 'undefined' ? Notification.permission : 'default'
messageType.value = 'error'
message.value = err?.response?.data?.detail || err?.message || 'Không thể cập nhật push notification.'
await refreshState()
} finally {
loading.value = false
}
}
async function handleTest() {
testing.value = true
message.value = ''
try {
const data = await sendTestPushNotification()
messageType.value = 'success'
message.value = `Đã gửi ${data.sent || 0} thông báo kiểm tra.`
} catch (err) {
messageType.value = 'error'
message.value = err?.response?.data?.detail || 'Không gửi được thông báo kiểm tra.'
} finally {
testing.value = false
}
}
onMounted(refreshState)
watch(isAuthenticated, refreshState)
</script>
|