feat: photo upload at level 3 + report a player (nudity avatar / chat insult)
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 2m58s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m9s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 1m0s

Photo upload:
- Lower the custom profile-photo gate from level 25 to level 3 (client const +
  i18n hint + server gate in ProfileService.Update). The level-25 "Expert" title
  is unrelated and unchanged.

Report a player:
- New ReportReason type + service.reportUser(targetId, reason, details?).
- Report entry points: a "گزارش تخلف" button + reason picker (nudity / insult /
  other) in the public-profile modal, and a flag button in the chat header
  (reports the peer for an insulting chat) with a confirmation toast.
- Mock records reports to localStorage; SignalR POSTs /api/report.
- Server: POST /api/report → ProfileService.ReportUser stores the report in the
  write-only ledger (kind="report", ref="{targetId}|{reason}|{details}") so no
  schema change is needed (server uses EnsureCreated, not migrations).
- i18n: report.* keys (fa + en).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-11 19:12:02 +03:30
parent 8033023a1f
commit 6641741669
10 changed files with 165 additions and 8 deletions
+16 -2
View File
@@ -42,7 +42,7 @@ const fa: Dict = {
"achv.unlocksSticker": "استیکر",
"lobby.chooseLeague": "لیگ را انتخاب کنید",
"lobby.lvl": "سطح",
"profile.uploadLocked": "آپلود عکس از سطح ۲۵ فعال می‌شود",
"profile.uploadLocked": "آپلود عکس از سطح ۳ فعال می‌شود",
"forfeit.title": "تسلیم",
"forfeit.ask": "از این بازی تسلیم می‌شوید؟",
@@ -161,6 +161,13 @@ const fa: Dict = {
"city.claimed": "جایزهٔ شهر دریافت شد ✓",
"city.change": "تغییر",
"city.unknown": "نامشخص",
"report.button": "گزارش تخلف",
"report.title": "علت گزارش این کاربر؟",
"report.nudity": "تصویر نامناسب (مستهجن)",
"report.insult": "توهین در گفتگو",
"report.other": "موارد دیگر",
"report.cancel": "انصراف",
"report.done": "گزارش شما ثبت شد. ممنون!",
"chat.empty": "گفتگو را شروع کنید",
"friends.message": "پیام",
@@ -398,7 +405,7 @@ const en: Dict = {
"achv.unlocksSticker": "Sticker",
"lobby.chooseLeague": "Choose a league",
"lobby.lvl": "Lvl",
"profile.uploadLocked": "Photo upload unlocks at level 25",
"profile.uploadLocked": "Photo upload unlocks at level 3",
"forfeit.title": "Forfeit",
"forfeit.ask": "Surrender this match?",
@@ -521,6 +528,13 @@ const en: Dict = {
"city.claimed": "City reward claimed ✓",
"city.change": "Change",
"city.unknown": "Unknown",
"report.button": "Report",
"report.title": "Why are you reporting this player?",
"report.nudity": "Inappropriate photo (nudity)",
"report.insult": "Insulting chat",
"report.other": "Something else",
"report.cancel": "Cancel",
"report.done": "Report submitted. Thank you!",
"chat.empty": "Start the conversation",
"friends.message": "Message",