mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 23:16:21 +00:00
ccebcad8a8
Player experience: - Tiered win celebration overlay (WheelWinReveal): quiet message for the "nothing" slice, lighter reveal for common prizes, full confetti + jackpot glow for rare ones. Rarity classified client-side by type + amount (wheelPrizeTier), shared icon rendering (wheelPrizeIcon). - Three-phase spin motion (wind-back -> overshoot -> settle) with a reduced-motion fast path; responsive wheel scaling via ResizeObserver. Reveal-timing fix: - The server pushes the refreshed winners list (which already contains the just-won prize) the instant it answers the spin, ~5s before the wheel stops. useFortuneWheel now buffers that update mid-spin and flushes it in finishSpin so the prize is no longer spoiled in the winners panel. - handleTransitionEnd only reacts to the wheel's own transform transition, so a child icon's bubbling transitionend can't advance the spin phase machine early. Prize editor (admin): - Add/Remove prize buttons in FortuneWheelSettingsView. New rows carry a negative temp id collapsed to 0 on the wire (server inserts); removed rows are simply omitted (server soft-disables). Requires the matching emulator change to WheelManager.savePrize / WheelAdminSavePrizesEvent. i18n: wheel.win.* and rarevalues.editor.add/remove in en/it/nl.
56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { CREDITS_RARE_THRESHOLD, getPrizeTier, POINTS_RARE_THRESHOLD } from './wheelPrizeTier';
|
|
|
|
const makePrize = (overrides: Partial<{ type: string; amount: number }>) => ({
|
|
id: 1,
|
|
type: 'credits',
|
|
spriteId: 0,
|
|
badgeCode: '',
|
|
amount: 0,
|
|
pointsType: -1,
|
|
label: '',
|
|
...overrides
|
|
}) as any;
|
|
|
|
describe('getPrizeTier', () =>
|
|
{
|
|
it('returns "common" for a null prize (defensive default)', () =>
|
|
{
|
|
expect(getPrizeTier(null)).toBe('common');
|
|
});
|
|
|
|
it('classifies the "nothing" slice as "none"', () =>
|
|
{
|
|
expect(getPrizeTier(makePrize({ type: 'nothing' }))).toBe('none');
|
|
});
|
|
|
|
it('classifies items and badges as "rare"', () =>
|
|
{
|
|
expect(getPrizeTier(makePrize({ type: 'item' }))).toBe('rare');
|
|
expect(getPrizeTier(makePrize({ type: 'badge' }))).toBe('rare');
|
|
});
|
|
|
|
it('classifies a free spin as "common"', () =>
|
|
{
|
|
expect(getPrizeTier(makePrize({ type: 'spin', amount: 1 }))).toBe('common');
|
|
});
|
|
|
|
it('tiers credits by the threshold', () =>
|
|
{
|
|
expect(getPrizeTier(makePrize({ type: 'credits', amount: CREDITS_RARE_THRESHOLD - 1 }))).toBe('common');
|
|
expect(getPrizeTier(makePrize({ type: 'credits', amount: CREDITS_RARE_THRESHOLD }))).toBe('rare');
|
|
expect(getPrizeTier(makePrize({ type: 'credits', amount: CREDITS_RARE_THRESHOLD + 1000 }))).toBe('rare');
|
|
});
|
|
|
|
it('tiers points by the threshold', () =>
|
|
{
|
|
expect(getPrizeTier(makePrize({ type: 'points', amount: POINTS_RARE_THRESHOLD - 1 }))).toBe('common');
|
|
expect(getPrizeTier(makePrize({ type: 'points', amount: POINTS_RARE_THRESHOLD }))).toBe('rare');
|
|
});
|
|
|
|
it('falls back to "common" for unknown prize types', () =>
|
|
{
|
|
expect(getPrizeTier(makePrize({ type: 'mystery-future-type' }))).toBe('common');
|
|
});
|
|
});
|