Moderator notes WIP (#144)

This commit is contained in:
John Livingston 2024-07-30 18:36:53 +02:00
parent 31c4e5a646
commit 704e660f37
No known key found for this signature in database
GPG Key ID: B17B5640CE66CDBC
11 changed files with 164 additions and 21 deletions

View File

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
//
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { tplMucNoteOccupant } from '../templates/muc-note-occupant'
import { api } from '@converse/headless'
import '../styles/muc-note-occupant.scss'
export default class MUCNoteOccupantView extends CustomElement {
static get properties () {
return {
model: { type: Object, attribute: true },
full_display: { type: Boolean, attribute: true }
}
}
async initialize () {
this.listenTo(this.model, 'change', () => this.requestUpdate())
}
render () {
return tplMucNoteOccupant(this, this.model)
}
}
api.elements.define('livechat-converse-muc-note-occupant', MUCNoteOccupantView)

View File

@ -14,7 +14,8 @@ export default class MUCNotesView extends DraggablesCustomElement {
return {
model: { type: Object, attribute: true },
create_note_error_message: { type: String, attribute: false },
create_note_opened: { type: Boolean, attribute: false }
create_note_opened: { type: Boolean, attribute: false },
create_note_for_occupant: { type: Object, attribute: false }
}
}
@ -41,9 +42,10 @@ export default class MUCNotesView extends DraggablesCustomElement {
return tplMucNotes(this, this.model)
}
async openCreateNoteForm (ev) {
async openCreateNoteForm (ev, occupant) {
ev?.preventDefault?.()
this.create_note_opened = true
this.create_note_for_occupant = occupant ?? undefined
await this.updateComplete
const textarea = this.querySelector('.notes-create-note textarea[name="description"]')
if (textarea) {
@ -54,6 +56,7 @@ export default class MUCNotesView extends DraggablesCustomElement {
closeCreateNoteForm (ev) {
ev?.preventDefault?.()
this.create_note_opened = false
this.create_note_for_occupant = undefined
}
async submitCreateNote (ev) {

View File

@ -11,6 +11,7 @@ import { initOrDestroyChatRoomNotes, getHeadingButtons, getMessageActionButtons
import './components/muc-note-app-view.js'
import './components/muc-notes-view.js'
import './components/muc-note-view.js'
import './components/muc-note-occupant-view.js'
converse.plugins.add('livechat-converse-notes', {
dependencies: ['converse-muc', 'converse-disco', 'converse-pubsub'],

View File

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
.conversejs {
livechat-converse-muc-note-occupant {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-between;
padding: 0.25em;
& > a {
display: flex;
flex-flow: row nowrap;
align-items: center;
span {
font-weight: bold;
margin-left: 0.5em;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
}
}
& > ul {
list-style: none;
text-align: right;
}
}
}

View File

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
//
// SPDX-License-Identifier: AGPL-3.0-only
import { html } from 'lit'
import { api } from '@converse/headless'
import { getAuthorStyle } from '../../../../src/utils/color.js'
import { __ } from 'i18n'
export function tplMucNoteOccupant (el, occupant) {
const authorStyle = getAuthorStyle(occupant)
const jid = occupant.get('jid')
const occupantId = occupant.get('occupant_id')
return html`
<a @click=${(ev) => {
api.modal.show('converse-muc-occupant-modal', { model: occupant }, ev)
}}>
<converse-avatar
.model=${occupant}
class="avatar chat-msg__avatar"
name="${occupant.getDisplayName()}"
nonce=${occupant.vcard?.get('vcard_updated')}
height="30" width="30"></converse-avatar>
<span style=${authorStyle}>${occupant.getDisplayName()}</span>
</a>
${
el.full_display
? html`<ul>
${jid ? html`<li title=${__('XMPP Address')}>${jid}</li>` : ''}
${occupantId ? html`<li title=${__('Occupant Id')}>${occupantId}</li>` : ''}
</ul>`
: ''
}
`
}

View File

@ -50,12 +50,32 @@ function _tplNoteForm (note) {
</fieldset>`
}
export function tplMucCreateNoteForm (notesEl) {
function _tplNoteOccupantFormFields (occupant) {
if (!occupant) { return '' }
return html`
<input type="hidden" name="occupant_nick" value=${occupant.get('nick')} />
<input type="hidden" name="occupant_jid" value=${occupant.get('jid')} />
<input type="hidden" name="occupant_id" value=${occupant.get('occupant_id')} />
`
}
export function tplMucCreateNoteForm (notesEl, occupant) {
const i18nOk = __('Ok')
const i18nCancel = __('Cancel')
return html`
<form class="notes-create-note converse-form" @submit=${notesEl.submitCreateNote}>
${
occupant
? html`
${_tplNoteOccupantFormFields(occupant)}
<livechat-converse-muc-note-occupant
full_display=${true}
.model=${occupant}
></livechat-converse-muc-note-occupant>
`
: ''
}
${_tplNoteForm(undefined)}
<fieldset class="form-group">
<input type="submit" class="btn btn-primary" value="${i18nOk}" />

View File

@ -14,7 +14,7 @@ export default function tplMucNotes (el, notes) {
return html`
${
el.create_note_opened ? tplMucCreateNoteForm(el) : tplCreateButton(el)
el.create_note_opened ? tplMucCreateNoteForm(el, el.create_note_for_occupant) : tplCreateButton(el)
}
${
repeat(notes, (note) => note.get('id'), (note) => {

View File

@ -48,23 +48,33 @@ export function getMessageActionButtons (messageActionsEl, buttons) {
return buttons
}
// TODO: button to create a note from a message.
// // eslint-disable-next-line no-undef
// const i18nCreate = __(LOC_task_create)
if (messageModel.occupant) {
// eslint-disable-next-line no-undef
const i18nCreate = __(LOC_moderator_note_create_for_participant)
// buttons.push({
// i18n_text: i18nCreate,
// handler: async (ev) => {
// ev.preventDefault()
// api.modal.show('livechat-converse-pick-task-list-modal', {
// muc,
// message: messageModel
// }, ev)
// },
// button_class: '',
// icon_class: 'fa fa-list-check',
// name: 'muc-task-create-from-message'
// })
buttons.push({
i18n_text: i18nCreate,
handler: async (ev) => {
ev.preventDefault()
const appElement = document.querySelector('livechat-converse-muc-note-app')
if (!appElement) {
throw new Error('Cant find Note App Element')
}
await appElement.showApp()
await appElement.updateComplete // waiting for the app to be open
const notesElement = appElement.querySelector('livechat-converse-muc-notes')
if (!notesElement) {
throw new Error('Cant find Notes Element')
}
await notesElement.updateComplete
notesElement.openCreateNoteForm(undefined, messageModel.occupant)
},
button_class: '',
icon_class: 'fa fa-note-sticky',
name: 'muc-note-create-for-occupant'
})
}
return buttons
}

View File

@ -76,6 +76,14 @@ export class MUCApp extends CustomElement {
}
}
showApp () {
if (!this.show) { return this.toggleApp() }
}
hideApp () {
if (this.show) { return this.toggleApp() }
}
_closeOtherApps () {
document.querySelectorAll('.livechat-converse-muc-app').forEach((el) => {
if (el !== this && el.show) {

View File

@ -55,7 +55,8 @@ const locKeys = [
'moderator_note_create',
'moderator_note_description',
'moderator_note_delete',
'moderator_note_delete_confirm'
'moderator_note_delete_confirm',
'moderator_note_create_for_participant'
]
module.exports = locKeys

View File

@ -600,3 +600,4 @@ moderator_note_create: 'Create a new note'
moderator_note_description: 'Description'
moderator_note_delete: 'Delete note'
moderator_note_delete_confirm: 'Are you sure you want to delete this note?'
moderator_note_create_for_participant: 'Create a new note for this participant'