feat(card): organiser's issued check-in passes list
The event organiser can see who they've issued check-in passes to (holder + revoked state) and revoke them — same affordance the park panel has. (Skipped listing a holder's passes on their public profile: a pass is between a venue and a holder, so publishing it would leak where someone has access.)
This commit is contained in:
parent
a4ef8218e3
commit
38ae1273ff
3 changed files with 35 additions and 0 deletions
|
|
@ -6394,6 +6394,7 @@ walletUi: {
|
||||||
notOrganiser: 'Only the organiser can issue passes',
|
notOrganiser: 'Only the organiser can issue passes',
|
||||||
passIssued: 'Pass issued',
|
passIssued: 'Pass issued',
|
||||||
issueFailed: 'Could not issue the pass',
|
issueFailed: 'Could not issue the pass',
|
||||||
|
issuedPasses: 'Issued check-in passes',
|
||||||
},
|
},
|
||||||
studio: {
|
studio: {
|
||||||
unsaved: 'Unsaved changes',
|
unsaved: 'Unsaved changes',
|
||||||
|
|
|
||||||
|
|
@ -6394,6 +6394,7 @@ walletUi: {
|
||||||
notOrganiser: 'Solo el organizador puede emitir pases',
|
notOrganiser: 'Solo el organizador puede emitir pases',
|
||||||
passIssued: 'Pase emitido',
|
passIssued: 'Pase emitido',
|
||||||
issueFailed: 'No se pudo emitir el pase',
|
issueFailed: 'No se pudo emitir el pase',
|
||||||
|
issuedPasses: 'Pases de acceso emitidos',
|
||||||
},
|
},
|
||||||
studio: {
|
studio: {
|
||||||
unsaved: 'Cambios sin guardar',
|
unsaved: 'Cambios sin guardar',
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,9 @@ export default function RiderCardPage() {
|
||||||
: memberships.some((m) => user?.pubkey && m.crew.admins.includes(user.pubkey)) ? 'admin'
|
: memberships.some((m) => user?.pubkey && m.crew.admins.includes(user.pubkey)) ? 'admin'
|
||||||
: undefined;
|
: undefined;
|
||||||
const organisesEvent = myEvents.some((e) => e.pubkey === user?.pubkey);
|
const organisesEvent = myEvents.some((e) => e.pubkey === user?.pubkey);
|
||||||
|
const eventPasses = activeEvent
|
||||||
|
? issuedPasses.filter((p) => p.coord === `${CALENDAR_EVENT_KIND}:${activeEvent.pubkey}:${activeEvent.identifier}`)
|
||||||
|
: [];
|
||||||
const myVenues = useMemo(
|
const myVenues = useMemo(
|
||||||
() => (allSpots ?? []).filter((s) => s.pubkey === user?.pubkey),
|
() => (allSpots ?? []).filter((s) => s.pubkey === user?.pubkey),
|
||||||
[allSpots, user?.pubkey],
|
[allSpots, user?.pubkey],
|
||||||
|
|
@ -1127,6 +1130,36 @@ export default function RiderCardPage() {
|
||||||
{t('cardUi.event.issuePassBtn')}
|
{t('cardUi.event.issuePassBtn')}
|
||||||
</Button>
|
</Button>
|
||||||
<p className="text-[10px] text-gray-600">{t('cardUi.event.issuePassHint')}</p>
|
<p className="text-[10px] text-gray-600">{t('cardUi.event.issuePassHint')}</p>
|
||||||
|
|
||||||
|
{eventPasses.length > 0 && (
|
||||||
|
<div className="space-y-2 border-t border-white/8 pt-3">
|
||||||
|
<p className="text-[10px] font-black uppercase tracking-widest text-gray-600">{t('cardUi.event.issuedPasses')}</p>
|
||||||
|
{eventPasses.slice(0, 6).map((p) => (
|
||||||
|
<div key={p.id} className="flex items-center justify-between gap-2 text-[11px]">
|
||||||
|
<span className="truncate text-gray-400">
|
||||||
|
{p.holder ? `${nip19.npubEncode(p.holder).slice(0, 12)}…` : '—'}
|
||||||
|
</span>
|
||||||
|
{p.status === 'revoked' ? (
|
||||||
|
<span className="shrink-0 font-bold uppercase text-red-400">{t('cardUi.parkRevoked')}</span>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="h-7 shrink-0 border-white/10 text-[10px]"
|
||||||
|
disabled={revokingPass}
|
||||||
|
onClick={() => {
|
||||||
|
void revokePass(p)
|
||||||
|
.then(() => toast({ title: t('cardUi.parkRevoked') }))
|
||||||
|
.catch(() => toast({ title: t('cardUi.parkRevokeFailed'), variant: 'destructive' }));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('cardUi.parkRevoke')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue