@pitvox/partner-react 0.7.24 → 0.7.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -175,6 +175,112 @@ import {
|
|
|
175
175
|
|
|
176
176
|
**`getCompetitionPodium(standings, topN?)`** — Extract the top N drivers from a standings payload.
|
|
177
177
|
|
|
178
|
+
## Promotions
|
|
179
|
+
|
|
180
|
+
Partner-run community promotions. The first (and currently only) type is `giveaway` — a one-click prize draw: drivers sign in with Steam, hit Enter, and the partner picks winners manually and publishes them. The `type` field is designed to grow (e.g. discount codes, free trials) without new hooks or components.
|
|
181
|
+
|
|
182
|
+
Promotions are managed by the partner on pitvox.com; the SDK is the read + entry surface for partner sites. Public data (config, entrants, winners) comes from the CDN; entry/withdraw go through the same backend-proxy pattern as competition registration.
|
|
183
|
+
|
|
184
|
+
### Drop-in composite (recommended)
|
|
185
|
+
|
|
186
|
+
```jsx
|
|
187
|
+
import { PromotionExplorer } from '@pitvox/partner-react'
|
|
188
|
+
import '@pitvox/partner-react/styles.css'
|
|
189
|
+
|
|
190
|
+
function GiveawaysPage() {
|
|
191
|
+
return <PromotionExplorer title="Giveaways" />
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`PromotionExplorer` is the whole experience in one component: a card grid that drills into a detail view (poster, markdown description, one-click entry with a public-display disclosure, live entrants grid, and the winners panel once announced). Selection lives in the `?promotion=` URL search param via the History API — links are shareable and the browser back button works — so it needs no router.
|
|
196
|
+
|
|
197
|
+
| Prop | Type | Default | Description |
|
|
198
|
+
|------|------|---------|-------------|
|
|
199
|
+
| `title` | `string` | `'Promotions'` | Page heading (pass `''` to hide it) |
|
|
200
|
+
| `driverData` | `object` | — | Extra fields sent to the enter callback (e.g. `displayName`, `avatarUrl`); usually unnecessary since the backend derives identity from the Steam token |
|
|
201
|
+
| `className` | `string` | — | Additional class on root container |
|
|
202
|
+
|
|
203
|
+
### Hooks
|
|
204
|
+
|
|
205
|
+
```jsx
|
|
206
|
+
import {
|
|
207
|
+
usePromotions,
|
|
208
|
+
usePromotionConfig,
|
|
209
|
+
usePromotionEntryList,
|
|
210
|
+
usePromotionEntryStatus,
|
|
211
|
+
} from '@pitvox/partner-react'
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**`usePromotions()`** — All active promotions for this partner (or all promotions in global mode). The CDN index carries active promotions only, so an empty result means nothing is running — handy for conditionally showing a nav link.
|
|
215
|
+
|
|
216
|
+
**`usePromotionConfig(promotionId, options?)`** — Single promotion config (title, prize, markdown description, entry window, winners).
|
|
217
|
+
|
|
218
|
+
**`usePromotionEntryList(promotionId, options?)`** — Entrants (Steam ID, display name, avatar, entered-at). `null` until the first entry.
|
|
219
|
+
|
|
220
|
+
**`usePromotionEntryStatus(promotionId)`** — Whether the current user (via `getSteamId`) has entered, plus the entry list. Lightweight CDN check.
|
|
221
|
+
|
|
222
|
+
All detail hooks accept `options.partnerSlug` to override the provider's slug (useful in global mode).
|
|
223
|
+
|
|
224
|
+
### Styled components
|
|
225
|
+
|
|
226
|
+
```jsx
|
|
227
|
+
import {
|
|
228
|
+
PromotionExplorer, PromotionCards, PromotionCard,
|
|
229
|
+
PromotionDetail, EnterButton,
|
|
230
|
+
} from '@pitvox/partner-react'
|
|
231
|
+
import '@pitvox/partner-react/styles.css'
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
- **`<PromotionExplorer>`** — The drop-in composite above.
|
|
235
|
+
- **`<PromotionCards>`** — Card grid with posters, status/type badges, prize, entry window, and entry count. Adapts the layout to the card count (a lone promotion renders as one wide centred card). Props: `promotions`, `isLoading`, `onSelect`, `className`.
|
|
236
|
+
- **`<PromotionCard>`** — Individual card, for when you want to control the grid yourself. Props: `promo`, `onSelect`.
|
|
237
|
+
- **`<PromotionDetail>`** — Full detail view: poster, markdown body, entrants grid, the entry action with public-display disclosure, and the winners panel. Self-contained — fetches via hooks. Props: `promotionId`, `driverData`, `onBack` (omit to hide the back link), `className`.
|
|
238
|
+
- **`<EnterButton>`** — Enter/withdraw toggle. Render-prop or default button, with the same basic/power-mode behaviour as `RegisterButton` (see below). Props: `promotionId`, `driverData`, `className`, `children` (render prop).
|
|
239
|
+
|
|
240
|
+
### Entry modes
|
|
241
|
+
|
|
242
|
+
Like registration, entry has two modes determined by whether you provide callbacks to the provider.
|
|
243
|
+
|
|
244
|
+
**Basic mode (default)** — no configuration; `EnterButton` and the detail view render a link to pitvox.com where the user enters with Steam.
|
|
245
|
+
|
|
246
|
+
**Power mode** — for partners with a backend proxying to pitvox-api (keeping the partner API key server-side), provide the callbacks. The Steam ID is derived server-side from the user's token, not from client input:
|
|
247
|
+
|
|
248
|
+
```jsx
|
|
249
|
+
<PitVoxPartnerProvider
|
|
250
|
+
partnerSlug="your-slug"
|
|
251
|
+
getSteamId={() => user?.steamId ?? null}
|
|
252
|
+
onEnterPromotion={async (promotionId, driverData) => {
|
|
253
|
+
// Call your backend (e.g. AppSync mutation) → pitvox-api
|
|
254
|
+
await client.graphql({ query: ENTER_PROMOTION, variables: { promotionId, ...driverData } })
|
|
255
|
+
}}
|
|
256
|
+
onWithdrawPromotionEntry={async (promotionId, steamId) => {
|
|
257
|
+
await client.graphql({ query: WITHDRAW_PROMOTION_ENTRY, variables: { promotionId } })
|
|
258
|
+
}}
|
|
259
|
+
>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Entry/withdraw hooks for fully custom UIs:
|
|
263
|
+
|
|
264
|
+
```jsx
|
|
265
|
+
import { useEnterPromotion, useWithdrawPromotionEntry, usePromotionMode, usePromotionUrl } from '@pitvox/partner-react'
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**`useEnterPromotion(promotionId)`** — Mutation delegating to `onEnterPromotion`, with optimistic entry-list updates.
|
|
269
|
+
|
|
270
|
+
**`useWithdrawPromotionEntry(promotionId)`** — Mutation delegating to `onWithdrawPromotionEntry`. Withdrawals are only accepted while entries are open.
|
|
271
|
+
|
|
272
|
+
**`usePromotionMode()`** — Returns `{ isPowerMode, isBasicMode }`.
|
|
273
|
+
|
|
274
|
+
**`usePromotionUrl(promotionId)`** — pitvox.com promotion URL for basic mode.
|
|
275
|
+
|
|
276
|
+
### Status helper
|
|
277
|
+
|
|
278
|
+
```jsx
|
|
279
|
+
import { getPromotionStatus, PROMOTION_STATUS_LABELS } from '@pitvox/partner-react'
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**`getPromotionStatus(promotion, now?)`** — Returns `'upcoming'` | `'open'` | `'closed'` | `'winners'`, derived from the clock against `opensAt`/`closesAt` (the CDN never stores a computed open/closed flag, so files can't go stale between syncs). `PROMOTION_STATUS_LABELS` maps each to a display string.
|
|
283
|
+
|
|
178
284
|
## Driver Dashboard
|
|
179
285
|
|
|
180
286
|
### Drop-in composite
|
package/dist/styles.css
CHANGED
package/package.json
CHANGED