Shop: every item is coin-priced; level/rank/achievement only gate the purchase
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 6m29s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m8s
CI/CD / Deploy - local stack (db + server + web) (push) Has been cancelled

No more earned-only (rank/wins) cosmetics — every avatar, card back/front,
reaction & sticker pack now has a coin price. Rank/wins/achievement become
purchase requirements (coin · coin+rank · coin+rank+achievement), enforced
client (mock + ShopScreen lock label) and server (ProfileService.ItemGate,
keyed by kind:id). Ownership = default + purchased only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-07 21:27:25 +03:30
parent ccfc9b0536
commit 72efc03e2d
6 changed files with 137 additions and 78 deletions
+5
View File
@@ -101,6 +101,11 @@ export function ShopScreen() {
const lockLabel = (item: ShopItem): string | null => {
if (item.reqLevel && profile.level < item.reqLevel) return `${t("shop.reqLevel")} ${item.reqLevel}`;
if (item.reqRating && profile.rating < item.reqRating) return `${t("shop.reqRating")} ${item.reqRating}`;
if (item.reqAchievement && !(profile.unlocked ?? []).includes(item.reqAchievement)) {
const ach = achievementById(item.reqAchievement);
const name = ach ? (locale === "fa" ? ach.nameFa : ach.nameEn) : item.reqAchievement;
return `${t("shop.reqAchv")} ${name}`;
}
return null;
};