Public Access
feat(points): show points result on every status save
Core now settles on GET /api/rewards/games/{appid}. The Frontend
shows a toast, refreshes the header balance, and lists the paid
rows and reasons on the game page. Deploy Core first.
This commit is contained in:
1 parent
9adc606c57
commit
814decc781
20 files changed
+429
-12
No files matched your search
@@ -0,0 +1,43 @@
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
import {useTranslation} from 'react-i18next';
|
||||
import usePointsCheck from '../hooks/usePointsCheck.js';
|
||||
import {formatDate} from '../utils/format.js';
|
||||
import {STATUS_NOT_REACHED} from '../utils/rewards.js';
|
||||
|
||||
const WAITING = {NO_PROOF: 'POINTS.GAME.WAITING', NO_PLAY_AFTER_START: 'POINTS.GAME.WAITING_START'};
|
||||
|
||||
/**
|
||||
* What the game earned: one line per paid row and one per kind that is missing, with the reason from Core. Loading it
|
||||
* settles the points; a status change after the first load also shows the points toast.
|
||||
*/
|
||||
export default function GamePointsLine({game}) {
|
||||
const {t, i18n} = useTranslation();
|
||||
const check = usePointsCheck();
|
||||
const [points, setPoints] = useState(null);
|
||||
const lastStatus = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const changed = lastStatus.current !== null && lastStatus.current !== game.status;
|
||||
lastStatus.current = game.status;
|
||||
let stale = false;
|
||||
check(game.appid, {status: game.status, tell: changed}).then((data) => {
|
||||
if (!stale && data) setPoints(data);
|
||||
});
|
||||
return () => {
|
||||
stale = true;
|
||||
};
|
||||
}, [check, game.appid, game.status]);
|
||||
|
||||
if (!points) return null;
|
||||
const kindText = (kind) => t(`POINTS.KINDS.${kind}`);
|
||||
const lines = [
|
||||
...points.paid.map((row) => t('POINTS.GAME.PAID', {
|
||||
kind: kindText(row.kind), points: row.points,
|
||||
date: formatDate(row.paidAt, i18n.language, {dateStyle: 'medium'}),
|
||||
}) + (row.appid === game.appid ? '' : ` ${t('POINTS.GAME.OTHER_EDITION')}`)),
|
||||
...Object.entries(points.missing).filter(([, reason]) => !STATUS_NOT_REACHED.includes(reason)).map(([kind, reason]) => (
|
||||
WAITING[reason] ? t(WAITING[reason])
|
||||
: t('POINTS.GAME.NONE', {kind: kindText(kind), reason: t(`POINTS.REASONS.${reason}`)}))),
|
||||
];
|
||||
return lines.map((line, i) => <p key={i} className="text-sm text-muted-foreground">{line}</p>);
|
||||
}
|
||||
Reference in new issue
Block a user