fix: format peer metrics with contracted units
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#f1f1f3" />
|
<meta name="theme-color" content="#f1f1f3" />
|
||||||
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
<script>
|
<script>
|
||||||
(() => {
|
(() => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
type ReportingPeriod,
|
type ReportingPeriod,
|
||||||
} from '$lib/api/client';
|
} from '$lib/api/client';
|
||||||
import { formatDate, formatMilliseconds, formatMoney, formatPercent, formatValue } from '$lib/format';
|
import { formatDate, formatMilliseconds, formatMoney, formatPercent, formatValue } from '$lib/format';
|
||||||
|
import { formatPeerMetric, peerMetricLabel } from '$lib/peer-metrics';
|
||||||
import DetailsPanel from './DetailsPanel.svelte';
|
import DetailsPanel from './DetailsPanel.svelte';
|
||||||
import MetricCard from './MetricCard.svelte';
|
import MetricCard from './MetricCard.svelte';
|
||||||
import SectionFrame from './SectionFrame.svelte';
|
import SectionFrame from './SectionFrame.svelte';
|
||||||
@@ -414,8 +415,8 @@
|
|||||||
{#each peers.data.metrics as metric}<div
|
{#each peers.data.metrics as metric}<div
|
||||||
class="grid grid-cols-[1fr_auto_auto] items-center gap-3 border-t border-[var(--border)] p-4 text-sm"
|
class="grid grid-cols-[1fr_auto_auto] items-center gap-3 border-t border-[var(--border)] p-4 text-sm"
|
||||||
>
|
>
|
||||||
<span class="ltr text-left">{metric.metricId}</span><span
|
<span>{peerMetricLabel(metric.metricId)}</span><span
|
||||||
>{formatPercent(metric.cohortMedian)}</span
|
>{formatPeerMetric(metric.metricId, metric.cohortMedian)}</span
|
||||||
><strong class="text-[var(--brand)]"
|
><strong class="text-[var(--brand)]"
|
||||||
>{formatPercent(metric.merchantPerformancePercentile)}</strong
|
>{formatPercent(metric.merchantPerformancePercentile)}</strong
|
||||||
>
|
>
|
||||||
|
|||||||
21
src/lib/peer-metrics.test.ts
Normal file
21
src/lib/peer-metrics.test.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import { formatPeerMetric, peerMetricLabel } from './peer-metrics';
|
||||||
|
|
||||||
|
describe('peer metric presentation', () => {
|
||||||
|
it('formats timing medians in milliseconds instead of percent', () => {
|
||||||
|
expect(formatPeerMetric('init_time_ms_p50', '1240')).toBe('۱٬۲۴۰ میلیثانیه');
|
||||||
|
expect(formatPeerMetric('verify_time_ms_p95', '980')).toBe('۹۸۰ میلیثانیه');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('formats rate medians as percentages', () => {
|
||||||
|
expect(formatPeerMetric('payment_success_rate', '87.25')).toBe('۸۷٫۲۵٪');
|
||||||
|
expect(formatPeerMetric('paid_fee_rate', '0.5')).toBe('۰٫۵٪');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('provides Persian labels for every contracted peer metric', () => {
|
||||||
|
expect(peerMetricLabel('payment_success_rate')).toBe('نرخ موفقیت پرداخت');
|
||||||
|
expect(peerMetricLabel('init_time_ms_p95')).toBe('زمان آغاز پرداخت — صدک ۹۵');
|
||||||
|
expect(peerMetricLabel('verify_time_ms_p50')).toBe('زمان تأیید — میانه');
|
||||||
|
});
|
||||||
|
});
|
||||||
30
src/lib/peer-metrics.ts
Normal file
30
src/lib/peer-metrics.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import type { components } from '$lib/api/schema';
|
||||||
|
import { formatMilliseconds, formatPercent } from '$lib/format';
|
||||||
|
|
||||||
|
export type PeerMetricId = components['schemas']['PeerMetric']['metricId'];
|
||||||
|
|
||||||
|
const labels = {
|
||||||
|
payment_success_rate: 'نرخ موفقیت پرداخت',
|
||||||
|
verification_completion_rate: 'نرخ تکمیل تأیید',
|
||||||
|
retry_recovery_rate: 'نرخ بازیابی تلاش مجدد',
|
||||||
|
init_time_ms_p50: 'زمان آغاز پرداخت — میانه',
|
||||||
|
init_time_ms_p95: 'زمان آغاز پرداخت — صدک ۹۵',
|
||||||
|
verify_time_ms_p50: 'زمان تأیید — میانه',
|
||||||
|
verify_time_ms_p95: 'زمان تأیید — صدک ۹۵',
|
||||||
|
paid_fee_rate: 'نرخ کارمزد پرداختشده',
|
||||||
|
} satisfies Record<PeerMetricId, string>;
|
||||||
|
|
||||||
|
const timingMetrics = new Set<PeerMetricId>([
|
||||||
|
'init_time_ms_p50',
|
||||||
|
'init_time_ms_p95',
|
||||||
|
'verify_time_ms_p50',
|
||||||
|
'verify_time_ms_p95',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function peerMetricLabel(metricId: PeerMetricId): string {
|
||||||
|
return labels[metricId];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatPeerMetric(metricId: PeerMetricId, value: string): string {
|
||||||
|
return timingMetrics.has(metricId) ? formatMilliseconds(Number(value)) : formatPercent(value);
|
||||||
|
}
|
||||||
5
static/favicon.svg
Normal file
5
static/favicon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="تحلیل زرینپال">
|
||||||
|
<rect width="64" height="64" rx="16" fill="#ffd400"/>
|
||||||
|
<path d="M17 18h30v8H28l19 20H17v-8h19L17 18Z" fill="#19191a"/>
|
||||||
|
<circle cx="47" cy="18" r="5" fill="#0a33ff"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 292 B |
Reference in New Issue
Block a user