diff --git a/src/lib/api/schema.d.ts b/src/lib/api/schema.d.ts
index 9ae13cc..69d871b 100644
--- a/src/lib/api/schema.d.ts
+++ b/src/lib/api/schema.d.ts
@@ -723,6 +723,8 @@ export interface components {
PaymentHistoryPoint: {
/** Format: date */
localDate: string;
+ /** @description Tehran-local hour bucket, present only for DAY periods. */
+ localHour?: number;
/** Format: int64 */
totalSessions: number;
/** Format: int64 */
diff --git a/src/lib/components/AnalyticsPage.svelte b/src/lib/components/AnalyticsPage.svelte
index 9387fff..532c276 100644
--- a/src/lib/components/AnalyticsPage.svelte
+++ b/src/lib/components/AnalyticsPage.svelte
@@ -177,14 +177,18 @@
> روند پرداختهای موفق
- برای دیدن مبلغ و تعداد هر روز، روی نقطههای نمودار بروید.
+ برای دیدن مبلغ و تعداد هر {run.period.periodType === 'DAY' ? 'ساعت' : 'روز'}، روی نقطههای
+ نمودار بروید.
{run.period.jalaliLabelFa}
diff --git a/src/lib/components/PaymentHistoryChart.svelte b/src/lib/components/PaymentHistoryChart.svelte
index 67a3292..eabf6e4 100644
--- a/src/lib/components/PaymentHistoryChart.svelte
+++ b/src/lib/components/PaymentHistoryChart.svelte
@@ -5,7 +5,8 @@
import { formatMoney, formatValue } from '$lib/format';
type Point = components['schemas']['PaymentHistoryPoint'];
- let { data }: { data: Point[] } = $props();
+ type PeriodType = components['schemas']['PeriodType'];
+ let { data, periodType }: { data: Point[]; periodType: PeriodType } = $props();
let active = $state(null);
const width = 760;
@@ -40,6 +41,27 @@
);
}
+ function persianHour(value: number) {
+ const hour = new Intl.NumberFormat('fa-IR', {
+ minimumIntegerDigits: 2,
+ maximumFractionDigits: 0,
+ useGrouping: false,
+ }).format(value);
+ return `${hour}:۰۰`;
+ }
+
+ function axisLabel(point: Point) {
+ return periodType === 'DAY' && point.localHour !== undefined
+ ? persianHour(point.localHour)
+ : persianDate(point.localDate);
+ }
+
+ function fullPointLabel(point: Point) {
+ return periodType === 'DAY' && point.localHour !== undefined
+ ? `${persianDate(point.localDate)}، ساعت ${persianHour(point.localHour)}`
+ : persianDate(point.localDate);
+ }
+
function tooltipPosition(point: (typeof positions)[number]) {
const horizontalPercent = (point.x / width) * 100;
const verticalPercent = (point.y / height) * 100;
@@ -104,7 +126,7 @@
fill="var(--muted-foreground)"
font-size="9"
text-anchor="middle"
- direction="rtl">{persianDate(tick.localDate)}{axisLabel(tick)}
{/each}
تاریخ{periodType === 'DAY' ? 'ساعت' : 'تاریخ'}
(active = index)}
onmouseleave={() => (active = null)}
onfocus={() => (active = index)}
@@ -165,7 +187,7 @@
class="rounded-md bg-zinc-950 p-3 text-right text-xs leading-6 text-white shadow-xl"
transition:scale={{ duration: 150, start: 0.96 }}
>
- {persianDate(positions[active].localDate)}
+ {fullPointLabel(positions[active])}
{formatValue(positions[active].bankPaidSessions)} پرداخت موفق
diff --git a/src/lib/components/PaymentHistoryChart.test.ts b/src/lib/components/PaymentHistoryChart.test.ts
new file mode 100644
index 0000000..2f6037a
--- /dev/null
+++ b/src/lib/components/PaymentHistoryChart.test.ts
@@ -0,0 +1,32 @@
+import { render, screen } from '@testing-library/svelte';
+import { describe, expect, it } from 'vitest';
+
+import PaymentHistoryChart from './PaymentHistoryChart.svelte';
+
+describe('PaymentHistoryChart', () => {
+ it('uses Persian hour labels for a one-day period', () => {
+ render(PaymentHistoryChart, {
+ periodType: 'DAY',
+ data: [
+ {
+ localDate: '2026-07-01',
+ localHour: 0,
+ totalSessions: 10,
+ bankPaidSessions: 8,
+ bankPaidAmountRial: 800_000,
+ },
+ {
+ localDate: '2026-07-01',
+ localHour: 12,
+ totalSessions: 14,
+ bankPaidSessions: 11,
+ bankPaidAmountRial: 1_100_000,
+ },
+ ],
+ });
+
+ expect(screen.getByText('۰۰:۰۰')).not.toBeNull();
+ expect(screen.getByText('۱۲:۰۰')).not.toBeNull();
+ expect(screen.getByText('ساعت')).not.toBeNull();
+ });
+});