Hi,
I'm building a simple chat box for support section of an online shop with Laravel, Vue.js 3 and Inertia.
I need when a new message seen by user, a request sent to server and set "seen" column at the "messages" table to true.
At first I did this, at the moment of loading page I assume user see every new message so I send a all-new-msgs-seen to server:
const postSeen = (msgid, userid) => {
Inertia.post(route('messages.seen'), {
message_id: msgid,
other_user: userid,
});
};
onMounted(() => {
postSeen('all', props.otherUser.id);
})
in MessageController:
public function seen(Request $request)
{
$validated = $request->validate([
'message_id' => 'required',
'other_user' => 'required',
]);
if($validated['message_id'] == 'all'){
Message::where('sender', $validated['other_user'])
->where('receiver', Auth::id())
->update(['seen' => true]);
}else{
$message = Message::find($validated['message_id']);
$message->seen = true;
$message->save();
}
}
It works correctly.
But it's a bad idea. Because when users are chatting and a new message loaded dynamically and seen by other user it doesn't send any request to server. I think I need recognize any message that get visible for user.
So I decide use useElementVisibility from vueUse library for this.
I want when a message get visible on the screen (so user seen the message) a request sent to server.
When i using useElementVisibility for checking just one element visibility it's simple but my issue is how I should put an array of messages to useElementVisibility and when each of them get visible send the request to server?
const seenMessage = ref([]);
const skipUnwrap = { seenMessage } // This line is just because of a Vue bug.
let messageIsVisible = useElementVisibility(seenMessage); //This is wrong! What is right?
<div v-for="message in messages">
<div v-if="message.sender !== $page.props.auth.user.id"
class="flex w-full mt-2 space-x-3 max-w-xs">
<div class="flex-shrink-0 h-10 w-10 rounded-full bg-gray-300"></div>
<div>
<div :ref="skipUnwrap.seenMessage"
class="bg-gray-300 p-3 rounded-r-lg rounded-bl-lg">
<p class="text-sm">{{ message.message }}</p>
</div>
<span class="text-xs text-gray-500 leading-none">
{{ formatedDateTime(message.created_at) }}
</span>
</div>
</div>
<div v-else> ...
I was thinking about it for a day and my brain is kinda locked and I don't have any idea for solving this problem.
FYI I'm new in front-end stuff, vue and js is too complicated to me yet!
I would be happy if you my friends give me a solution or a clue to know what I should to do.
Thank you.