diff --git a/src/components/App.tsx b/src/components/App.tsx index a9f8780..6de316d 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,6 +1,7 @@ import { CSSProperties, lazy, Suspense } from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import NotificationsProvider from '../state/Notifications/NotificationsProvider'; +import Header from './Header/Header'; import { useMe } from './hooks'; import WheelShare from './WheelShare'; import WheelShareLoggedOut from './WheelShareLoggedOut'; @@ -31,11 +32,8 @@ export default function App() { {user ? ( +
- diff --git a/src/components/Carpool/CarpoolPage.tsx b/src/components/Carpool/CarpoolPage.tsx index a7c381c..71cdf65 100644 --- a/src/components/Carpool/CarpoolPage.tsx +++ b/src/components/Carpool/CarpoolPage.tsx @@ -1,14 +1,8 @@ import { useParams } from 'react-router-dom'; -import Header from '../Header/Header'; import Carpool from './Carpool'; export default function CarpoolPage() { const id = +useParams<{ id: string }>().id; - return ( - <> -
- - - ); + return ; } diff --git a/src/components/Event/Event.tsx b/src/components/Event/Event.tsx index f84c824..13ebae1 100644 --- a/src/components/Event/Event.tsx +++ b/src/components/Event/Event.tsx @@ -1,19 +1,14 @@ import { useCallback, useEffect, useState } from 'react'; -import { green, lightgrey } from '../../lib/colors'; -import getPlaceDetails from '../../lib/getPlaceDetails'; -import { addOrUpdateEventSignup, getEvent, removeEventSignup } from '../api'; -import { useMe } from '../hooks'; +import { getEvent } from '../api'; import { IEvent } from '../types'; -import UIButton from '../UI/UIButton'; import UILink from '../UI/UILink'; -import UIPlacesAutocomplete from '../UI/UIPlacesAutocomplete'; import UISecondaryBox from '../UI/UISecondaryBox'; import UISecondaryHeader from '../UI/UISecondaryHeader'; import useImmutable from '../useImmutable'; -import EventCarpools from './EventCarpools'; import EventContext from './EventContext'; import EventDetails from './EventDetails'; -import EventSignups from './EventSignups'; +import EventInterestForm from './EventInterestForm'; +import EventPlaceholder from './EventPlaceholder'; function GroupName({ group }: { group: IEvent['group'] }) { return {group.name}; @@ -26,89 +21,28 @@ export default function Event({ id: number; initial?: IEvent; }) { - const [event, setEvent] = useImmutable({ - id, - name: '', - group: { - id: 0, - name: '', - }, - signups: {}, - carpools: [], - startTime: '', - endTime: '', - daysOfWeek: 0, - placeId: '', - formattedAddress: '', - latitude: 0, - longitude: 0, - duration: 0, - ...(initial || {}), - }); - - const [found, setFound] = useState(false); - - const me = useMe() || { id: 0, name: '' }; - + const [event, setEvent] = useImmutable(initial ?? null); + const [loading, setLoading] = useState(true); const [tentativeInvites] = useImmutable>({}); const refresh = useCallback(() => { - getEvent(id).then((e) => { - if (e) { - setFound(true); - setEvent(e); - } else { - setFound(false); - } - }); + setLoading(true); + getEvent(id) + .then((e) => e && setEvent(e)) + .finally(() => setLoading(false)); }, [id, setEvent]); useEffect(refresh, [refresh]); - const updateSignup = useCallback( - async (placeId: string | null) => { - await addOrUpdateEventSignup(id, placeId); - - if (placeId) { - const details = await getPlaceDetails(placeId); - - event.signups[me.id] = { - user: { id: me.id, name: me.name }, - placeId, - ...details, - }; - } else { - event.signups[me.id] = { - user: { id: me.id, name: me.name }, - placeId: null, - latitude: null, - longitude: null, - formattedAddress: null, - }; - } - }, - [event.signups, id, me.id, me.name] - ); - - const removeSignup = useCallback(async () => { - await removeEventSignup(id); - - if (event.signups[me.id]) { - delete event.signups[me.id]; - } - }, [id, me.id, event.signups]); - - const interested = !!event.signups[me.id]; - - if (!found) { - return ( - <> -

Event Not Found

- - ); + if (loading) { + return ; } - const { name, group, formattedAddress, startTime, endTime } = event; + if (!event) { + return

Event Not Found

; + } + + const { name, group } = event; return ( {name} {group && } - - removeSignup() : () => updateSignup(null)} - style={{ - backgroundColor: interested ? green : lightgrey, - color: interested ? 'white' : 'black', - transition: 'color 0.2s, background-color 0.2s', - }} - > - {interested ? 'Interested' : 'Not interested'} - - {interested && ( - <> - { - updateSignup(placeId); - }} - style={ - event.signups[me.id]?.placeId != null - ? { border: '2px solid ' + green } - : {} - } - placeId={event.signups[me.id]?.placeId} - /> -
- - {event.signups !== null && } - - )} + +
); diff --git a/src/components/Event/EventDetails.tsx b/src/components/Event/EventDetails.tsx index e9363e2..2952308 100644 --- a/src/components/Event/EventDetails.tsx +++ b/src/components/Event/EventDetails.tsx @@ -1,16 +1,13 @@ import formatStartAndEndTime from '../../lib/dates'; import EventIcon from '@material-ui/icons/Event'; import LocationOnIcon from '@material-ui/icons/LocationOn'; +import { useContext } from 'react'; +import EventContext from './EventContext'; + +export default function EventDetails() { + const { startTime, endTime, formattedAddress } = + useContext(EventContext).event; -export default function Details({ - startTime, - endTime, - formattedAddress, -}: { - startTime: string; - endTime: string | null; - formattedAddress: string; -}) { return (
{ + await addOrUpdateEventSignup(event.id, placeId); + + if (placeId) { + const details = await getPlaceDetails(placeId); + + event.signups[me.id] = { + user: { id: me.id, name: me.name }, + placeId, + ...details, + }; + } else { + event.signups[me.id] = { + user: { id: me.id, name: me.name }, + placeId: null, + latitude: null, + longitude: null, + formattedAddress: null, + }; + } + }, + [event.id, event.signups, me.id, me.name] + ); + + const removeSignup = useCallback(async () => { + await removeEventSignup(event.id); + + if (event.signups[me.id]) { + delete event.signups[me.id]; + } + }, [event.id, event.signups, me.id]); + + const interested = !!event.signups[me.id]; + + return ( + <> + removeSignup() : () => updateSignup(null)} + style={{ + backgroundColor: interested ? green : lightgrey, + color: interested ? 'white' : 'black', + transition: 'color 0.2s, background-color 0.2s', + }} + > + {interested ? 'Interested' : 'Not interested'} + + {interested && ( + <> + { + updateSignup(placeId); + }} + style={ + event.signups[me.id]?.placeId != null + ? { border: '2px solid ' + green } + : {} + } + placeId={event.signups[me.id]?.placeId} + /> +
+ + {event.signups !== null && } + + )} + + ); +} diff --git a/src/components/Event/EventPage.tsx b/src/components/Event/EventPage.tsx index c18acee..e503e7c 100644 --- a/src/components/Event/EventPage.tsx +++ b/src/components/Event/EventPage.tsx @@ -1,14 +1,8 @@ import { useParams } from 'react-router-dom'; -import Header from '../Header/Header'; import Event from './Event'; export default function EventPage() { const id = +useParams<{ id: string }>().id; - return ( - <> -
- - - ); + return ; } diff --git a/src/components/Event/EventPlaceholder.tsx b/src/components/Event/EventPlaceholder.tsx new file mode 100644 index 0000000..f108f7d --- /dev/null +++ b/src/components/Event/EventPlaceholder.tsx @@ -0,0 +1,7 @@ +import UISecondaryBox from '../UI/UISecondaryBox'; + +export default function EventPlaceholder() { + return ( + Loading... + ); +} diff --git a/src/components/EventCreator/EventCreator.tsx b/src/components/EventCreator/EventCreator.tsx index 8da8878..7133d71 100644 --- a/src/components/EventCreator/EventCreator.tsx +++ b/src/components/EventCreator/EventCreator.tsx @@ -84,7 +84,7 @@ export default function EventCreator({ group }: { group: IGroup }) { ]); return ( - +

Create Event

diff --git a/src/components/EventCreator/EventCreatorLink.tsx b/src/components/EventCreator/EventCreatorLink.tsx index ce0b10c..2310b14 100644 --- a/src/components/EventCreator/EventCreatorLink.tsx +++ b/src/components/EventCreator/EventCreatorLink.tsx @@ -1,5 +1,6 @@ import { useContext } from 'react'; import { GroupContext } from '../Group/Group'; +import UIPressable from '../UI/UIPressable'; import useToggle from '../useToggle'; import EventCreator from './EventCreator'; @@ -8,22 +9,14 @@ export default function EventCreatorLink() { const { group } = useContext(GroupContext); return ( -
-
- Create Event -
+ <> + Create Event {open && ( <>
)} -
+ ); } diff --git a/src/components/Group/Group.tsx b/src/components/Group/Group.tsx index 77a47f5..009d5cd 100644 --- a/src/components/Group/Group.tsx +++ b/src/components/Group/Group.tsx @@ -19,48 +19,50 @@ const DEFAULT_GROUP = (): IGroup => ({ export const GroupContext = createContext({ group: DEFAULT_GROUP() }); export default function Group({ id }: { id: number }) { - const [group, setGroup] = useImmutable(DEFAULT_GROUP()); - const [found, setFound] = useState(false); + const [group, setGroup] = useImmutable(null); + const [loading, setLoading] = useState(false); useEffect(() => { + setLoading(true); getGroup(id) .then(setGroup) - .catch(() => setFound(false)); + .finally(() => setLoading(false)); }, [id, setGroup]); - return found ? ( + if (loading) { + return

Loading...

; + } + + return group ? ( +

{group.name}

-

{group.name}

Home
-


-
- - {group.events.length > 0 ? ( - - ) : ( - - There are no events yet. Click 'create event' above to add one! - - )}
+
+ + {group.events.length > 0 ? ( + + ) : ( + + There are no events yet. Click 'create event' above to add one! + + )}
) : ( - <> -

Group not found

- +

Group not found

); } diff --git a/src/components/Group/GroupInviteCodeGenerator.tsx b/src/components/Group/GroupInviteCodeGenerator.tsx index caecffe..31a8a40 100644 --- a/src/components/Group/GroupInviteCodeGenerator.tsx +++ b/src/components/Group/GroupInviteCodeGenerator.tsx @@ -1,4 +1,4 @@ -import { useCallback, useContext } from 'react'; +import { useCallback, useContext, useState } from 'react'; import { lightgrey } from '../../lib/colors'; import { generateCode, resetCode } from '../api'; import UIButton from '../UI/UIButton'; @@ -7,6 +7,8 @@ import { GroupContext } from './Group'; export default function GroupInviteCodeGenerator() { const { group } = useContext(GroupContext); + const [shown, setShown] = useState(false); + const generateJoinCode = useCallback(() => { generateCode(group.id).then((code) => { group.joinCode = code; @@ -22,11 +24,15 @@ export default function GroupInviteCodeGenerator() { if (group.joinCode) { return ( <> - + Join this group with the code{' '} - - {group.joinCode} - + setShown((shown) => !shown)} + > + {shown ? group.joinCode : 'XXXXXX'} + {' '} + (click to show/hide)

- +

Members

- - {group.users.map(({ name }) => ( {name} ))} +
+ +
)} diff --git a/src/components/Group/GroupSettings.tsx b/src/components/Group/GroupSettings.tsx index fb1d9ff..b7a5f0b 100644 --- a/src/components/Group/GroupSettings.tsx +++ b/src/components/Group/GroupSettings.tsx @@ -20,7 +20,7 @@ export default function GroupSettings({ group }: { group: IGroup }) { }, [group.id]); return ( - +

Settings

{deletionSuccessful !== true && ( Delete Group diff --git a/src/components/Group/GroupSettingsLink.tsx b/src/components/Group/GroupSettingsLink.tsx index a3ad286..ccdc50e 100644 --- a/src/components/Group/GroupSettingsLink.tsx +++ b/src/components/Group/GroupSettingsLink.tsx @@ -1,4 +1,5 @@ import { useContext } from 'react'; +import UIPressable from '../UI/UIPressable'; import useToggle from '../useToggle'; import { GroupContext } from './Group'; import GroupSettings from './GroupSettings'; @@ -8,22 +9,14 @@ export default function GroupSettingsLink() { const { group } = useContext(GroupContext); return ( -
-
- Settings -
+ <> + Settings {open && ( <>
)} -
+ ); } diff --git a/src/components/WheelShare.tsx b/src/components/WheelShare.tsx index c3b4970..d1670d8 100644 --- a/src/components/WheelShare.tsx +++ b/src/components/WheelShare.tsx @@ -1,13 +1,10 @@ import ActiveCarpools from './ActiveCarpools/ActiveCarpools'; import ActiveEvents from './ActiveEvents/Events'; import Groups from './Groups/Groups'; -import Header from './Header/Header'; export default function WheelShare() { return ( <> -
-