Add public Shard page + player Game Accounts UI (phase 4)
Frontend for the uo-link integration, matching the existing site styling. - api/client.js: api.shard.* (status/feed/economy/idoc/char), the shardStreamUrl SSE endpoint, and api.player.shard.* (link/accounts/roster/ vendors). - lib/useShardFeed.js: EventSource hook over /public/shard/stream with a rolling buffer and a connected flag (browser never touches the sidecar WS). - routes/public/Shard.jsx: connection banner, stat tiles (online / gold supply / link), a gold-supply sparkline, "recent vendor sales" and "IDOC houses" lists, and a live event ticker — built from the shared panel/grid/format vocabulary. Registered at /site/shard under the maintenance gate and linked from the site header. - routes/player/PlayerAccount.jsx: a "Game accounts" section — enter a [link code to link an account, then expand it to see characters and player vendors on demand (503 shows a retry banner). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011qPmpmVH1xGCiZoz9m9vW3
This commit is contained in:
@@ -79,6 +79,26 @@ export const api = {
|
||||
pagePreview: (id, token) => req(`/public/pages/${id}/preview/${token}`),
|
||||
contact: (payload) => req('/public/contact', { method: 'POST', body: payload }),
|
||||
|
||||
// ----- shard live data (uo-link) -----
|
||||
// Token-free, same-origin reads backed by the ingested feed + a cached live
|
||||
// character round-trip. shardStreamUrl is the SSE endpoint for useShardFeed.
|
||||
shard: {
|
||||
status: () => req('/public/shard/status'),
|
||||
feed: (opts = {}) => {
|
||||
const qs = new URLSearchParams()
|
||||
if (opts.kind) qs.set('kind', opts.kind)
|
||||
if (opts.limit) qs.set('limit', opts.limit)
|
||||
const s = qs.toString()
|
||||
return req(`/public/shard/feed${s ? `?${s}` : ''}`)
|
||||
},
|
||||
economy: (limit) => req(`/public/shard/economy${limit ? `?limit=${limit}` : ''}`),
|
||||
idoc: () => req('/public/shard/idoc'),
|
||||
char: (serial) => req(`/public/shard/char/${encodeURIComponent(serial)}`),
|
||||
},
|
||||
// Full path (incl. /api/v1) for the browser EventSource — the req() wrapper is
|
||||
// fetch-only, so SSE subscribers build the URL from here.
|
||||
shardStreamUrl: `${BASE}/public/shard/stream`,
|
||||
|
||||
// ----- admin -----
|
||||
admin: {
|
||||
dashboard: () => req('/admin/dashboard'),
|
||||
@@ -225,6 +245,14 @@ export const api = {
|
||||
totpDisable: (code) => req('/player/account/totp/disable', { method: 'POST', body: { code } }),
|
||||
linkedIdentities: () => req('/player/account/identities'),
|
||||
unlinkIdentity: (provider) => req(`/player/account/identities/${provider}`, { method: 'DELETE' }),
|
||||
|
||||
// ----- game account linking (uo-link) -----
|
||||
shard: {
|
||||
link: (code) => req('/player/shard/link', { method: 'POST', body: { code } }),
|
||||
accounts: () => req('/player/shard/accounts'),
|
||||
roster: (account) => req(`/player/shard/roster/${encodeURIComponent(account)}`),
|
||||
vendors: (account) => req(`/player/shard/vendors/${encodeURIComponent(account)}`),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user