113 lines
2.7 KiB
Vue
113 lines
2.7 KiB
Vue
<script setup lang="ts">
|
|
import { h, resolveComponent } from 'vue'
|
|
import type { TableColumn } from '@nuxt/ui'
|
|
import type { Period, Range, Sale } from '~/types'
|
|
|
|
const props = defineProps<{
|
|
period: Period
|
|
range: Range
|
|
}>()
|
|
|
|
const UBadge = resolveComponent('UBadge')
|
|
|
|
const sampleEmails = [
|
|
'james.anderson@example.com',
|
|
'mia.white@example.com',
|
|
'william.brown@example.com',
|
|
'emma.davis@example.com',
|
|
'ethan.harris@example.com'
|
|
]
|
|
|
|
const { data } = await useAsyncData('sales', async () => {
|
|
const sales: Sale[] = []
|
|
const currentDate = new Date()
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
const hoursAgo = randomInt(0, 48)
|
|
const date = new Date(currentDate.getTime() - hoursAgo * 3600000)
|
|
|
|
sales.push({
|
|
id: (4600 - i).toString(),
|
|
date: date.toISOString(),
|
|
status: randomFrom(['paid', 'failed', 'refunded']),
|
|
email: randomFrom(sampleEmails),
|
|
amount: randomInt(100, 1000)
|
|
})
|
|
}
|
|
|
|
return sales.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
}, {
|
|
watch: [() => props.period, () => props.range],
|
|
default: () => []
|
|
})
|
|
|
|
const columns: TableColumn<Sale>[] = [
|
|
{
|
|
accessorKey: 'id',
|
|
header: 'ID',
|
|
cell: ({ row }) => `#${row.getValue('id')}`
|
|
},
|
|
{
|
|
accessorKey: 'date',
|
|
header: 'Date',
|
|
cell: ({ row }) => {
|
|
return new Date(row.getValue('date')).toLocaleString('en-US', {
|
|
day: 'numeric',
|
|
month: 'short',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false
|
|
})
|
|
}
|
|
},
|
|
{
|
|
accessorKey: 'status',
|
|
header: 'Status',
|
|
cell: ({ row }) => {
|
|
const color = {
|
|
paid: 'success' as const,
|
|
failed: 'error' as const,
|
|
refunded: 'neutral' as const
|
|
}[row.getValue('status') as string]
|
|
|
|
return h(UBadge, { class: 'capitalize', variant: 'subtle', color }, () =>
|
|
row.getValue('status')
|
|
)
|
|
}
|
|
},
|
|
{
|
|
accessorKey: 'email',
|
|
header: 'Email'
|
|
},
|
|
{
|
|
accessorKey: 'amount',
|
|
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
|
cell: ({ row }) => {
|
|
const amount = Number.parseFloat(row.getValue('amount'))
|
|
|
|
const formatted = new Intl.NumberFormat('en-US', {
|
|
style: 'currency',
|
|
currency: 'EUR'
|
|
}).format(amount)
|
|
|
|
return h('div', { class: 'text-right font-medium' }, formatted)
|
|
}
|
|
}
|
|
]
|
|
</script>
|
|
|
|
<template>
|
|
<UTable
|
|
:data="data"
|
|
:columns="columns"
|
|
class="shrink-0"
|
|
:ui="{
|
|
base: 'table-fixed border-separate border-spacing-0',
|
|
thead: '[&>tr]:bg-elevated/50 [&>tr]:after:content-none',
|
|
tbody: '[&>tr]:last:[&>td]:border-b-0',
|
|
th: 'first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r',
|
|
td: 'border-b border-default'
|
|
}"
|
|
/>
|
|
</template>
|