Report a Join on an event without an attendees list as not recorded, and trim redundant comments
This commit is contained in:
@@ -54,6 +54,7 @@ export function EventDetailScreen() {
|
||||
const registration = eventId ? getEventRegistration(eventId) : undefined;
|
||||
const registered = registration?.registered ?? false;
|
||||
const [confirmingLeave, setConfirmingLeave] = useState(false);
|
||||
const [joining, setJoining] = useState(false);
|
||||
const [leaving, setLeaving] = useState(false);
|
||||
|
||||
const handleToggleMeetingPoint = (id: string, _title: string, willJoin: boolean) => {
|
||||
@@ -71,11 +72,14 @@ export function EventDetailScreen() {
|
||||
};
|
||||
|
||||
const handleJoinEvent = () => {
|
||||
if (!eventId) return;
|
||||
void Promise.resolve(joinEvent(eventId)).catch((err: unknown) => {
|
||||
console.error('[EventDetail] event sign-up failed:', err);
|
||||
showToast("L'inscription à l'événement n'a pas pu être enregistrée", 'error');
|
||||
});
|
||||
if (!eventId || joining) return;
|
||||
setJoining(true);
|
||||
Promise.resolve(joinEvent(eventId))
|
||||
.catch((err: unknown) => {
|
||||
console.error('[EventDetail] event sign-up failed:', err);
|
||||
showToast("L'inscription à l'événement n'a pas pu être enregistrée", 'error');
|
||||
})
|
||||
.finally(() => setJoining(false));
|
||||
};
|
||||
|
||||
const withdrawFromEvent = () => {
|
||||
@@ -92,8 +96,6 @@ export function EventDetailScreen() {
|
||||
});
|
||||
};
|
||||
|
||||
// Withdrawing from an event also leaves its meeting points: ask first when
|
||||
// there are any, otherwise withdraw at once.
|
||||
const handleLeaveEvent = () => {
|
||||
if (registration && registration.meetingPointIds.length > 0) setConfirmingLeave(true);
|
||||
else withdrawFromEvent();
|
||||
@@ -217,7 +219,7 @@ export function EventDetailScreen() {
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button variant="primary" onClick={handleJoinEvent} style={{ padding: '12px 0' }}>
|
||||
<Button variant="primary" onClick={handleJoinEvent} disabled={joining} style={{ padding: '12px 0' }}>
|
||||
S'inscrire à l'événement
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -205,6 +205,18 @@ interface ContactKeys {
|
||||
}
|
||||
|
||||
/** The memo key of one contact's member URN at one event. */
|
||||
/** The event a joined target is anchored to: its own event for a meeting point, itself for an event. */
|
||||
function anchorEventIdOf(bindings: RefineBackend['bindings'], targetId: string, record: unknown): string | undefined {
|
||||
if (bindings.meetingPoint.isInstance?.(record) ?? false) {
|
||||
try {
|
||||
return bindings.meetingPoint.toDomain(record).eventId || undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return bindings.event.isInstance?.(record) ?? true ? targetId : undefined;
|
||||
}
|
||||
|
||||
function memberUrnKey(contactId: string, eventId: string, secret: string): string {
|
||||
return `${contactId}\n${eventId}\n${secret}`;
|
||||
}
|
||||
@@ -464,17 +476,8 @@ function useRefineData(backend: RefineBackend): FestipodDataContextValue {
|
||||
for (const mpId of joinedForeignMeetingPointIds) {
|
||||
const record = foreignMeetingPointsRead.records.get(mpId);
|
||||
if (record === undefined) continue;
|
||||
// A joined target that reads as an event is a direct sign-up: its own anchor.
|
||||
if (!(bindings.meetingPoint.isInstance?.(record) ?? false)) {
|
||||
if (bindings.event.isInstance?.(record) ?? true) ids.add(mpId);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const eventId = bindings.meetingPoint.toDomain(record).eventId;
|
||||
if (eventId) ids.add(eventId);
|
||||
} catch {
|
||||
// Unreadable by the binding — the pick below drops the record too.
|
||||
}
|
||||
const eventId = anchorEventIdOf(bindings, mpId, record);
|
||||
if (eventId) ids.add(eventId);
|
||||
}
|
||||
return [...ids].filter(id => !ownEventIds.has(id));
|
||||
}, [joinedForeignMeetingPointIds, foreignMeetingPointsRead.records, bindings, ownEventIds]);
|
||||
@@ -852,17 +855,8 @@ function useRefineData(backend: RefineBackend): FestipodDataContextValue {
|
||||
for (const uri of contactMpUris) {
|
||||
const record = contactMpsRead.records.get(uri);
|
||||
if (record === undefined) continue;
|
||||
// A listed target that reads as an event is a direct sign-up: its own anchor.
|
||||
if (!(bindings.meetingPoint.isInstance?.(record) ?? false)) {
|
||||
if (bindings.event.isInstance?.(record) ?? true) ids.set(uri, uri);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const eventId = bindings.meetingPoint.toDomain(record).eventId;
|
||||
if (eventId) ids.set(uri, eventId);
|
||||
} catch {
|
||||
// Not a readable meeting point — the binding drops it, as everywhere.
|
||||
}
|
||||
const eventId = anchorEventIdOf(bindings, uri, record);
|
||||
if (eventId) ids.set(uri, eventId);
|
||||
}
|
||||
return ids;
|
||||
}, [contactMpUris, contactMpsRead.records, bindings]);
|
||||
@@ -1248,8 +1242,6 @@ function useRefineData(backend: RefineBackend): FestipodDataContextValue {
|
||||
afterMembershipAct(event.id, 'join');
|
||||
}, [logPrefix, allEvents, session, myTargetIds, ensureParticipationSecret, afterMembershipAct]);
|
||||
|
||||
// One Leave per held target, in parallel; each accepted one is followed, the
|
||||
// refused ones are named — the status keeps following the data.
|
||||
const leaveEvent = useCallback(async (eventId: string) => {
|
||||
if (!allEvents.some(e => e.id === eventId) || !session) {
|
||||
throw new Error(`leaveEvent refused: ${eventId} is not in the read set (or there is no session).`);
|
||||
|
||||
Reference in New Issue
Block a user