linguaielts-api / fronted /src /components /layout /EnableNotificationButton.vue
phuc1st
feat(cms): implement soft-archive (hide) and restore (unhide) features for tests
076c536
Raw
History Blame Contribute Delete
5.17 kB
<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>