Refine order detail status layout

This commit is contained in:
Ruslan Bakiev
2026-04-06 20:58:08 +07:00
parent aabebe9b90
commit f1129199bd
4 changed files with 179 additions and 64 deletions

View File

@@ -1,6 +1,10 @@
<script setup lang="ts">
import OrderStatusBadge from '~/components/orders/OrderStatusBadge.vue';
import { getOrderStatusPresentation } from '~/composables/useOrderStatusPresentation';
import {
getOrderStatusBadgePresentation,
getOrderStatusPresentation,
type OrderStatusTone,
} from '~/composables/useOrderStatusPresentation';
const props = defineProps<{
status: string;
@@ -11,10 +15,53 @@ const props = defineProps<{
const isExpanded = ref(false);
const presentation = computed(() => getOrderStatusPresentation(props.status, props.createdAt, props.audience ?? 'client'));
const currentBadge = computed(() => getOrderStatusBadgePresentation(props.status));
function currentToneClass(tone: OrderStatusTone) {
if (tone === 'success') {
return {
marker: 'bg-[#139957] ring-4 ring-[#dff4e8]',
panel: 'bg-[#eef8f2]',
title: 'text-[#123824]',
note: 'text-[#355947]',
date: 'text-[#139957]',
connector: 'bg-[#bfe0cb]',
};
}
if (tone === 'danger') {
return {
marker: 'bg-[#d94b55] ring-4 ring-[#fbe5e7]',
panel: 'bg-[#fff1f2]',
title: 'text-[#7e2130]',
note: 'text-[#9b4150]',
date: 'text-[#d94b55]',
connector: 'bg-[#f1c6cb]',
};
}
if (tone === 'warning') {
return {
marker: 'bg-[#f1a43a] ring-4 ring-[#fff0d9]',
panel: 'bg-[#fff7eb]',
title: 'text-[#6c4303]',
note: 'text-[#8f6420]',
date: 'text-[#c67d11]',
connector: 'bg-[#efd1a2]',
};
}
return {
marker: 'bg-[#2e8de4] ring-4 ring-[#e3effb]',
panel: 'bg-[#eef5fc]',
title: 'text-[#174b7e]',
note: 'text-[#436b92]',
date: 'text-[#2e8de4]',
connector: 'bg-[#c7dbef]',
};
}
function markerClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return 'bg-[#139957] ring-4 ring-[#dff4e8]';
return currentToneClass(currentBadge.value.tone).marker;
}
if (state === 'done') {
return 'bg-[#9dcfb0]';
@@ -24,7 +71,9 @@ function markerClass(state: 'done' | 'current' | 'upcoming') {
function connectorClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'done' || state === 'current') {
return 'bg-[#cfe5d7]';
return state === 'current'
? currentToneClass(currentBadge.value.tone).connector
: 'bg-[#cfe5d7]';
}
return 'bg-[#e4ece7]';
@@ -32,7 +81,7 @@ function connectorClass(state: 'done' | 'current' | 'upcoming') {
function titleClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return 'text-[#123824]';
return currentToneClass(currentBadge.value.tone).title;
}
if (state === 'done') {
return 'text-[#355947]';
@@ -43,7 +92,7 @@ function titleClass(state: 'done' | 'current' | 'upcoming') {
function noteClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return 'text-[#355947]';
return currentToneClass(currentBadge.value.tone).note;
}
if (state === 'done') {
return 'text-[#557562]';
@@ -51,6 +100,28 @@ function noteClass(state: 'done' | 'current' | 'upcoming') {
return 'text-[#7d9688]';
}
function stagePanelClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return currentToneClass(currentBadge.value.tone).panel;
}
if (state === 'done') {
return 'bg-[#f3f7f4]';
}
return 'bg-[#f7faf8]';
}
function dateClass(state: 'done' | 'current' | 'upcoming') {
if (state === 'current') {
return currentToneClass(currentBadge.value.tone).date;
}
if (state === 'done') {
return 'text-[#5c7b69]';
}
return 'text-[#86a091]';
}
</script>
<template>
@@ -60,17 +131,19 @@ function noteClass(state: 'done' | 'current' | 'upcoming') {
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>
<div class="space-y-3">
<div class="flex flex-wrap items-center gap-3">
<h2 class="text-2xl font-black leading-tight text-[#123824]">
{{ presentation.title }}
</h2>
<OrderStatusBadge :status="status" />
</div>
<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 }"
@@ -97,22 +170,24 @@ function noteClass(state: 'done' | 'current' | 'upcoming') {
/>
</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 }}
<div class="min-w-0 flex-1 pb-5">
<div
class="rounded-[22px] px-4 py-4 transition-colors"
:class="stagePanelClass(stage.state)"
>
<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]" :class="dateClass(stage.state)">
{{ stage.dateLabel }}
</p>
</div>
<p class="mt-2 text-sm leading-6" :class="noteClass(stage.state)">
{{ stage.note }}
</p>
</div>
<p class="mt-2 text-sm leading-6" :class="noteClass(stage.state)">
{{ stage.note }}
</p>
</div>
</div>
</div>