all repos — stealth-developers @ 4cdbb9b271bdd3f8da8da6b6f43e0834fe69fbb4

apps/web/src/components/Tickets/TicketMessages.vue (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
<script setup lang="ts">
import type {
	SanitisedActor,
	SanitisedTicketAttachment,
	SanitisedTicketMessage,
} from "@stealth-developers/api";

import { computed } from "vue";

import MessageGroup from "./MessageGroup.vue";

const props = defineProps<{
	messages: SanitisedTicketMessage[];
	attachments: SanitisedTicketAttachment[];
	actorMap: Record<string, SanitisedActor>;
}>();

const groupedMessages = computed(() => {
	const groups: SanitisedTicketMessage[][] = [];
	let currentGroup: SanitisedTicketMessage[] = [];

	for (const msg of props.messages) {
		if (currentGroup.length === 0) {
			currentGroup.push(msg);
		} else {
			const lastMsg = currentGroup[currentGroup.length - 1]!;
			if (
				lastMsg.actorId === msg.actorId &&
				lastMsg.actorRole === msg.actorRole &&
				lastMsg.isPrivate === msg.isPrivate
			) {
				currentGroup.push(msg);
			} else {
				groups.push(currentGroup);
				currentGroup = [msg];
			}
		}
	}

	if (currentGroup.length > 0) {
		groups.push(currentGroup);
	}
	return groups;
});

const attachmentsByMessageId = computed(() => {
	const map: Record<string, SanitisedTicketAttachment[]> = {};
	for (const att of props.attachments) {
		const msgId = att.messageId || att.ticketMessageId;
		if (msgId) {
			if (!map[msgId]) {
				map[msgId] = [];
			}
			map[msgId].push(att);
		}
	}
	return map;
});
</script>

<template>
	<div class="ticket-messages">
		<h2>Messages</h2>
		<div class="messages-container" v-if="groupedMessages.length > 0">
			<MessageGroup
				v-for="(group, index) in groupedMessages"
				:key="index"
				:group="group"
				:actorMap="props.actorMap"
				:attachmentsByMessageId="attachmentsByMessageId"
			/>
		</div>
		<div v-else class="no-messages">No messages in this ticket.</div>
	</div>
</template>

<style scoped>
.ticket-messages {
	display: flex;
	flex-direction: column;
	background-color: hsl(var(--crust));
	border-radius: 1.5rem;
	overflow: hidden;

	h2 {
		padding: 0.5rem 1rem;
		font-size: 1.5rem;
		font-weight: 800;
		color: hsl(var(--text));
	}

	.messages-container {
		display: flex;
		flex-direction: column;
	}

	.no-messages {
		color: hsl(var(--subtext0));
		font-style: italic;
		font-size: 0.95rem;
		padding: 1rem 0;
	}
}
</style>