Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions apps/web-app/app/components/chart/KitchenRevenue.client.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<template>
<UCard ref="cardRef" :ui="{ root: 'overflow-visible', body: '!px-0 !pt-0 !pb-3' }">
<template #header>
<div>
<p class="text-xs text-muted uppercase mb-1.5">
Выручка за {{ data.length }} {{ pluralizationRu(data.length, ['день', 'дня', 'дней']) }}
</p>
<p class="text-3xl text-highlighted font-semibold">
{{ formatNumber(total) }}
</p>
</div>
</template>

<VisXYContainer
:data="data"
:padding="{ top: 40 }"
class="h-96"
:width="width"
>
<VisLine
:x="x"
:y="y"
color="var(--ui-secondary)"
/>
<VisArea
:x="x"
:y="y"
color="var(--ui-secondary)"
:opacity="0.1"
/>

<VisAxis
type="x"
:x="x"
:tick-format="xTicks"
/>

<VisCrosshair
color="var(--ui-secondary)"
:template="template"
/>

<VisTooltip />
</VisXYContainer>
</UCard>
</template>

<script setup lang="ts">
import type { Period, Range } from '#shared/types'
import { VisArea, VisAxis, VisCrosshair, VisLine, VisTooltip, VisXYContainer } from '@unovis/vue'
import { eachDayOfInterval, eachMonthOfInterval, eachWeekOfInterval, format } from 'date-fns'
import { ru } from 'date-fns/locale'

type DataRecord = {
date: Date
total: number
checks: number
}

const { period, range, values } = defineProps<{
period: Period
range: Range
values: { date: string, total: number, checks: number }[]
}>()

const cardRef = useTemplateRef<HTMLElement | null>('cardRef')

const { width } = useElementSize(cardRef)

const data = ref<DataRecord[]>([])

watch([() => period, () => range, () => values], () => {
const dates = ({
daily: eachDayOfInterval,
weekly: eachWeekOfInterval,
monthly: eachMonthOfInterval,
} as Record<Period, typeof eachDayOfInterval>)[period](range)

data.value = dates.map((date) => {
const dateStr = format(date, 'yyyy-MM-dd')
const value = values.find((d) => d.date.startsWith(dateStr))

return {
date,
total: value?.total ?? 0,
checks: value?.checks ?? 0,
}
})
}, { immediate: true })

const x = (_: DataRecord, i: number) => i
const y = (d: DataRecord) => d.total

const total = computed(() => data.value.reduce((acc: number, { total }) => acc + total, 0))

const formatNumber = new Intl.NumberFormat('ru', { style: 'currency', currency: 'RUB', maximumFractionDigits: 0 }).format

function formatDate(date: Date): string {
return ({
daily: format(date, 'd MMMM', { locale: ru }),
weekly: format(date, 'd MMMM', { locale: ru }),
monthly: format(date, 'MMMM yyy', { locale: ru }),
})[period]
}

function xTicks(i: number) {
if (i === 0 || i === data.value.length - 1 || !data.value[i]) {
return ''
}

return formatDate(data.value[i].date)
}

const template = (d: DataRecord) => `${formatDate(d.date)}: ${formatNumber(d.total)}, ${d.checks} ${pluralizationRu(d.checks, ['чек', 'чека', 'чеков'])}`
</script>

<style scoped>
.unovis-xy-container {
--vis-crosshair-line-stroke-color: var(--ui-secondary);
--vis-crosshair-circle-stroke-color: var(--ui-bg);

--vis-axis-grid-color: var(--ui-border);
--vis-axis-tick-color: var(--ui-border);
--vis-axis-tick-label-color: var(--ui-text-dimmed);

--vis-tooltip-background-color: var(--ui-bg);
--vis-tooltip-border-color: var(--ui-border);
--vis-tooltip-text-color: var(--ui-text-highlighted);
}
</style>
16 changes: 15 additions & 1 deletion apps/web-app/app/pages/kitchen/[id]/finance.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
<template>
<Content>
<div>{{ data }}</div>
<ChartKitchenRevenue
:period="period"
:range="range"
:values="data ?? []"
/>
</Content>
</template>

<script setup lang="ts">
import type { Period, Range } from '#shared/types'
import { sub } from 'date-fns'

const { params } = useRoute('kitchen-id')

const { data } = useFetch(`/api/kitchen/id/${params.id}/revenue`)

const range = shallowRef<Range>({
start: sub(new Date(), { days: 14 }),
end: new Date(),
})
const period = ref<Period>('daily')
</script>
7 changes: 7 additions & 0 deletions apps/web-app/shared/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,10 @@ export type PrintWithData = Print & {
export type KitchenWithData = Kitchen & {
feedbackPoints: FeedbackPoint[]
}

export type Period = 'daily' | 'weekly' | 'monthly'

export interface Range {
start: Date
end: Date
}
2 changes: 2 additions & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"@internationalized/date": "catalog:",
"@nuxt/ui": "catalog:",
"@nuxtjs/i18n": "catalog:",
"@unovis/ts": "catalog:",
"@unovis/vue": "catalog:",
"@vueuse/core": "catalog:",
"@vueuse/integrations": "catalog:",
"@vueuse/nuxt": "catalog:",
Expand Down
Loading