feat(gamification): expand activity badge paths

This commit is contained in:
2026-10-02 13:03:22 +03:30
parent 341c7215b3
commit 8c70f5bf01
8 changed files with 27 additions and 28 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@@ -11,12 +11,8 @@ import type { PublicGamificationBadgeSchema } from "@/lib/types";
const badgeProgressionRows = activityLadders.map((ladder) => ({ const badgeProgressionRows = activityLadders.map((ladder) => ({
id: ladder.category, id: ladder.category,
label: ladder.category === "likes" ? "لایک‌های انجمن" : ladder.title, label: ladder.title,
badges: ladder.badges.map((badge) => ({ badges: ladder.badges,
id: badge.id,
label: badge.label,
description: ladder.category === "likes" ? badge.description.replace(/پسند/g, "لایک") : badge.description,
})),
})); }));
export function ActivityBadgePaths({ export function ActivityBadgePaths({

View File

@@ -8,7 +8,7 @@ const categoryLabels: Record<PublicGamificationBadgeSchema["category"], string>
attendance: "رویداد", attendance: "رویداد",
posts: "نویسندگی", posts: "نویسندگی",
comments: "گفت‌وگو", comments: "گفت‌وگو",
likes: "پسندها", likes: "لایک‌ها",
}; };
export function GamificationBadges({ export function GamificationBadges({

View File

@@ -41,22 +41,23 @@ export const activityLadders: ActivityLadderDefinition[] = [
unitLabel: "حضور تأییدشده", unitLabel: "حضور تأییدشده",
pointsPerAction: 30, pointsPerAction: 30,
badges: [ badges: [
{ id: "attendance-1", label: "حضور اول", threshold: 1, description: "حضور تأییدشده در یک رویداد" }, { id: "attendance-1", label: "حضور اول", threshold: 1, description: "حضور تأییدشده در ۱ رویداد" },
{ id: "attendance-5", label: "همراه رویدادها", threshold: 5, description: "حضور تأییدشده در پنج رویداد" }, { id: "attendance-5", label: "همراه رویدادها", threshold: 5, description: "حضور تأییدشده در ۵ رویداد" },
{ id: "attendance-10", label: "همیار رویدادها", threshold: 10, description: "حضور تأییدشده در ده رویداد" }, { id: "attendance-10", label: "همیار رویدادها", threshold: 10, description: "حضور تأییدشده در ۱۰ رویداد" },
{ id: "attendance-25", label: "چهره آشنای رویدادها", threshold: 25, description: "حضور تأییدشده در بیست‌وپنج رویداد" }, { id: "attendance-25", label: "چهره آشنای رویدادها", threshold: 25, description: "حضور تأییدشده در ۲۵ رویداد" },
], ],
}, },
{ {
category: "posts", category: "posts",
title: "نوشته‌های منتشرشده", title: "نوشته‌های منتشرشده",
description: "نوشته‌های منتشرشده و هم‌نویسندگی‌هایی که در انجمن ثبت شده‌اند حساب می‌شوند.", description: "نوشته‌های منتشرشده در انجمن به این مسیر کمک می‌کنند.",
unitLabel: "نوشته منتشرشده یا هم‌نویسندگی", unitLabel: "نوشته منتشرشده",
pointsPerAction: 20, pointsPerAction: 20,
badges: [ badges: [
{ id: "post-1", label: "نویسنده انجمن", threshold: 1, description: "انتشار یا هم‌نویسندگی یک نوشته" }, { id: "post-1", label: "نویسنده انجمن", threshold: 1, description: "۱ نوشته منتشرشده" },
{ id: "post-5", label: "نویسنده فعال", threshold: 5, description: "انتشار یا هم‌نویسندگی پنج نوشته" }, { id: "post-5", label: "نویسنده فعال", threshold: 5, description: "۵ نوشته منتشرشده" },
{ id: "post-10", label: "نویسنده برجسته", threshold: 10, description: "انتشار یا هم‌نویسندگی ده نوشته" }, { id: "post-10", label: "نویسنده برجسته", threshold: 10, description: "۱۰ نوشته منتشرشده" },
{ id: "post-25", label: "نویسنده پیشرو", threshold: 25, description: "۲۵ نوشته منتشرشده" },
], ],
}, },
{ {
@@ -66,21 +67,23 @@ export const activityLadders: ActivityLadderDefinition[] = [
unitLabel: "دیدگاه یا پاسخ تأییدشده", unitLabel: "دیدگاه یا پاسخ تأییدشده",
pointsPerAction: 5, pointsPerAction: 5,
badges: [ badges: [
{ id: "comment-5", label: "اهل گفت‌وگو", threshold: 5, description: "پنج دیدگاه یا پاسخ تأییدشده" }, { id: "comment-1", label: "آغاز گفت‌وگو", threshold: 1, description: "۱ دیدگاه یا پاسخ تأییدشده" },
{ id: "comment-20", label: "همراه گفت‌وگو", threshold: 20, description: "بیست دیدگاه یا پاسخ تأییدشده" }, { id: "comment-5", label: "اهل گفت‌وگو", threshold: 5, description: "۵ دیدگاه یا پاسخ تأییدشده" },
{ id: "comment-50", label: "صدای اثرگذار", threshold: 50, description: "پنجاه دیدگاه یا پاسخ تأییدشده" }, { id: "comment-20", label: "همراه گفت‌وگو", threshold: 20, description: "۲۰ دیدگاه یا پاسخ تأییدشده" },
{ id: "comment-50", label: "صدای اثرگذار", threshold: 50, description: "۵۰ دیدگاه یا پاسخ تأییدشده" },
], ],
}, },
{ {
category: "likes", category: "likes",
title: "پسندهای انجمن", title: "لایک‌های انجمن",
description: "پسندهایی که داده‌اید و پسندهایی که نوشته‌های شما گرفته‌اند با هم شمرده می‌شوند.", description: "این مسیر با لایک‌کردن نوشته‌ها پیش می‌رود؛ لایک‌های دریافتی برای امتیاز کلی حساب می‌شوند، اما در نشان‌های این مسیر شمرده نمی‌شوند.",
unitLabel: "پسند داده‌شده یا دریافت‌شده", unitLabel: "لایک روی نوشته",
pointsPerAction: 1, pointsPerAction: 1,
badges: [ badges: [
{ id: "likes-10", label: "دست‌گرم", threshold: 10, description: "ده پسند داده‌شده یا دریافت‌شده" }, { id: "likes-1", label: "نخستین لایک", threshold: 1, description: "۱ لایک روی یک نوشته" },
{ id: "likes-50", label: "محبوب انجمن", threshold: 50, description: "پنجاه پسند داده‌شده یا دریافت‌شده" }, { id: "likes-10", label: "دست‌گرم", threshold: 10, description: "۱۰ لایک روی نوشته‌ها" },
{ id: "likes-100", label: "الهام‌بخش", threshold: 100, description: "صد پسند داده‌شده یا دریافت‌شده" }, { id: "likes-50", label: "محبوب انجمن", threshold: 50, description: "۵۰ لایک روی نوشته‌ها" },
{ id: "likes-100", label: "الهام‌بخش", threshold: 100, description: "۱۰۰ لایک روی نوشته‌ها" },
], ],
}, },
]; ];
@@ -88,7 +91,7 @@ export const activityLadders: ActivityLadderDefinition[] = [
export const activityPoints = { export const activityPoints = {
save: 1, save: 1,
saveLabel: "ذخیره نوشته امتیاز دارد، اما نشان جداگانه ندارد.", saveLabel: "ذخیره نوشته امتیاز دارد، اما نشان جداگانه ندارد.",
selfLikeLabel: "پسند نوشته خودتان هم برای شما حساب می‌شود.", likeScoringLabel: "لایک‌کردن نوشته‌ها، حتی نوشته خودتان، در امتیاز کلی حساب می‌شود؛ لایک‌های دریافتی هم امتیاز کلی دارند، اما در نشان‌های لایک شمرده نمی‌شوند.",
reversalLabel: "اگر فعالیتی حذف یا نامعتبر شود، امتیاز و نشان وابسته به آن هم بازبینی می‌شود.", reversalLabel: "اگر فعالیتی حذف یا نامعتبر شود، امتیاز و نشان وابسته به آن هم بازبینی می‌شود.",
}; };

View File

@@ -535,7 +535,7 @@ export default function Profile({ initialTab }: { initialTab?: string }) {
<div className="rounded-2xl border border-border/70 bg-muted/45 p-4 text-right shadow-sm dark:bg-background/70"> <div className="rounded-2xl border border-border/70 bg-muted/45 p-4 text-right shadow-sm dark:bg-background/70">
<Heart className="h-5 w-5 text-primary" aria-hidden="true" /> <Heart className="h-5 w-5 text-primary" aria-hidden="true" />
<p className="mt-3 text-2xl font-bold">{formatNumberPersian(gamification?.activity_counts.likes ?? 0)}</p> <p className="mt-3 text-2xl font-bold">{formatNumberPersian(gamification?.activity_counts.likes ?? 0)}</p>
<p className="mt-1 text-sm text-muted-foreground">پسند داده‌شده یا دریافت‌شده</p> <p className="mt-1 text-sm text-muted-foreground">لایک‌های ثبت‌شده روی نوشته‌ها</p>
</div> </div>
<div className="rounded-2xl border border-border/70 bg-muted/45 p-4 text-right shadow-sm dark:bg-background/70"> <div className="rounded-2xl border border-border/70 bg-muted/45 p-4 text-right shadow-sm dark:bg-background/70">
<Activity className="h-5 w-5 text-primary" aria-hidden="true" /> <Activity className="h-5 w-5 text-primary" aria-hidden="true" />

View File

@@ -202,7 +202,7 @@ export default function RankGuide() {
<div className="min-w-0"> <div className="min-w-0">
<p className="text-sm font-semibold">تعامل با نوشته‌ها</p> <p className="text-sm font-semibold">تعامل با نوشته‌ها</p>
<p className="mt-0.5 text-xs leading-5 text-muted-foreground"> <p className="mt-0.5 text-xs leading-5 text-muted-foreground">
{activityPoints.saveLabel} {activityPoints.selfLikeLabel} {activityPoints.saveLabel} {activityPoints.likeScoringLabel}
</p> </p>
</div> </div>
</div> </div>