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',
|
||||
passIssued: 'Pass issued',
|
||||
issueFailed: 'Could not issue the pass',
|
||||
issuedPasses: 'Issued check-in passes',
|
||||
},
|
||||
studio: {
|
||||
unsaved: 'Unsaved changes',
|
||||
|
|
|
|||
|
|
@ -6394,6 +6394,7 @@ walletUi: {
|
|||
notOrganiser: 'Solo el organizador puede emitir pases',
|
||||
passIssued: 'Pase emitido',
|
||||
issueFailed: 'No se pudo emitir el pase',
|
||||
issuedPasses: 'Pases de acceso emitidos',
|
||||
},
|
||||
studio: {
|
||||
unsaved: 'Cambios sin guardar',
|
||||
|
|
|
|||
|
|
@ -277,6 +277,9 @@ export default function RiderCardPage() {
|
|||
: memberships.some((m) => user?.pubkey && m.crew.admins.includes(user.pubkey)) ? 'admin'
|
||||
: undefined;
|
||||
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(
|
||||
() => (allSpots ?? []).filter((s) => s.pubkey === user?.pubkey),
|
||||
[allSpots, user?.pubkey],
|
||||
|
|
@ -1127,6 +1130,36 @@ export default function RiderCardPage() {
|
|||
{t('cardUi.event.issuePassBtn')}
|
||||
</Button>
|
||||
<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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue