Files
simrsx-fe/app/components/pub/base/summary-card/summary-card.vue

72 lines
2.2 KiB
Vue

<script setup lang="ts">
import type { Summary } from './type'
import { ChevronDown, ChevronUp } from 'lucide-vue-next'
import { cn } from '~/lib/utils'
const props = defineProps<{
stat?: Summary
isSkeleton?: boolean
}>()
const timeFrame = computed((): string => {
if (!props.stat?.timeframe) return 'from unknown timeframe'
let word: string = ''
switch (props.stat.timeframe) {
case 'daily':
word = 'from yesterday'
break
case 'weekly':
word = 'from last week'
break
case 'monthly':
word = 'from last month'
break
case 'yearly':
word = 'from last year'
break
}
return word
})
const isTrending = computed<boolean>(() => (props.stat?.trend ?? 0) > 0)
</script>
<template>
<Card v-if="props.isSkeleton">
<CardHeader class="flex flex-row items-center justify-between pb-2">
<Skeleton class="h-6 w-32 bg-gray-100 text-sm font-medium" />
<Skeleton class="h-4 w-4 bg-gray-100" />
</CardHeader>
<CardContent>
<Skeleton class="mb-2 h-6 w-48 bg-gray-100 text-2xl" />
<Skeleton v-if="props.stat?.trend" class="h-4 w-64 bg-gray-100 text-xs font-medium" />
</CardContent>
</Card>
<Card v-else-if="props.stat && !props.isSkeleton" class="h-42">
<CardHeader class="flex flex-row items-center justify-between pb-2">
<CardTitle class="text-sm font-medium"> {{ props.stat.title }} </CardTitle>
<component :is="props.stat.icon" class="bg-primary h-[40px] w-auto rounded-md p-2 text-white" />
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
{{ props.stat.metric.toLocaleString('id-ID') }}
</div>
<p v-if="props.stat.trend !== 0" class="text-muted-foreground flex items-center gap-1 text-xs">
<component
:is="isTrending ? ChevronUp : ChevronDown"
:class="cn('h-4 w-4', { 'text-green-500': isTrending }, { 'text-red-500': !isTrending })"
/>
<span :class="cn('font-medium', { 'text-green-500': isTrending }, { 'text-red-500': !isTrending })">
{{ props.stat.trend.toFixed(1) }}%
<!-- {{ Math.abs(props.stat.trend).toFixed(1) }}% -->
</span>
<span>{{ timeFrame }}</span>
</p>
</CardContent>
</Card>
</template>
<style scoped></style>