Files
kondiplo_front/app/javascript/controllers/board_channel_controller.js

74 lines
2.6 KiB
JavaScript

import { Controller } from "@hotwired/stimulus"
import { createConsumer } from "@rails/actioncable"
export default class extends Controller {
static values = {
boardId: Number,
currentParticipantId: Number
}
connect() {
this.channel = createConsumer().subscriptions.create(
{ channel: "BoardChannel", board_id: this.boardIdValue },
{
received: (data) => {
this._insertMessage(data)
}
}
)
this.element.scrollTop = this.element.scrollHeight
}
disconnect() {
if (this.channel) {
this.channel.unsubscribe()
}
}
_insertMessage(data) {
const isMe = data.participant_id === this.currentParticipantIdValue
// 最初の投稿の場合、"まだ投稿がありません"メッセージを消す
const noPostsMessage = document.getElementById("no-posts-message")
if (noPostsMessage) {
noPostsMessage.remove()
}
const html = `
<div class="flex ${isMe ? 'justify-end' : 'justify-start'} mb-4 message-item" id="post_${data.post_id}">
${!isMe ? `
<div class="flex-shrink-0 mr-3">
<span class="inline-flex items-center justify-center h-8 w-8 rounded-full text-xs font-bold border border-gray-300 bg-white text-gray-700 shadow-sm" title="${data.display_name || data.power || '?'}">
${(data.display_name || data.power || '?').substring(0, 2)}
</span>
</div>
` : ''}
<div class="max-w-lg ${isMe ? 'order-1' : 'order-2'}">
<div class="flex items-baseline space-x-2 mb-1 ${isMe ? 'justify-end' : 'justify-start'}">
${!isMe ? `<span class="text-xs font-bold text-gray-900">${data.display_name || data.power || '?'}</span>` : ''}
<span class="text-xs text-gray-500">${data.created_at}</span>
${data.phase ? `<span class="text-xs bg-gray-100 px-1 rounded text-gray-600 border border-gray-200">${data.phase}</span>` : ''}
</div>
<div class="px-4 py-2 rounded-lg shadow-sm text-sm ${isMe ? 'bg-indigo-600 text-white rounded-br-none' : 'bg-white border border-gray-200 text-gray-900 rounded-bl-none'}">
<div>${this._escapeHtml(data.body).replace(/\n/g, '<br>')}</div>
</div>
</div>
</div>
`
this.element.insertAdjacentHTML('afterbegin', html)
// this.element.scrollTop = 0 // 必要ならトップへスクロール
}
_escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;")
}
}