Improve social milestone sharing flow

This commit is contained in:
2026-08-14 12:31:10 +02:00
parent e0c32542f9
commit 925540f3c6
11 changed files with 400 additions and 121 deletions

View File

@@ -39,6 +39,18 @@ export function milestoneThreshold(kind: string): number | null {
export type SocialLocale = 'en' | 'de';
export type SocialMilestoneCard = {
version: 'milestone-card-v2';
language: SocialLocale;
qrTitle: string;
label: string;
title: string;
totalUniqueScans: number;
milestoneThreshold: number;
reachedAt: string;
trend: { periodDays: number; series: number[]; recentTotal: number } | null;
};
export function socialLocale(value?: string | null): SocialLocale {
return value === 'de' ? 'de' : 'en';
}
@@ -63,6 +75,37 @@ export function buildMilestoneCard(primaryUseCase: string | null, threshold: num
return { version: 'milestone-card-v1', language: locale, threshold, label: usageLabel(primaryUseCase, locale), title: locale === 'de' ? 'Erfolgsmeilenstein' : 'Success milestone' };
}
export function buildMilestonePostForQr(primaryUseCase: string | null, totalUniqueScans: number, xHandle: string | null | undefined, locale: SocialLocale, qrTitle: string): string {
const count = totalUniqueScans.toLocaleString(locale === 'de' ? 'de-DE' : 'en-US');
const subject = qrTitle.trim() || usageLabel(primaryUseCase, locale);
const base = locale === 'de'
? `${subject}“ hat ${count} eindeutige Scans erreicht.`
: `${subject}” reached ${count} unique scans.`;
return xHandle ? `${base} By @${xHandle.replace(/^@/, '')}.` : base;
}
export function buildMilestoneCardSnapshot(input: {
primaryUseCase: string | null;
qrTitle: string;
totalUniqueScans: number;
milestoneThreshold: number;
reachedAt: Date;
trend: { periodDays: number; series: number[]; recentTotal: number } | null;
locale: SocialLocale;
}): SocialMilestoneCard {
return {
version: 'milestone-card-v2',
language: input.locale,
qrTitle: input.qrTitle,
label: usageLabel(input.primaryUseCase, input.locale),
title: input.locale === 'de' ? 'Erfolgsmeilenstein' : 'Success milestone',
totalUniqueScans: input.totalUniqueScans,
milestoneThreshold: input.milestoneThreshold,
reachedAt: input.reachedAt.toISOString(),
trend: input.trend,
};
}
export function normalizeXHandle(value: string): string | null {
const handle = value.trim().replace(/^@/, '');
return /^[A-Za-z0-9_]{1,15}$/.test(handle) ? handle : null;