알림 요청 화면에 ‘알림 요청’ 버튼 하나만 있는 것은 상당히 불친절합니다. 왜 알림 요청을 해야 하는지 설명이 있어야 하고, 알림 요청 버튼을 눌렀을 때 처리 결과에 대해 알려 주어야 하고, 그리고 알림은 어떤 형태를 가지는지 보여주는 것이 아무래도 좀 더 사용자에 친절할 것입니다.
1. 알림 요청
2. src/views/NotificationView.vue
<!-- src/views/NotificationView.vue -->
<template>
<v-container class="mt-4" fluid>
<v-row align="center" justify="center">
<v-col cols="12">
<v-card class="pa-4">
<v-card-title>
<span class="text-h5">알림 요청</span>
</v-card-title>
<v-list-item-subtitle>
마이로그를 구독하기 위해서는 '알림 요청'을 해야 합니다.
</v-list-item-subtitle>
</v-card>
</v-col>
</v-row>
<v-row>
<v-col class="text-center" cols="10" offset="1" sm="8" offset-sm="2">
<v-btn color="primary" @click="requestFCMToken">
<v-icon left>mdi-bell</v-icon>
알림 요청
</v-btn>
</v-col>
</v-row>
<v-row align="center" justify="center">
<v-col cols="10" offset="1">
<!-- v-alert : type="success" "info" "warning" "error" -->
<v-alert v-if="error" type="info" dismissible @input="resetErrorMsg" class="my-alert">{{ error }}</v-alert>
</v-col>
</v-row>
</v-container>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
export default {
name: "NotificationView",
data() {
return {
};
},
computed: {
...mapGetters('fcm',['error']),
},
methods: {
...mapActions('fcm', ['getAndSaveFCMToken', 'resetError']),
async requestFCMToken() {
try {
const userId = this.$store.state.auth.user.id;
this.getAndSaveFCMToken(userId);
this.ShowNotification();
} catch (error) {
console.error("Error requesting FCM token:", error);
}
},
resetErrorMsg() {
this.resetError();
},
ShowNotification() {
const title = "마이로그-일상의 기록";
const options = {
body: "알림 서비스 가입을 환영합니다!",
icon: "/img/push-noti.png",
badge: "/img/push-badge-icon.png",
image: "/img/push-image.jpg",
data: [
{ action: "like", title: "링크를 클릭하세요.", icon: "/img/push-coffee.png", url: 'https://velog.io/@inetsos/posts'}
],
vibrate: [500, 100, 500]
};
navigator.serviceWorker.ready
.then(function(swreg) {
swreg.showNotification(title, options);
});
},
}
};
</script>
<style scoped>
.my-alert {
text-align: justify;
bottom: 30px;
margin: 20px 0;
}
#blog-link:hover {
color: blue;
cursor: pointer;
}
</style>
3. src/store/modules/fcm.js
// src/store/modules/fcm.js
import { messaging } from '@/firebase';
import { getToken } from "firebase/messaging";
import { db, collection, doc, setDoc, getDoc, arrayUnion } from "@/firebase";
const state = {
isLoading: false,
error: null
};
const mutations = {
setError(state, error) {
state.error = error;
state.isLoading = false;
},
setLoading(state, isLoading) {
state.isLoading = isLoading;
}
};
const actions = {
async getAndSaveFCMToken({ commit, dispatch }, userId) {
try {
// Request permission from the user to send notifications
const permission = await Notification.requestPermission();
if (permission === "granted") {
console.log("Notification permission granted.");
// Get the FCM token
const token = await getToken(messaging, { vapidKey: process.env.VUE_APP_VAPID_KEY });
if (token) {
//console.log("FCM Token: ", token);
// Save the FCM token to Firestore
dispatch('saveFCMToken', { userId, token });
} else {
commit('setError', "No registration token available.");
console.log("No registration token available.");
}
} else {
commit('setError', "Notification permission denied.");
console.log("Notification permission denied.");
}
} catch (error) {
console.error("An error occurred while getting the FCM token:", error);
commit('setError', "An error occurred while getting the FCM token: ${error}");
}
},
// Save the FCM token to Firestore
async saveFCMToken({ commit}, {userId, token}) {
const tokenRef = doc(db, 'fcmTokens', userId);
try {
const tokenDoc = await getDoc(tokenRef);
if (tokenDoc.exists()) {
// 이미 등록된 토큰이 있는 경우
const tokens = tokenDoc.data().tokens || [];
// Check if the token already exists
const tokenExists = tokens.some(t => t.token === token);
if (!tokenExists) {
// Add the token with creation date using arrayUnion
await updateDoc(tokenRef, {
tokens: arrayUnion({
token: token,
createdAt: new Date()
//createdAt: serverTimestamp() // Store server timestamp as creation date
})
});
console.log('New FCM token added with creation date.');
commit('setError', 'New FCM token added with creation date.');
} else {
console.log('FCM token already exists, no action taken.');
commit('setError', 'FCM token already exists, no action taken.');
}
} else {
// Create a new document if the user does not exist, with the token and creation date
await setDoc(tokenRef, {
tokens: [{
token: token,
createdAt: new Date()
//createdAt: serverTimestamp() // Store server timestamp as creation date
}]
});
console.log('User document created and token saved.');
commit('setError', 'User document created and token saved.');
}
} catch (error) {
commit('setError','Error saving FCM token: ${error}');
console.error('Error saving FCM token:', error);
}
},
resetError({ commit }) {
commit('setError', null);
},
};
const getters = {
isLoading: state => state.isLoading,
error: state => state.error
};
export default {
namespaced: true,
state,
mutations,
actions,
getters
};
'Vue로 PWA 개발' 카테고리의 다른 글
51. mylog FCM 보내기 (2) | 2024.11.01 |
---|---|
50. mylog Firebase Functions (2) | 2024.10.31 |
48. mylog FCM 토큰 등록 (0) | 2024.10.31 |
47. mylog 여러 기기에 알림 (0) | 2024.10.30 |
46. mylog 알림 요청 (0) | 2024.10.30 |