fix: 避免 entrypoint 覆寫 .env 的 DB 憑證 #11
@@ -4,6 +4,8 @@ import api from '../api/axios'
|
|||||||
import coachApi from '../api/coachAxios'
|
import coachApi from '../api/coachAxios'
|
||||||
import echo from '../plugins/echo'
|
import echo from '../plugins/echo'
|
||||||
import { useNotificationStore } from '../stores/notifications'
|
import { useNotificationStore } from '../stores/notifications'
|
||||||
|
import { useAuthStore } from '../stores/auth'
|
||||||
|
import { useCoachAuthStore } from '../stores/coachAuth'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
bookingId: { type: Number, required: true },
|
bookingId: { type: Number, required: true },
|
||||||
@@ -21,6 +23,12 @@ const otherUserOnline = ref(false)
|
|||||||
const channel = ref(null)
|
const channel = ref(null)
|
||||||
|
|
||||||
const notificationStore = useNotificationStore()
|
const notificationStore = useNotificationStore()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const coachAuthStore = useCoachAuthStore()
|
||||||
|
|
||||||
|
const currentUserId = computed(() =>
|
||||||
|
props.currentUserType === 'provider' ? coachAuthStore.user?.id : authStore.user?.id
|
||||||
|
)
|
||||||
|
|
||||||
const isConfirmed = computed(() => props.bookingStatus === 'confirmed')
|
const isConfirmed = computed(() => props.bookingStatus === 'confirmed')
|
||||||
const isCompleted = computed(() => props.bookingStatus === 'completed')
|
const isCompleted = computed(() => props.bookingStatus === 'completed')
|
||||||
@@ -91,6 +99,19 @@ async function sendText() {
|
|||||||
const content = textInput.value.trim()
|
const content = textInput.value.trim()
|
||||||
textInput.value = ''
|
textInput.value = ''
|
||||||
isSending.value = true
|
isSending.value = true
|
||||||
|
|
||||||
|
const tempId = `_temp_${Date.now()}`
|
||||||
|
messages.value.push({
|
||||||
|
id: tempId,
|
||||||
|
sender_id: currentUserId.value,
|
||||||
|
sender_type: props.currentUserType,
|
||||||
|
type: 'text',
|
||||||
|
content,
|
||||||
|
read_at: null,
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
})
|
||||||
|
scrollToBottom()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await axiosInstance.value.post(`/bookings/${props.bookingId}/messages`, {
|
await axiosInstance.value.post(`/bookings/${props.bookingId}/messages`, {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@@ -98,6 +119,7 @@ async function sendText() {
|
|||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
textInput.value = content
|
textInput.value = content
|
||||||
|
messages.value = messages.value.filter(m => m.id !== tempId)
|
||||||
} finally {
|
} finally {
|
||||||
isSending.value = false
|
isSending.value = false
|
||||||
}
|
}
|
||||||
@@ -142,6 +164,16 @@ function subscribeChannel() {
|
|||||||
if (e.user_type === otherType.value) otherUserOnline.value = e.online
|
if (e.user_type === otherType.value) otherUserOnline.value = e.online
|
||||||
})
|
})
|
||||||
.listen('.MessageSent', async (e) => {
|
.listen('.MessageSent', async (e) => {
|
||||||
|
if (e.sender_type === props.currentUserType) {
|
||||||
|
// 自己送的訊息:替換樂觀更新的暫存訊息(避免重複)
|
||||||
|
const tempIdx = messages.value.findIndex(
|
||||||
|
m => typeof m.id === 'string' && m.id.startsWith('_temp_') && m.content === e.content
|
||||||
|
)
|
||||||
|
if (tempIdx !== -1) {
|
||||||
|
messages.value[tempIdx] = { id: e.id, sender_id: e.sender_id, sender_type: e.sender_type, type: e.type, content: e.content, read_at: null, created_at: e.created_at }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
id: e.id,
|
id: e.id,
|
||||||
sender_id: e.sender_id,
|
sender_id: e.sender_id,
|
||||||
@@ -153,7 +185,6 @@ function subscribeChannel() {
|
|||||||
})
|
})
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
if (e.sender_type !== props.currentUserType) {
|
if (e.sender_type !== props.currentUserType) {
|
||||||
// 對方傳來的訊息:推瀏覽器通知、刷新 bell badge
|
|
||||||
showBrowserNotification(e)
|
showBrowserNotification(e)
|
||||||
notificationStore.fetchUnreadCount()
|
notificationStore.fetchUnreadCount()
|
||||||
await markLastRead()
|
await markLastRead()
|
||||||
@@ -177,17 +208,32 @@ function handleReconnected() {
|
|||||||
subscribeChannel()
|
subscribeChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback:presence channel 失效時,收到 bell 通知也補拉訊息
|
||||||
|
async function handleNotificationFallback() {
|
||||||
|
const lastId = messages.value[messages.value.length - 1]?.id
|
||||||
|
if (lastId && typeof lastId === 'string') return // 還在樂觀更新中,不拉
|
||||||
|
await loadHistory()
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await requestBrowserNotificationPermission()
|
await requestBrowserNotificationPermission()
|
||||||
await loadHistory()
|
await loadHistory()
|
||||||
if (isConfirmed.value) {
|
if (isConfirmed.value) {
|
||||||
subscribeChannel()
|
subscribeChannel()
|
||||||
echo.connector.pusher.connection.bind('reconnected', handleReconnected)
|
echo.connector.pusher.connection.bind('reconnected', handleReconnected)
|
||||||
|
if (currentUserId.value) {
|
||||||
|
echo.private(`App.Models.User.${currentUserId.value}`)
|
||||||
|
.listen('.notification.created', handleNotificationFallback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
echo.connector.pusher.connection.unbind('reconnected', handleReconnected)
|
echo.connector.pusher.connection.unbind('reconnected', handleReconnected)
|
||||||
|
if (currentUserId.value) {
|
||||||
|
echo.private(`App.Models.User.${currentUserId.value}`)
|
||||||
|
.stopListening('.notification.created', handleNotificationFallback)
|
||||||
|
}
|
||||||
if (channel.value) {
|
if (channel.value) {
|
||||||
channel.value.whisper('presence', { user_type: props.currentUserType, online: false })
|
channel.value.whisper('presence', { user_type: props.currentUserType, online: false })
|
||||||
echo.leave(`booking.${props.bookingId}`)
|
echo.leave(`booking.${props.bookingId}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user