Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/APIFunctions/SCEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,32 @@ export async function updateSCEvent(id, token, eventUpdates) {
return status;
}

export async function deleteSCEvent(id, token) {
const status = new ApiResponse();
try {
const res = await fetch(`${SCEVENTS_API_URL}/events/${id}`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${token}`,
},
});
let body;
try {
body = await res.json();
} catch {
body = {};
}
status.responseData = body;
if (!res.ok) {
status.error = true;
}
} catch (err) {
status.error = true;
status.responseData = { error: err?.message || 'Failed to connect to SCEvents API' };
}
return status;
}

export async function getEventRegistrations(eventId, token, { limit = 50, offset = 0 } = {}) {
const status = new ApiResponse();
try {
Expand Down
28 changes: 27 additions & 1 deletion src/Pages/Events/EditEventPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { useMemo, useState, useEffect, useRef } from 'react';
import { Link, useHistory, useParams } from 'react-router-dom';
import { useSCE } from '../../Components/context/SceContext';
import { getEventByID, updateSCEvent } from '../../APIFunctions/SCEvents';
import { deleteSCEvent, getEventByID, updateSCEvent } from '../../APIFunctions/SCEvents';
import { getAllUsers, validateEventAdmins } from '../../APIFunctions/User';
import { membershipState } from '../../Enums';
import { toApiRegistrationForm, useEventQuestions } from './useEventQuestions';
Expand Down Expand Up @@ -57,6 +57,8 @@ export default function EditEventPage() {
const [submitError, setSubmitError] = useState('');
const [submitting, setSubmitting] = useState(false);
const debounceRef = useRef(null);
const [deleteSubmitting, setDeleteSubmitting] = useState(false);
const [deleteError, setDeleteError] = useState('');

const userId = useMemo(() => (user?._id != null ? String(user._id) : ''), [user]);
const eventAdminIds = useMemo(
Expand Down Expand Up @@ -236,6 +238,23 @@ export default function EditEventPage() {
history.push('/events');
}

async function handleConfirmDelete() {
setDeleteError('');
setDeleteSubmitting(true);
const token = window.localStorage.getItem('jwtToken');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i might be wrong but i believe there is a hook called useSCE which lets you extract the token without needing to directly access local storage. see here. if the token you're accessing is different from the clark jwt token then forget i said any of this

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is true lol + we should probably update all refs in SCEvents in Clark

can you open a new PR to do this @maernest04 ? we can just merge this for now + do the "refactor" in a new focused PR

const result = await deleteSCEvent(id, token);
setDeleteSubmitting(false);
if (result.error) {
setDeleteError(getApiErrorMessage(result, {
fallback: 'SCEvents returned an error.',
networkHint: 'Is the SCEvents API running (e.g. Docker on port 8002)?',
}));
return false;
}
history.push('/events');
return true;
}

if (isLoading) {
return <div className="p-10 text-center text-lg">Loading event details...</div>;
}
Expand Down Expand Up @@ -281,6 +300,13 @@ export default function EditEventPage() {
submitError,
unlimitedAttendeesValue: UNLIMITED_ATTENDEES,
maxAttendeesMode: 'edit',
eventDelete: {
show: true,
deleteSubmitting,
deleteError,
clearDeleteError: () => setDeleteError(''),
onConfirmDelete: handleConfirmDelete,
},
}}
form={{
eventName,
Expand Down
70 changes: 70 additions & 0 deletions src/Pages/Events/EventEditorForm.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useRef } from 'react';
import { Link } from 'react-router-dom';
import CreateEventFormQuestionBlock from './CreateEventFormQuestionBlock';

Expand All @@ -18,8 +19,11 @@ export default function EventEditorForm({
submitError,
unlimitedAttendeesValue,
maxAttendeesMode,
eventDelete,
} = meta;

const deleteDialogRef = useRef(null);

const {
eventName,
setEventName,
Expand Down Expand Up @@ -425,6 +429,72 @@ export default function EventEditorForm({
Cancel
</Link>
</div>

{eventDelete?.show && (
<div className="mt-10 border-t border-gray-200 pt-8 dark:border-gray-700">
<h2 className="mb-3 text-xl font-semibold text-gray-900 dark:text-white">Danger zone</h2>
{status === 'published' ? (
<p className="text-sm text-gray-600 dark:text-gray-400">
Set status to <span className="font-medium">Closed</span> before you can delete this event.
</p>
) : (
<>
<p className="mb-3 text-sm text-gray-600 dark:text-gray-400">
Permanently delete this event and its registrations. This cannot be undone.
</p>
{eventDelete.deleteError && (
<div className="mb-3 rounded-lg bg-red-50 p-3 text-sm text-red-700 dark:bg-red-900/30 dark:text-red-200">
{eventDelete.deleteError}
</div>
)}
<button
type="button"
className="btn btn-outline btn-error"
disabled={eventDelete.deleteSubmitting}
onClick={() => {
eventDelete.clearDeleteError?.();
deleteDialogRef.current?.showModal();
}}
>
Delete event
</button>
<dialog
ref={deleteDialogRef}
id="delete-event-modal"
className="modal modal-bottom sm:modal-middle"
>
<div className="modal-box">
<h3 className="mb-2 text-lg font-bold text-gray-900 dark:text-white">Delete this event?</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
This removes the event and all related registration and waitlist data from SCEvents.
</p>
<div className="modal-action">
<form method="dialog" className="flex flex-wrap gap-2">
<button type="submit" className="btn btn-ghost">
Cancel
</button>
<button
type="button"
className="btn btn-error"
disabled={eventDelete.deleteSubmitting}
onClick={async (e) => {
e.preventDefault();
const ok = await eventDelete.onConfirmDelete();
if (ok) {
deleteDialogRef.current?.close();
}
}}
>
{eventDelete.deleteSubmitting ? 'Deleting…' : 'Yes, delete permanently'}
</button>
</form>
</div>
</div>
</dialog>
</>
)}
</div>
)}
</div>
);
}
Loading