Files
web-frontend/app/components/orders/OrderStatusTimelineCard.vue
2026-04-06 15:21:05 +07:00

121 lines
3.5 KiB
Vue

<script setup lang="ts">
import OrderStatusBadge from '~/components/orders/OrderStatusBadge.vue';
import { getOrderStatusPresentation } from '~/composables/useOrderStatusPresentation';
const props = defineProps<{
status: string;
createdAt: string | Date;
audience?: 'client' | 'manager';
}>();
const isExpanded = ref(false);
const presentation = computed(() => getOrderStatusPresentation(props.status, props.createdAt, props.audience ?? 'client'));
function markerClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return 'bg-[#139957] ring-4 ring-[#dff4e8]';
}
if (state === 'done') {
return 'bg-[#9dcfb0]';
}
return 'bg-[#d8e4dd]';
}
function connectorClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'done' || state === 'current') {
return 'bg-[#cfe5d7]';
}
return 'bg-[#e4ece7]';
}
function titleClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return 'text-[#123824]';
}
if (state === 'done') {
return 'text-[#355947]';
}
return 'text-[#6a8a76]';
}
function noteClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return 'text-[#355947]';
}
if (state === 'done') {
return 'text-[#557562]';
}
return 'text-[#7d9688]';
}
</script>
<template>
<div class="surface-card rounded-3xl p-5">
<button
type="button"
class="flex w-full items-start justify-between gap-4 text-left"
@click="isExpanded = !isExpanded"
>
<div class="space-y-2">
<h2 class="text-2xl font-black leading-tight text-[#123824]">
{{ presentation.title }}
</h2>
<p class="max-w-2xl text-sm leading-6 text-[#355947]">
{{ presentation.summary }}
</p>
</div>
<div class="flex items-center gap-3 pt-1">
<OrderStatusBadge :status="status" />
<span
class="flex h-10 w-10 items-center justify-center rounded-full bg-[#f2f5f3] text-[#123824] transition-transform"
:class="{ 'rotate-180': isExpanded }"
>
<svg class="h-4 w-4" viewBox="0 0 20 20" fill="none">
<path d="M5 7.5L10 12.5L15 7.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</div>
</button>
<div v-if="isExpanded" class="mt-5 pt-1">
<div
v-for="(stage, index) in presentation.stages"
:key="stage.code"
class="flex gap-4"
>
<div class="flex w-4 shrink-0 flex-col items-center">
<span class="mt-1 h-3 w-3 rounded-full" :class="markerClass(stage.state)" />
<span
v-if="index < presentation.stages.length - 1"
class="mt-2 w-px flex-1"
:class="connectorClass(stage.state)"
/>
</div>
<div
class="min-w-0 flex-1 pb-5"
:class="index < presentation.stages.length - 1 ? 'border-b border-[#e1ebe4]' : ''"
>
<div class="flex flex-wrap items-center justify-between gap-2">
<p class="text-sm font-semibold" :class="titleClass(stage.state)">
{{ stage.label }}
</p>
<p class="text-xs font-semibold uppercase tracking-[0.12em] text-[#5c7b69]">
{{ stage.dateLabel }}
</p>
</div>
<p class="mt-2 text-sm leading-6" :class="noteClass(stage.state)">
{{ stage.note }}
</p>
</div>
</div>
</div>
</div>
</template>