mirror of
https://github.com/myfatemi04/wheelshare-frontend.git
synced 2025-04-09 22:00:16 -04:00
rename some hooks, make events deletable by creator
This commit is contained in:
parent
5d0a25991d
commit
c25d650276
|
@ -1,21 +1,11 @@
|
|||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { getEvent } from '../api';
|
||||
import { IEvent } from '../types';
|
||||
import UILink from '../UI/UILink';
|
||||
import UISecondaryBox from '../UI/UISecondaryBox';
|
||||
import UISecondaryHeader from '../UI/UISecondaryHeader';
|
||||
import useImmutable from '../useImmutable';
|
||||
import EventContent from './EventContent';
|
||||
import EventContext from './EventContext';
|
||||
import EventDetails from './EventDetails';
|
||||
import EventInterestForm from './EventInterestForm';
|
||||
import EventPlaceholder from './EventPlaceholder';
|
||||
|
||||
type NotNull<T> = T extends null ? never : T;
|
||||
|
||||
function GroupName({ group }: { group: NotNull<IEvent['group']> }) {
|
||||
return <UILink href={`/groups/${group.id}`}>{group.name}</UILink>;
|
||||
}
|
||||
|
||||
export default function Event({
|
||||
id,
|
||||
initial,
|
||||
|
@ -44,8 +34,6 @@ export default function Event({
|
|||
return <h1>Event Not Found</h1>;
|
||||
}
|
||||
|
||||
const { name, group } = event;
|
||||
|
||||
return (
|
||||
<EventContext.Provider
|
||||
value={{
|
||||
|
@ -55,16 +43,7 @@ export default function Event({
|
|||
tentativeInvites,
|
||||
}}
|
||||
>
|
||||
<UISecondaryBox style={{ width: '35rem', maxWidth: '100vw' }}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<UISecondaryHeader>{name}</UISecondaryHeader>
|
||||
<span>Created by {event.creator.name}</span>
|
||||
<br />
|
||||
{group && <GroupName group={group} />}
|
||||
</div>
|
||||
<EventDetails />
|
||||
<EventInterestForm />
|
||||
</UISecondaryBox>
|
||||
<EventContent />
|
||||
</EventContext.Provider>
|
||||
);
|
||||
}
|
||||
|
|
83
src/components/Event/EventAdminControls.tsx
Normal file
83
src/components/Event/EventAdminControls.tsx
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { useCallback, useState } from 'react';
|
||||
import { deleteEvent } from '../api';
|
||||
import UIPressable from '../UI/UIPressable';
|
||||
import { useCurrentEventId } from './EventHooks';
|
||||
|
||||
export enum AsyncCallbackStatus {
|
||||
NONE = 0,
|
||||
PENDING = 1,
|
||||
RESOLVED = 2,
|
||||
REJECTED = 3,
|
||||
}
|
||||
|
||||
export function useAsyncCallback<T, A extends unknown[]>(
|
||||
callback: (...args: A) => Promise<T>
|
||||
) {
|
||||
const [status, setStatus] = useState(AsyncCallbackStatus.NONE);
|
||||
|
||||
const cb = useCallback(
|
||||
(...args: any) => {
|
||||
setStatus(AsyncCallbackStatus.PENDING);
|
||||
|
||||
callback(...args)
|
||||
.then(() => setStatus(AsyncCallbackStatus.RESOLVED))
|
||||
.catch(() => setStatus(AsyncCallbackStatus.REJECTED));
|
||||
},
|
||||
[callback]
|
||||
);
|
||||
|
||||
const reset = useCallback(() => setStatus(AsyncCallbackStatus.NONE), []);
|
||||
|
||||
return [cb as typeof callback, status, reset] as const;
|
||||
}
|
||||
|
||||
export default function EventAdminControls() {
|
||||
const id = useCurrentEventId();
|
||||
// const desc = useCurrentEventDescription();
|
||||
|
||||
// const descriptionTextareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const [onPressDelete, deletionStatus] = useAsyncCallback(
|
||||
useCallback(() => deleteEvent(id), [id])
|
||||
);
|
||||
|
||||
// const [onSaveDescription, saveDescriptionStatus] = useAsyncCallback(
|
||||
// useCallback(() => {
|
||||
// if (!descriptionTextareaRef.current) {
|
||||
// return Promise.reject('Textarea not ready');
|
||||
// }
|
||||
// setEditDescriptionOpen(false);
|
||||
// return setEventDescription(id, descriptionTextareaRef.current.value);
|
||||
// }, [id])
|
||||
// );
|
||||
|
||||
// const [editDescriptionOpen, setEditDescriptionOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex' }}>
|
||||
{deletionStatus === AsyncCallbackStatus.NONE ? (
|
||||
<UIPressable onClick={onPressDelete}>Delete</UIPressable>
|
||||
) : deletionStatus === AsyncCallbackStatus.PENDING ? (
|
||||
<span>Deleting...</span>
|
||||
) : deletionStatus === AsyncCallbackStatus.RESOLVED ? (
|
||||
<span>Deleted</span>
|
||||
) : (
|
||||
<span>Delete failed</span>
|
||||
)}
|
||||
|
||||
{/* {!editDescriptionOpen ? (
|
||||
<UIPressable onClick={() => setEditDescriptionOpen(true)}>
|
||||
Edit description
|
||||
</UIPressable>
|
||||
) : (
|
||||
<>
|
||||
<textarea defaultValue={desc} ref={descriptionTextareaRef} />
|
||||
<UIPressable onClick={onSaveDescription}>Save</UIPressable>
|
||||
<UIPressable onClick={() => setEditDescriptionOpen(false)}>
|
||||
Cancel
|
||||
</UIPressable>
|
||||
</>
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -5,7 +5,7 @@ import { useMe } from '../hooks';
|
|||
import UIButton from '../UI/UIButton';
|
||||
import UILink from '../UI/UILink';
|
||||
import EventContext from './EventContext';
|
||||
import { useMyCarpool } from './EventHooks';
|
||||
import { useCurrentEventCarpool } from './EventHooks';
|
||||
|
||||
type CreationStatus = null | 'pending' | 'completed' | 'errored';
|
||||
|
||||
|
@ -16,7 +16,7 @@ export default function EventCarpoolCreateButton() {
|
|||
const [createdCarpoolId, setCreatedCarpoolId] = useState<null | number>(null);
|
||||
|
||||
const me = useMe() || { id: 0, name: '' };
|
||||
const myCarpool = useMyCarpool();
|
||||
const myCarpool = useCurrentEventCarpool();
|
||||
|
||||
const createCarpoolCallback = useCallback(async () => {
|
||||
setCreationStatus('pending');
|
||||
|
|
|
@ -11,7 +11,7 @@ import { useMe } from '../hooks';
|
|||
import { IEvent, IEventSignupComplete } from '../types';
|
||||
import useOptimalPath from '../useOptimalPath';
|
||||
import EventContext from './EventContext';
|
||||
import { useMySignup } from './EventHooks';
|
||||
import { useCurrentEventSignup } from './EventHooks';
|
||||
|
||||
function useMemberLocations(members: IEvent['carpools'][0]['members']) {
|
||||
const { event } = useContext(EventContext);
|
||||
|
@ -61,7 +61,7 @@ function CarpoolRow({
|
|||
|
||||
const { event } = useContext(EventContext);
|
||||
|
||||
const mySignup = useMySignup();
|
||||
const mySignup = useCurrentEventSignup();
|
||||
|
||||
const memberLocations = useMemberLocations(carpool.members);
|
||||
|
||||
|
@ -145,13 +145,15 @@ export default function Carpools() {
|
|||
Click <EmojiPeopleIcon style={{ fontSize: '0.875rem' }} /> to request to
|
||||
join a carpool.
|
||||
</span>
|
||||
{event.carpools.length>0 ? event.carpools.map((carpool) => (
|
||||
<CarpoolRow
|
||||
carpool={carpool}
|
||||
key={carpool.id}
|
||||
inCarpoolAlready={alreadyInCarpool}
|
||||
/>
|
||||
)) : "No Carpools"}
|
||||
{event.carpools.length > 0
|
||||
? event.carpools.map((carpool) => (
|
||||
<CarpoolRow
|
||||
carpool={carpool}
|
||||
key={carpool.id}
|
||||
inCarpoolAlready={alreadyInCarpool}
|
||||
/>
|
||||
))
|
||||
: 'No Carpools'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
39
src/components/Event/EventContent.tsx
Normal file
39
src/components/Event/EventContent.tsx
Normal file
|
@ -0,0 +1,39 @@
|
|||
import UILink from '../UI/UILink';
|
||||
import UISecondaryBox from '../UI/UISecondaryBox';
|
||||
import UISecondaryHeader from '../UI/UISecondaryHeader';
|
||||
import EventAdminControls from './EventAdminControls';
|
||||
import EventDetails from './EventDetails';
|
||||
import {
|
||||
useCurrentEventCreator,
|
||||
useCurrentEventGroup,
|
||||
useCurrentEventName,
|
||||
useIsCurrentEventCreator,
|
||||
} from './EventHooks';
|
||||
import EventInterestForm from './EventInterestForm';
|
||||
|
||||
export default function EventContent() {
|
||||
const group = useCurrentEventGroup();
|
||||
const name = useCurrentEventName();
|
||||
const creator = useCurrentEventCreator();
|
||||
const isEventCreator = useIsCurrentEventCreator();
|
||||
|
||||
return (
|
||||
<UISecondaryBox style={{ width: '35rem', maxWidth: '100vw' }}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<UISecondaryHeader>{name}</UISecondaryHeader>
|
||||
<span>
|
||||
Created by {isEventCreator ? 'you' : creator.name}
|
||||
{group && (
|
||||
<>
|
||||
{' '}
|
||||
in <UILink href={`/groups/${group.id}`}>{group.name}</UILink>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<EventDetails />
|
||||
<EventInterestForm />
|
||||
{isEventCreator && <EventAdminControls />}
|
||||
</UISecondaryBox>
|
||||
);
|
||||
}
|
|
@ -2,7 +2,41 @@ import { useContext, useDebugValue, useMemo } from 'react';
|
|||
import { useMe } from '../hooks';
|
||||
import EventContext from './EventContext';
|
||||
|
||||
export function useSignups() {
|
||||
export function useCurrentEventId() {
|
||||
const { event } = useContext(EventContext);
|
||||
return useMemo(() => event.id, [event.id]);
|
||||
}
|
||||
|
||||
export function useCurrentEventName() {
|
||||
const { event } = useContext(EventContext);
|
||||
return useMemo(() => event.name, [event.name]);
|
||||
}
|
||||
|
||||
export function useCurrentEventDescription() {
|
||||
const { event } = useContext(EventContext);
|
||||
return useMemo(() => event.description, [event.description]);
|
||||
}
|
||||
|
||||
export function useCurrentEventCreator() {
|
||||
const { event } = useContext(EventContext);
|
||||
return useMemo(() => event.creator, [event.creator]);
|
||||
}
|
||||
|
||||
export function useCurrentEventGroup() {
|
||||
const { event } = useContext(EventContext);
|
||||
return useMemo(() => event.group, [event.group]);
|
||||
}
|
||||
|
||||
export function useIsCurrentEventCreator() {
|
||||
const creator = useCurrentEventCreator();
|
||||
const me = useMe();
|
||||
if (!me) {
|
||||
return false;
|
||||
}
|
||||
return me.id === creator.id;
|
||||
}
|
||||
|
||||
export function useCurrentEventSignups() {
|
||||
const signups = useContext(EventContext).event.signups;
|
||||
|
||||
useDebugValue(signups);
|
||||
|
@ -10,8 +44,8 @@ export function useSignups() {
|
|||
return signups;
|
||||
}
|
||||
|
||||
export function useMySignup() {
|
||||
const signups = useSignups();
|
||||
export function useCurrentEventSignup() {
|
||||
const signups = useCurrentEventSignups();
|
||||
const me = useMe() || { id: 0, name: '' };
|
||||
|
||||
const signup = useMemo(() => signups[me.id] ?? null, [signups, me.id]);
|
||||
|
@ -21,7 +55,7 @@ export function useMySignup() {
|
|||
return signup;
|
||||
}
|
||||
|
||||
export function useMyCarpool() {
|
||||
export function useCurrentEventCarpool() {
|
||||
const me = useMe() || { id: 0, name: '' };
|
||||
const { event } = useContext(EventContext);
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ import { IEventSignup } from '../types';
|
|||
import EventCarpoolCreateButton from './EventCarpoolCreateButton';
|
||||
import EventContext from './EventContext';
|
||||
import pickLatLong from './pickLatLong';
|
||||
import { useMySignup } from './EventHooks';
|
||||
import { useCurrentEventSignup } from './EventHooks';
|
||||
|
||||
function EventSignup({ signup }: { signup: IEventSignup }) {
|
||||
const { user } = signup;
|
||||
const me = useMe();
|
||||
const { tentativeInvites, event } = useContext(EventContext);
|
||||
const mySignup = useMySignup();
|
||||
const mySignup = useCurrentEventSignup();
|
||||
const myLocation = pickLatLong(mySignup);
|
||||
const theirLocation = pickLatLong(signup);
|
||||
const eventLocation = pickLatLong(event)!;
|
||||
|
|
|
@ -113,6 +113,17 @@ export async function createEvent({
|
|||
};
|
||||
}
|
||||
|
||||
export async function setEventDescription(
|
||||
eventId: number,
|
||||
description: string
|
||||
) {
|
||||
return await post(`/events/${eventId}/update`, { description });
|
||||
}
|
||||
|
||||
export async function deleteEvent(eventId: number) {
|
||||
return await delete$(`/events/${eventId}`);
|
||||
}
|
||||
|
||||
export async function getEvents(): Promise<IEvent[]> {
|
||||
return await get('/events');
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ export type IEvent = {
|
|||
name: string;
|
||||
}[];
|
||||
}[];
|
||||
description: string;
|
||||
signups: Record<string, IEventSignup>;
|
||||
startTime: string; // Datestring
|
||||
duration: number;
|
||||
|
|
Loading…
Reference in New Issue
Block a user