Files
BarangaySystem/resources/js/Components/SystemBroadcast.vue
2026-06-06 18:43:00 +08:00

151 lines
3.5 KiB
Vue

<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';
const message = ref(null);
const visible = ref(true);
const fetchMessage = async () => {
try {
const response = await axios.get('/api/public/global-message');
if (response.data.success && response.data.data) {
message.value = response.data.data;
}
} catch (error) {
console.error('Error fetching global message:', error);
}
};
const dismiss = () => {
visible.value = false;
// Optional: Store in localStorage to keep it dismissed for the session
sessionStorage.setItem('dismissed_global_message', JSON.stringify(message.value));
};
onMounted(() => {
const dismissed = sessionStorage.getItem('dismissed_global_message');
fetchMessage().then(() => {
if (dismissed && message.value && JSON.stringify(message.value) === dismissed) {
visible.value = false;
}
});
// Refresh every 30 seconds
setInterval(fetchMessage, 30000);
});
const getIcon = (type) => {
switch (type) {
case 'success': return 'check-circle';
case 'warning': return 'exclamation-triangle';
case 'danger': return 'exclamation-circle';
default: return 'info-circle';
}
};
</script>
<template>
<transition name="fade">
<div v-if="message && visible" :class="['system-broadcast', `broadcast-${message.type || 'info'}`]">
<div class="broadcast-container">
<div class="broadcast-content">
<i :class="['fas', `fa-${getIcon(message.type)}`, 'broadcast-icon']"></i>
<span class="broadcast-text">{{ message.text }}</span>
</div>
<button class="broadcast-close" @click="dismiss">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</transition>
</template>
<style scoped>
.system-broadcast {
width: 100%;
padding: 12px 16px;
position: relative;
z-index: 10001;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
animation: slideDown 0.5s ease-out;
}
@keyframes slideDown {
from { transform: translateY(-100%); }
to { transform: translateY(0); }
}
.broadcast-container {
max-width: 800px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: space-between;
gap: 15px;
}
.broadcast-content {
display: flex;
align-items: center;
gap: 12px;
}
.broadcast-icon {
font-size: 1.2rem;
}
.broadcast-text {
font-weight: 600;
font-size: 0.95rem;
line-height: 1.4;
}
.broadcast-close {
background: transparent;
border: none;
color: inherit;
font-size: 1.1rem;
cursor: pointer;
opacity: 0.7;
transition: opacity 0.2s;
padding: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.broadcast-close:hover {
opacity: 1;
}
/* Types */
.broadcast-info {
background: linear-gradient(90deg, #0284c7, #0ea5e9);
color: white;
}
.broadcast-success {
background: linear-gradient(90deg, #059669, #10b981);
color: white;
}
.broadcast-warning {
background: linear-gradient(90deg, #d97706, #f59e0b);
color: white;
}
.broadcast-danger {
background: linear-gradient(90deg, #dc2626, #ef4444);
color: white;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s, transform 0.5s;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
transform: translateY(-20px);
}
</style>