| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- <template>
- <div class="w-full py-4">
- <div class="flex items-center justify-between relative">
- <!-- Background line -->
- <div class="absolute left-0 top-1/2 -translate-y-1/2 w-full h-1 bg-border/50 rounded-full z-0"></div>
-
- <!-- Colored line up to current step -->
- <div
- class="absolute left-0 top-1/2 -translate-y-1/2 h-1 bg-primary rounded-full z-0 transition-all duration-1000 ease-in-out"
- :style="{ width: progressWidth }"
- ></div>
- <!-- Steps -->
- <div
- v-for="(step, i) in steps"
- :key="step.id"
- class="relative z-10 flex flex-col items-center gap-2"
- :class="[i <= currentIndex ? 'opacity-100' : 'opacity-40 grayscale']"
- >
- <div
- class="w-8 h-8 sm:w-10 sm:h-10 rounded-full flex items-center justify-center transition-all duration-500 shadow-sm"
- :class="[
- i < currentIndex ? 'bg-primary text-primary-foreground' :
- i === currentIndex ? 'bg-primary text-primary-foreground ring-4 ring-primary/20 animate-pulse' :
- 'bg-card border-2 border-border text-muted-foreground'
- ]"
- >
- <component :is="step.icon" class="w-4 h-4 sm:w-5 sm:h-5" />
- </div>
- <span class="text-[10px] sm:text-xs font-bold whitespace-nowrap hidden sm:block" :class="i <= currentIndex ? 'text-foreground' : 'text-muted-foreground'">
- {{ step.label }}
- </span>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { computed } from 'vue';
- import { Clock, ShieldCheck, Printer, Truck, PackageCheck, XCircle } from 'lucide-vue-next';
- import { useI18n } from 'vue-i18n';
- const props = defineProps<{
- status: string;
- }>();
- const { t } = useI18n();
- const steps = computed(() => {
- if (props.status === 'cancelled') {
- return [
- { id: 'pending', icon: Clock, label: t('statuses.pending') },
- { id: 'cancelled', icon: XCircle, label: t('statuses.cancelled') }
- ];
- }
- return [
- { id: 'pending', icon: Clock, label: t('statuses.pending') },
- { id: 'processing', icon: ShieldCheck, label: t('statuses.approved') },
- { id: 'printing', icon: Printer, label: t('statuses.printing') },
- { id: 'shipped', icon: Truck, label: t('statuses.shipped') },
- { id: 'completed', icon: PackageCheck, label: t('statuses.delivered') }
- ];
- });
- const currentIndex = computed(() => {
- // If printing doesn't exist in actual DB, we map processing->processing
- // but if the status is "printing", we'd use it.
- // Standard statuses: pending, processing, shipped, completed
- const map: Record<string, number> = {
- 'pending': 0,
- 'processing': 1,
- 'printing': 2,
- 'shipped': 3,
- 'completed': 4,
- 'cancelled': 1
- };
- return map[props.status] ?? 0;
- });
- const progressWidth = computed(() => {
- if (steps.value.length === 0) return '0%';
- return `${(currentIndex.value / (steps.value.length - 1)) * 100}%`;
- });
- </script>
|