@msflib/react-lottery¶
Standalone lottery module built on TanStack Query.
Install¶
pnpm add @msflib/react-lottery
Peer deps¶
- react >= 18
- @tanstack/react-query >= 5
Usage¶
Wrap your app with the module Provider inside your QueryClientProvider.
In Next.js App Router, Provider must be in a client component (
"use client").
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { LotteryProvider, useLottery } from '@msflib/react-lottery';
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<LotteryProvider options={{ requireAuth: true, isAuthenticated: true }}>
<LotteryList />
</LotteryProvider>
</QueryClientProvider>;
function LotteryList() {
const { lotteries, myEntries, loading, createEntry } = useLottery();
if (loading.lotteries) return <p>Loading…</p>;
return (
<ul>
{lotteries.map((lottery) => (
<li key={lottery.id}>
{lottery.name} — prize: {lottery.prize}
<button
disabled={loading.createEntry}
onClick={() => createEntry(lottery.id, { number: 7 })}
>
Enter with number 7
</button>
</li>
))}
</ul>
);
}
The provider auto-fetches both lotteries and the current user's myEntries (across all lotteries) on mount, each paginated via options.query (offset/limit, default { offset: 0, limit: 100 }).
Admin lottery access¶
Alongside the student-facing /lottery routes, the backend exposes /admin/lottery routes for instructor/admin surfaces — create/update/delete a lottery, and inspect entries/winners across the whole workspace or for one lottery. These are off by default; opt in with enableAdminAccess, the same way @msflib/react-tasks gates its promotion/demotion flows:
<LotteryProvider options={{ enableAdminAccess: true }}>
{children}
</LotteryProvider>
When enabled, the provider automatically loads GET /admin/lottery/entries and GET /admin/lottery/winners (both paginated via options.query) and exposes:
const {
adminEntries,
adminWinners,
createLottery,
updateLottery,
deleteLottery,
listAllEntries,
listAllWinners,
listLotteryEntries,
listLotteryWinners,
} = useLottery();
adminEntries/adminWinners— the current workspace-wide admin listings ([]until loaded, and always[]whenenableAdminAccessis off).createLottery(data, options?)/updateLottery(id, data, options?)/deleteLottery(id, options?)— manage lotteries. These are always exposed on context regardless ofenableAdminAccess(matchingpromoteTask/demoteTaskinreact-tasks) — only the automatic fetch is gated.listAllEntries(params?, options?)/listAllWinners(params?, options?)— on-demand fetch with different pagination.listLotteryEntries(lotteryId, params?, options?)/listLotteryWinners(lotteryId, params?, options?)— entries/winners scoped to one lottery.
Entries¶
myEntries— the current user's entries across all lotteries (GET /lottery/entries).getUserEntry(lotteryId, options?)— fetch the current user's entry for one specific lottery (GET /lottery/{id}/entry).createEntry(lotteryId, data, options?)— submit a number for a lottery (POST /lottery/{id}/entries).
Fetching a single lottery¶
Use getLottery from context for an on-demand fetch, or the standalone useGetLottery hook for a declarative, cache-backed read:
import { useGetLottery } from '@msflib/react-lottery';
function LotteryDetail({ lotteryId }: { lotteryId: number }) {
const { data: lottery, isPending } = useGetLottery(lotteryId);
if (isPending) return <p>Loading…</p>;
return <h2>{lottery?.name}</h2>;
}
useGetLottery is disabled (no request fired) while lotteryId is undefined.
Background task¶
runBackgroundTask() triggers the lottery draw/processing job (POST /background-tasks/lottery) — a global, non-workspace-scoped endpoint (it has no workspace_slug in its path), mirroring runWorker in @msflib/react-documents.
Options¶
| Key | Type | Default | Description |
|---|---|---|---|
isWorkspaceScoped |
boolean |
true |
If true, lotteries are isolated per active workspace. |
requireAuth |
boolean |
false |
If true, lotteries are only fetched once isAuthenticated is true. |
isAuthenticated |
boolean |
false |
The authentication status of the user (e.g. from useAuth().status). |
enableAdminAccess |
boolean |
false |
If true, also loads the workspace-wide admin entries/winners on mount. |
query |
object |
— | { offset?, limit? } used for every list fetched on mount (lotteries, myEntries, adminEntries, adminWinners). |
Endpoints¶
Configure paths through configureApplication({ endpoints: { lottery } }).
| Key | Default path | Methods / routes |
|---|---|---|
lottery |
/lottery |
list (GET, supports offset/limit); detail (GET on /{id}); /entries (GET, all my entries); /{id}/entry (GET, my entry for one lottery); /{id}/entries (POST, submit a number) |
adminLottery |
/admin/lottery |
create (POST); update/delete on /{id} (PUT/DELETE); /entries and /winners (GET, workspace-wide); /{id}/entries and /{id}/winners (GET, per-lottery) |
backgroundTask |
/background-tasks/lottery |
POST — not workspace-scoped |
Notes:
- All lottery/adminLottery endpoints are workspace-scoped (they send the workspace header/prefix).
- runBackgroundTask is not workspace-scoped, matching the backend API contract (the route has no workspace_slug segment).
- deleteLottery resolves with the deleted Lottery, matching the backend response.