style(reports): simplify timeline ui and update composer integration
This commit is contained in:
+55
-43
@@ -31,7 +31,10 @@ const statusHistory = computed(() => (reportData.value as any)?.history || [])
|
|||||||
const messages = computed(() => (messagesData.value as any)?.messages || [])
|
const messages = computed(() => (messagesData.value as any)?.messages || [])
|
||||||
|
|
||||||
const newMessage = ref('')
|
const newMessage = ref('')
|
||||||
|
const fileInput = ref<HTMLInputElement | null>(null)
|
||||||
|
const selectedFiles = ref<File[]>([])
|
||||||
const isSubmittingMessage = ref(false)
|
const isSubmittingMessage = ref(false)
|
||||||
|
|
||||||
const isFeedbackOpen = ref(false)
|
const isFeedbackOpen = ref(false)
|
||||||
const feedbackRating = ref(5)
|
const feedbackRating = ref(5)
|
||||||
const feedbackComment = ref('')
|
const feedbackComment = ref('')
|
||||||
@@ -39,14 +42,28 @@ const isSubmittingFeedback = ref(false)
|
|||||||
const selectedMediaIndex = ref(0)
|
const selectedMediaIndex = ref(0)
|
||||||
const isGalleryOpen = ref(false)
|
const isGalleryOpen = ref(false)
|
||||||
|
|
||||||
|
// Gestione selezione file
|
||||||
|
const handleFileSelect = (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement
|
||||||
|
if (target.files) {
|
||||||
|
selectedFiles.value = Array.from(target.files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Invia messaggio
|
// Invia messaggio
|
||||||
const handleSendMessage = async (msgText: string, files: File[]) => {
|
const handleSendMessage = async () => {
|
||||||
if (!msgText.trim() && files.length === 0) return
|
if (!newMessage.value.trim() && selectedFiles.value.length === 0) return
|
||||||
|
|
||||||
isSubmittingMessage.value = true
|
isSubmittingMessage.value = true
|
||||||
try {
|
try {
|
||||||
// Gestione mock di file, nella realtà si usa FormData o simle
|
// Gestione mock di file, nella realtà si usa FormData o simile
|
||||||
await addMessage(reportId, { body: msgText })
|
await addMessage(reportId, { body: newMessage.value })
|
||||||
|
|
||||||
|
// Pulisci i campi
|
||||||
|
newMessage.value = ''
|
||||||
|
selectedFiles.value = []
|
||||||
|
if (fileInput.value) fileInput.value.value = ''
|
||||||
|
|
||||||
await refreshMessages()
|
await refreshMessages()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error sending message:', error)
|
console.error('Error sending message:', error)
|
||||||
@@ -75,7 +92,10 @@ const handleSubmitFeedback = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isOwner = computed(() => report.value?.user_id === user.value?.id)
|
const isOwner = computed(() => report.value?.user_id === user.value?.id)
|
||||||
const canFeedback = computed(() => report.value?.status === 'RESOLVED' || report.value?.status === 'CLOSED')
|
|
||||||
|
// Valutazione solo se lo stato è specificamente "RESOLVED"
|
||||||
|
const canFeedback = computed(() => report.value?.status === 'RESOLVED')
|
||||||
|
|
||||||
const statusMeta: Record<string, { label: string; tone: string }> = {
|
const statusMeta: Record<string, { label: string; tone: string }> = {
|
||||||
OPEN: { label: 'Aperta', tone: 'info' },
|
OPEN: { label: 'Aperta', tone: 'info' },
|
||||||
UNDER_REVIEW: { label: 'In revisione', tone: 'warning' },
|
UNDER_REVIEW: { label: 'In revisione', tone: 'warning' },
|
||||||
@@ -180,30 +200,21 @@ const formatDate = (dateString: string): string => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="statusHistory.length > 0" class="card card-bg border-0 shadow-sm mb-4">
|
<div class="card card-bg border-0 shadow-sm mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="report-section-head mb-4">
|
<h2 class="h6 mb-3">Cronologia eventi</h2>
|
||||||
<BIIcon name="it-history" size="sm" color="primary" class="me-2" />
|
<div v-if="statusHistory.length === 0" class="small text-muted">Nessun evento registrato.</div>
|
||||||
<h2 class="h6 mb-0">Cronologia</h2>
|
<ul class="list-unstyled mb-0 ms-2">
|
||||||
</div>
|
<li v-for="item in statusHistory" :key="item.id" class="mb-3 border-start border-primary border-3 ps-3">
|
||||||
<div class="timeline">
|
<small class="text-muted d-block">{{ formatDate(item.created_at) }}</small>
|
||||||
<div v-for="item in statusHistory" :key="item.id" class="timeline-item mb-3">
|
<div class="d-flex align-items-center gap-2 mt-1">
|
||||||
<div class="d-flex gap-3">
|
|
||||||
<div class="flex-shrink-0">
|
|
||||||
<div class="timeline-marker"></div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1">
|
|
||||||
<small class="text-muted">{{ formatDate(item.created_at) }}</small>
|
|
||||||
<div class="small font-weight-semibold d-flex align-items-center gap-2 mt-1">
|
|
||||||
<StatusBadge :status="item.old_status" />
|
<StatusBadge :status="item.old_status" />
|
||||||
<BIIcon name="it-arrow-right" size="xs" />
|
<BIIcon name="it-arrow-right" size="xs" />
|
||||||
<StatusBadge :status="item.new_status" />
|
<StatusBadge :status="item.new_status" />
|
||||||
</div>
|
</div>
|
||||||
<small v-if="item.note" class="text-muted d-block">{{ item.note }}</small>
|
<div v-if="item.note" class="small mt-1 bg-light p-1 rounded">{{ item.note }}</div>
|
||||||
</div>
|
</li>
|
||||||
</div>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -219,8 +230,10 @@ const formatDate = (dateString: string): string => {
|
|||||||
</div>
|
</div>
|
||||||
<span class="badge bg-light text-dark border">{{ messages.length }} messaggi</span>
|
<span class="badge bg-light text-dark border">{{ messages.length }} messaggi</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MessageList :messages="messages" />
|
<MessageList :messages="messages" />
|
||||||
<MessageComposer @send="handleSendMessage" />
|
|
||||||
|
<MessageComposer @send=handleSendMessage />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -408,23 +421,25 @@ const formatDate = (dateString: string): string => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-marker {
|
/* Stili specifici per l'input della Chat per gestire le tue richieste visive */
|
||||||
width: 12px;
|
.chat-textarea {
|
||||||
height: 12px;
|
resize: none !important;
|
||||||
background-color: #006f9d;
|
height: 48px;
|
||||||
border-radius: 50%;
|
min-height: 48px;
|
||||||
border: 3px solid #f0f0f0;
|
overflow-y: auto;
|
||||||
|
padding-top: 12px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-item:not(:last-child) .timeline-marker::after {
|
.btn-square {
|
||||||
content: '';
|
width: 48px;
|
||||||
position: absolute;
|
height: 48px;
|
||||||
left: 50%;
|
padding: 0;
|
||||||
top: 20px;
|
display: flex;
|
||||||
width: 2px;
|
align-items: center;
|
||||||
height: calc(100% + 20px);
|
justify-content: center;
|
||||||
background-color: #006f9d;
|
border-radius: 6px;
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ratio {
|
.ratio {
|
||||||
@@ -457,6 +472,3 @@ const formatDate = (dateString: string): string => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user