HomeSales.vue 3.04 KB
<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 { locale, t } = useAppI18n()

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 dateFormatter = computed(() => {
  return new Intl.DateTimeFormat(locale.value === 'zh-CN' ? 'zh-CN' : 'en-US', {
    day: 'numeric',
    month: 'short',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false
  })
})

const currencyFormatter = computed(() => {
  return new Intl.NumberFormat(locale.value === 'zh-CN' ? 'zh-CN' : 'en-US', {
    style: 'currency',
    currency: 'EUR'
  })
})

const columns = computed<TableColumn<Sale>[]>(() => [
  {
    accessorKey: 'id',
    header: t('home.sales.id'),
    cell: ({ row }) => `#${row.getValue('id')}`
  },
  {
    accessorKey: 'date',
    header: t('home.sales.date'),
    cell: ({ row }) => dateFormatter.value.format(new Date(row.getValue('date')))
  },
  {
    accessorKey: 'status',
    header: t('home.sales.status'),
    cell: ({ row }) => {
      const status = row.getValue('status') as Sale['status']
      const color = {
        paid: 'success' as const,
        failed: 'error' as const,
        refunded: 'neutral' as const
      }[status]

      return h(UBadge, { class: 'capitalize', variant: 'subtle', color }, () =>
        t(`home.sales.statusMap.${status}`)
      )
    }
  },
  {
    accessorKey: 'email',
    header: t('home.sales.email')
  },
  {
    accessorKey: 'amount',
    header: () => h('div', { class: 'text-right' }, t('home.sales.amount')),
    cell: ({ row }) => {
      const amount = Number.parseFloat(row.getValue('amount'))
      return h('div', { class: 'text-right font-medium' }, currencyFormatter.value.format(amount))
    }
  }
])
</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>