diff --git a/firestore.rules b/firestore.rules index 5bee1fb..901f4d5 100644 --- a/firestore.rules +++ b/firestore.rules @@ -6,21 +6,21 @@ service cloud.firestore { match /hosts/{hostId} { allow read: if request.auth != null; allow write: if request.auth != null && - (('admin' in request.auth.token.roles) || ('host' in request.auth.token.roles)); + request.auth.token.roles.hasAny(['admin', 'host']); } // Club settings - admin and host roles can manage match /club/{clubId} { allow read: if request.auth != null; allow write: if request.auth != null && - (('admin' in request.auth.token.roles) || ('host' in request.auth.token.roles)); + request.auth.token.roles.hasAny(['admin', 'host']); } // Default rule for all other documents match /{document=**} { allow read: if request.auth != null; allow write: if request.auth != null && - (('admin' in request.auth.token.roles) || ('host' in request.auth.token.roles)); + request.auth.token.roles.hasAny(['admin', 'host']); } } } \ No newline at end of file diff --git a/webapp/src/features/event/EventRoot.tsx b/webapp/src/features/event/EventRoot.tsx index 450710f..50f0746 100644 --- a/webapp/src/features/event/EventRoot.tsx +++ b/webapp/src/features/event/EventRoot.tsx @@ -28,7 +28,7 @@ const EventRoot = () => { const [lineupPosterPreviewUrl, setLineupPosterPreviewUrl] = useState(null); const { eventId } = useParams(); - const { saveEvent, getReconcicledEvent} = useEventStore(); + const { saveEvent, getReconciledEvent} = useEventStore(); // Listen for changes to the event and reset our actual event when they change. useEffect(() => { @@ -78,7 +78,7 @@ const EventRoot = () => { const proposeEventChange = (event: Event) => { let newEvent = { ...event }; - newEvent = getReconcicledEvent(newEvent); + newEvent = getReconciledEvent(newEvent); setHasChanges(true); setEventScratchpad(newEvent); }; @@ -145,7 +145,7 @@ const EventRoot = () => { // Ensure the event (including lineup poster fields) is fully reconciled // before saving so that image-only changes are also persisted. - eventToSave = getReconcicledEvent(eventToSave); + eventToSave = getReconciledEvent(eventToSave); await saveEvent(eventToSave, event); diff --git a/webapp/src/features/event/basic/EventBasicDetailsForm.tsx b/webapp/src/features/event/basic/EventBasicDetailsForm.tsx index 0f93ffb..0edbea5 100644 --- a/webapp/src/features/event/basic/EventBasicDetailsForm.tsx +++ b/webapp/src/features/event/basic/EventBasicDetailsForm.tsx @@ -16,6 +16,8 @@ type Props = { const EventBasicDetailsForm = ({ event: eventScratchpad, onEventChange: proposeEventChange, onLineupPosterFileChange }: Props) => { + // Note: The Host argument is intentionally unused here; it remains in the + // signature to stay compatible with the HostSearchSelect callback API. const handleHostSelect = (_: Host | null, hostRef: DocumentReference | null) => { proposeEventChange({ ...eventScratchpad, diff --git a/webapp/src/features/host/CreateHostModal.tsx b/webapp/src/features/host/CreateHostModal.tsx index eeb422f..ea3580c 100644 --- a/webapp/src/features/host/CreateHostModal.tsx +++ b/webapp/src/features/host/CreateHostModal.tsx @@ -2,7 +2,7 @@ import { Modal, Button, Stack } from "react-bootstrap"; import { useState } from "react"; import { Host } from "../../util/types"; import HostForm from "./HostForm"; -import { createHost } from "../../store/host"; +import { createHost, updateHost } from "../../store/host"; import { toast } from "react-hot-toast"; import { ref, uploadBytes, getDownloadURL } from "firebase/storage"; import { storage } from "../../util/firebase"; @@ -42,6 +42,9 @@ const CreateHostModal = ({ show, onHide, onHostCreated }: Props) => { host.host_poster_path = storagePath; host.host_poster_url = downloadUrl; + + // Update the host document in Firestore with the poster information + await updateHost(hostRef.id, host); } const createdHost = { ...host, id: hostRef.id }; diff --git a/webapp/src/hooks/useEventStore/useEventStore.tsx b/webapp/src/hooks/useEventStore/useEventStore.tsx index 54be4de..82d8c6b 100644 --- a/webapp/src/hooks/useEventStore/useEventStore.tsx +++ b/webapp/src/hooks/useEventStore/useEventStore.tsx @@ -9,7 +9,7 @@ import { useCallback } from "react"; export const useEventStore = () => { const { djCache, hostCache } = useEventDjCache(); - const getReconcicledEvent = useCallback((event: Event) => reconcileEventData(event, djCache, hostCache), [djCache, hostCache]); + const getReconciledEvent = useCallback((event: Event) => reconcileEventData(event, djCache, hostCache), [djCache, hostCache]); const getNextEvent = useCallback(async () => { const q = query(collection(db, "events"), where("end_datetime", ">", Timestamp.now()), orderBy("start_datetime", "asc")); @@ -19,10 +19,10 @@ export const useEventStore = () => { const events: Event[] = querySnapshot.docs .map((doc) => docToEvent(doc)) .filter((event): event is Exclude => event !== null) - .map(event => getReconcicledEvent(event)); + .map(event => getReconciledEvent(event)); return events[0] ?? null; - }, [getReconcicledEvent]); + }, [getReconciledEvent]); const getCurrentEvent = useCallback(async () => { const q = query( @@ -36,10 +36,10 @@ export const useEventStore = () => { const events: Event[] = querySnapshot.docs .map((doc) => docToEvent(doc)) .filter((event): event is Exclude => event !== null) - .map(event => getReconcicledEvent(event)); + .map(event => getReconciledEvent(event)); return events[0] ?? null; - }, [getReconcicledEvent]); + }, [getReconciledEvent]); const createEvent = useCallback(async (event: Event) => { // lastUpdated is derived from Firestore snapshot metadata and should not @@ -51,7 +51,7 @@ export const useEventStore = () => { }, []); const saveEvent = useCallback(async (event: Event, previousEvent?: Event) => { - event = getReconcicledEvent(event); + event = getReconciledEvent(event); const eventId = event.id; @@ -87,12 +87,12 @@ export const useEventStore = () => { }); } }); - }, [getReconcicledEvent]); + }, [getReconciledEvent]); return { createEvent, saveEvent, - getReconcicledEvent, + getReconciledEvent, getCurrentEvent, getNextEvent }; diff --git a/webapp/src/store/clubSettings.ts b/webapp/src/store/clubSettings.ts index 17e95dd..02f4411 100644 --- a/webapp/src/store/clubSettings.ts +++ b/webapp/src/store/clubSettings.ts @@ -14,6 +14,7 @@ export const getClubSettings = async (): Promise => { console.warn(`Club settings document at path "${CLUB_SETTINGS_PATH}" does not exist. Returning default empty settings.`); // Return default empty settings if document doesn't exist return {}; + } } export const updateClubSettings = async (settings: Club) => { diff --git a/webapp/src/store/converters.ts b/webapp/src/store/converters.ts index b5ffabe..4d5c184 100644 --- a/webapp/src/store/converters.ts +++ b/webapp/src/store/converters.ts @@ -96,8 +96,8 @@ function extractDateOrAny(date: Date | Timestamp | TimestampShell | string | und /** * Converts a firebase doc to a host * - * @param doc - * @returns + * @param doc - The Firestore document containing host data + * @returns A Host object with the document data and ID */ export const docToHost = (doc: DocumentData): Host => { const data = doc.data();