<div class="messenger"></div>
<div class="messenger"></div>
/* No context defined. */
<?php
namespace Theme\Views\Molecules\messenger;
use ACFToolkit\Types\CustomMolecule;
class Messenger extends CustomMolecule
{
public string $name = 'messenger';
public string $label = 'Messenger';
public int $needsJs = 0;
public int $needsVue = 1;
public int $needsVueInitialisation = 1;
public function __construct($name = '', $title = '', $children = [])
{
parent::__construct($name, $title);
$this->addChildren(array_merge($children, [
]));
}
}
<?php
namespace Theme\Views\Molecules\messenger;
use ACFToolkit\ViewModels\BaseViewModel;
class MessengerViewModel extends BaseViewModel
{
}
<template>
<div :class="{'mb-1 flex-basis-1/2': true, 'self-start': from_id !== id, 'self-end': from_id === id}">
<strong v-text="from"></strong>
<p v-text="body"></p>
<small v-text="date"></small>
</div>
</template>
<script>
/* IMPORTS */
import {mapGetters} from 'vuex';
export default {
components: {},
props: {
body: {
type: String
},
from: {
type: String
},
date: {
type: String
},
isNew: {
type: Boolean
},
from_id: {
type: String
}
},
data: () => {
return {}
},
computed: {
...mapGetters('Member', ['id']),
getThreads() {
},
getClass(){
return this.id === this.from_id
}
},
methods: {
},
async created() {
}
}
</script>
.messenger {
}
<template>
<div class="flex flex-col rounded-md border border-lighter px-1 h-full" v-if="!loading && id">
<div class="header flex justify-between items-center py-1.5 h-1/10">
<icon
type="iconoir"
icon="nav-arrow-left"
class-name="cursor-pointer"
@click="goBack"
/>
<button
@click="createNewMessage"
class="flex justify-between items-center gap-x-1"
>
<Headline
:headline="$t('Neue Nachricht')"
type="h3"
class-name="cursor-pointer"
/>
<icon
type="iconoir"
icon="edit-pencil"
/>
</button>
</div>
<div class="flex flex-row relative h-9/10 gap-x-2">
<div class="threads w-full h-full sm:w-auto sm:basis-1/3">
<Thread
:active="currentThread && currentThread.id === thread.id"
v-for="thread in threads"
:subject="thread.subject"
:preview="thread.preview"
:id="thread.id"
:creator="thread.creator"
:participants="thread.participants"
:unread-messages="thread.unreadMessagesCount"
:is-new="thread.isNew"
@click="selectThread(thread)"
/>
</div>
<div :class="{
'absolute justify-between h-full w-full sm:w-auto bg-white sm:relative right-0 sm:right-auto sm:translate-x-0 flex flex-col sm:basis-2/3': 1,
'translate-x-full': !currentThread,
'translate-x-0': currentThread
}">
<div class="flex flex-col h-7/10">
<Headline
v-if="currentThread"
:headline="getFromLine(currentThread)"
type="h3"
class-name="sm:hidden text-center mb-1"
/>
<div class="messages flex flex-col h-full overflow-scroll">
<label v-if="(currentThread && currentThread.isNew)" v-text="$t('Empfänger')"></label>
<AutoComplete
v-model="query"
:suggestions="recipientItems"
@complete="getRecipients"
multiple
@item-select="addRecipient"
option-label="name"
data-key="id"
class="w-full mb-1"
v-if="currentThread && currentThread.isNew"
/>
<Message
v-for="message in currentMessages"
:body="message.body"
:from="message.from"
:date="message.date"
:from_id="message.from_id"
/>
</div>
</div>
<div class="flex flex-col gap-y-0.5">
<div>
<label v-if="(currentThread && currentThread.isNew)" v-text="$t('Nachricht')"></label>
<textarea
v-model="newMessage"
rows="4"
v-if="currentMessages && currentMessages.length || (currentThread && currentThread.isNew)"
class="mb-1"
></textarea>
</div>
<CustomButton
v-if="newMessage && newMessage.trim() !== ''"
:cta="$t('Nachricht absenden')"
@click="sendMessage"
type="x-btn--accent"
/>
</div>
</div>
</div>
</div>
</template>
<script>
/* IMPORTS */
import Thread from './thread.vue';
import Message from './message.vue';
import CustomButton from '../../Atoms/button/button.vue';
import AutoComplete from 'primevue/autocomplete';
import MemberService from '../../Assets/src/js/services/MemberService';
import MessageService from '../../Assets/src/js/services/MessageService';
import Headline from '../../Atoms/headline/headline.vue';
import Icon from '../../Atoms/icon/icon.vue';
import {mapGetters} from 'vuex';
export default {
components: {
Icon,
Headline,
CustomButton,
Thread,
Message,
AutoComplete
},
props: {
initialThreads: {
type: Array,
},
},
data: () => {
return {
query: '',
recipients: [],
recipientItems: [],
currentThread: null,
threads: [],
messages: {},
currentMessages: [],
newMessage: ''
}
},
computed: {
...mapGetters('Member', ['id', 'name', 'loading']),
getThreads() {
},
getFirstThread() {
return this.initialThreads.threads[0] || null
},
},
methods: {
goBack() {
window.history.back()
},
getFromLine(thread) {
return [thread.creator, thread.participants]
.filter(item => item && (item.trim() !== ''))
.join(', ')
},
async getRecipients($e) {
const {data} = await MemberService.getMembers({query: $e.query})
this.recipientItems = data
},
async addRecipient(e) {
this.recipients.push(e.value.id)
},
async sendMessage() {
const {data} = this.currentThread.isNew ?
await MessageService.createThread({
message: this.newMessage,
recipients: this.recipients
}) :
await MessageService.updateThread({
threadId: this.currentThread.id,
message: this.newMessage,
})
this.currentMessages.push(data.data)
},
createNewMessage() {
const thread = {
subject: this.$t('Neue Nachricht'),
isNew: true,
messages: []
}
this.newMessage = ''
this.threads.unshift(thread)
this.currentThread = thread
this.currentMessages = this.currentThread.messages
},
getInitialMessages() {
const initialThread = this.getFirstThread
this.currentThread = initialThread
this.currentMessages = initialThread ? initialThread.messages : []
},
selectThread(thread) {
this.newMessage = ''
this.currentThread = thread
this.currentMessages = thread.messages
}
},
async created() {
this.threads = this.initialThreads.threads
if (innerWidth > 768)
this.getInitialMessages()
}
}
</script>
<style lang="scss">
.messenger-container {
height: 80dvh;
}
.p-autocomplete {
ul {
@apply w-full gap-0.5 border border-grey rounded-md px-1 py-0.5 text-primary placeholder-primary/90 bg-lighter outline-accent;
}
.p-autocomplete-token {
@apply bg-white gap-x-0.5 px-0.5 py-0.25 rounded-md;
}
input {
}
}
</style>
<template>
<div :class="{'thread mb-0.5 p-0.5 rounded-md': 1, 'bg-accent': active}">
<strong v-if="isNew" v-text="subject"></strong>
<strong
v-if="unreadMessagesCount > 0"
v-text="fromLine"
></strong>
<p
class="from"
v-else
v-text="fromLine"
:title="fromLine"
></p>
<p v-text="preview"></p>
</div>
</template>
<script>
/* IMPORTS */
export default {
components: {},
props: {
active: {
type: Boolean
},
subject: {
type: String,
},
preview: {
type: String,
},
id: {
type: Number,
},
unreadMessagesCount: {
type: Number,
},
creator: {
type: String,
},
participants: {
type: String,
},
isNew: {
type: Boolean,
}
},
data: () => {
return {
}
},
computed: {
fromLine(){
return [this.creator, this.participants]
.filter(item => item && (item.trim() !== ''))
.join(', ')
}
},
methods: {
},
async created(){
}
}
</script>
<style lang="scss">
.thread {
@apply cursor-pointer;
}
.from {
@apply overflow-ellipsis text-ellipsis;
}
</style>
{% include '@molecules/messenger/messenger.twig' with {
} only %}Fields