diff --git a/src/components/NewUI/App.tsx b/src/components/NewUI/App.tsx index 136a741..cf857c1 100644 --- a/src/components/NewUI/App.tsx +++ b/src/components/NewUI/App.tsx @@ -1,3 +1,4 @@ +import EventCreator from './EventCreator'; import Group from './Group'; import UIPrimaryTitle from './UIPrimaryTitle'; @@ -15,6 +16,7 @@ export default function App() { }} > <UIPrimaryTitle>WheelShare</UIPrimaryTitle> + <EventCreator /> <Group events={[ { diff --git a/src/components/NewUI/Event.tsx b/src/components/NewUI/Event.tsx index 47c6550..e98a50f 100644 --- a/src/components/NewUI/Event.tsx +++ b/src/components/NewUI/Event.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from 'react'; +import UIButton from './UIButton'; import UIPlacesAutocomplete from './UIPlacesAutocomplete'; +import UISecondaryBox from './UISecondaryBox'; import UISecondaryHeader from './UISecondaryHeader'; import UITimeInput from './UITimeInput'; @@ -25,16 +27,7 @@ export default function Event({ title, group, location, time }: IEvent) { }, [rideTherePickupPlaceID, rideBackDropoffPlaceID]); return ( - <div - style={{ - display: 'flex', - flexDirection: 'column', - backgroundColor: '#f9f9f9', - borderRadius: '0.5rem', - padding: '1rem', - marginBottom: '1em', - }} - > + <UISecondaryBox> <UISecondaryHeader>{title}</UISecondaryHeader> <span style={{ @@ -76,44 +69,32 @@ export default function Event({ title, group, location, time }: IEvent) { marginTop: '1rem', }} > - <div + <UIButton style={{ backgroundColor: needRideThere ? green : lightgrey, color: needRideThere ? 'white' : 'black', transition: 'color 0.2s, background-color 0.2s', - padding: '1rem', - borderRadius: '0.5em', - textTransform: 'uppercase', - fontWeight: 500, marginRight: '0.5em', - cursor: 'pointer', - userSelect: 'none', }} onClick={() => { setNeedRideThere((needRideThere) => !needRideThere); }} > I need a ride there - </div> - <div + </UIButton> + <UIButton style={{ backgroundColor: needRideBack ? green : lightgrey, color: needRideBack ? 'white' : 'black', transition: 'color 0.2s, background-color 0.2s', - padding: '1rem', - borderRadius: '0.5em', - textTransform: 'uppercase', - fontWeight: 500, marginLeft: '0.5em', - cursor: 'pointer', - userSelect: 'none', }} onClick={() => { setNeedRideBack((needRideBack) => !needRideBack); }} > I need a ride back - </div> + </UIButton> </div> {needRideThere && ( <> @@ -161,25 +142,18 @@ export default function Event({ title, group, location, time }: IEvent) { )} {(needRideThere || needRideBack) && (rideTherePickupPlaceID || rideBackDropoffPlaceID) && ( - <div + <UIButton style={{ backgroundColor: confirmed ? green : lightgrey, color: confirmed ? 'white' : 'black', - padding: '1rem', - borderRadius: '0.5em', - textTransform: 'uppercase', - fontWeight: 500, - marginTop: '0.5em', - cursor: 'pointer', - userSelect: 'none', }} onClick={() => { setConfirmed((confirmed) => !confirmed); }} > {confirmed ? 'Confirmed' : 'Confirm'} - </div> + </UIButton> )} - </div> + </UISecondaryBox> ); } diff --git a/src/components/NewUI/EventCreator.tsx b/src/components/NewUI/EventCreator.tsx new file mode 100644 index 0000000..96c2cb0 --- /dev/null +++ b/src/components/NewUI/EventCreator.tsx @@ -0,0 +1,53 @@ +import { useCallback, useState } from 'react'; +import UIButton from './UIButton'; +import UIDatetimeInput from './UIDatetimeInput'; +import UIPlacesAutocomplete from './UIPlacesAutocomplete'; +import UISecondaryBox from './UISecondaryBox'; +import UITextInput from './UITextInput'; + +export default function EventCreator() { + const [name, setName] = useState(''); + const [startTime, setStartTime] = useState<Date | null>(null); + const [endTime, setEndTime] = useState<Date | null>(null); + const [placeId, setPlaceId] = useState<string | null>(null); + const [groupId, setGroupId] = useState(''); + + const createEvent = useCallback(() => { + fetch('http://localhost:5000/api/events', { + method: 'post', + body: JSON.stringify({ + name, + startTime, + endTime, + groupId, + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + }, [name, startTime, endTime, groupId]); + + return ( + <UISecondaryBox style={{ width: '100%', boxSizing: 'border-box' }}> + Name + <UITextInput value={name} onChangeText={setName} /> + <br /> + Group + <UITextInput value={groupId} onChangeText={setGroupId} /> + <br /> + Start time + <UIDatetimeInput onChangedDate={setStartTime} /> + <br /> + End time + <UIDatetimeInput onChangedDate={setEndTime} /> + <br /> + Location + <UIPlacesAutocomplete + onSelected={(address, placeId) => { + setPlaceId(placeId); + }} + /> + <UIButton onClick={createEvent}>Create Event</UIButton> + </UISecondaryBox> + ); +} diff --git a/src/components/NewUI/Group.tsx b/src/components/NewUI/Group.tsx index 073ac3c..a508b19 100644 --- a/src/components/NewUI/Group.tsx +++ b/src/components/NewUI/Group.tsx @@ -7,9 +7,9 @@ export type IGroup = { export default function Group({ events, name }: IGroup) { return ( - <div style={{ textAlign: 'center' }}> + <div style={{ textAlign: 'center', width: '100%' }}> <h1>{name}</h1> - <div style={{ display: 'flex', flexDirection: 'column' }}> + <div style={{ display: 'flex', flexDirection: 'column', width: '100%' }}> {events.map((event) => ( <Event {...event} key={event.title} /> ))} diff --git a/src/components/NewUI/UIButton.tsx b/src/components/NewUI/UIButton.tsx new file mode 100644 index 0000000..483813f --- /dev/null +++ b/src/components/NewUI/UIButton.tsx @@ -0,0 +1,33 @@ +import { useMemo, CSSProperties, MouseEventHandler, ReactNode } from 'react'; + +const baseStyle: CSSProperties = { + padding: '1rem', + borderRadius: '0.5em', + textTransform: 'uppercase', + fontWeight: 500, + marginTop: '0.5em', + cursor: 'pointer', + userSelect: 'none', +}; + +export default function UIButton({ + style, + children, + onClick, +}: { + style?: CSSProperties; + children: ReactNode; + onClick: MouseEventHandler<HTMLDivElement>; +}) { + const computedStyle = useMemo(() => { + if (!style) { + return baseStyle; + } + return { ...baseStyle, ...style }; + }, [style]); + return ( + <div style={computedStyle} onClick={onClick}> + {children} + </div> + ); +} diff --git a/src/components/NewUI/UIDatetimeInput.tsx b/src/components/NewUI/UIDatetimeInput.tsx new file mode 100644 index 0000000..156a6d3 --- /dev/null +++ b/src/components/NewUI/UIDatetimeInput.tsx @@ -0,0 +1,22 @@ +const baseStyle = { + marginTop: '0.5em', + padding: '0.5em', + fontFamily: 'Inter', + fontSize: '1.25rem', + borderRadius: '0.5em', + border: '0px', +}; + +export default function UIDatetimeInput({ + onChangedDate, +}: { + onChangedDate: (date: Date | null) => void; +}) { + return ( + <input + style={baseStyle} + type="datetime-local" + onChange={(e) => onChangedDate(e.target.valueAsDate)} + /> + ); +} diff --git a/src/components/NewUI/UISecondaryBox.tsx b/src/components/NewUI/UISecondaryBox.tsx new file mode 100644 index 0000000..d38c94b --- /dev/null +++ b/src/components/NewUI/UISecondaryBox.tsx @@ -0,0 +1,26 @@ +import { CSSProperties, ReactNode, useMemo } from 'react'; + +const baseStyle: CSSProperties = { + display: 'flex', + flexDirection: 'column', + backgroundColor: '#f9f9f9', + borderRadius: '0.5rem', + padding: '1rem', + marginBottom: '1em', +}; + +export default function UISecondaryBox({ + children, + style, +}: { + children: ReactNode; + style?: CSSProperties; +}) { + const computedStyle = useMemo(() => { + if (!style) { + return baseStyle; + } + return { ...baseStyle, ...style }; + }, [style]); + return <div style={computedStyle}>{children}</div>; +} diff --git a/src/components/NewUI/UITextInput.tsx b/src/components/NewUI/UITextInput.tsx new file mode 100644 index 0000000..50339f6 --- /dev/null +++ b/src/components/NewUI/UITextInput.tsx @@ -0,0 +1,24 @@ +const baseStyle = { + marginTop: '0.5em', + padding: '0.5em', + fontFamily: 'Inter', + fontSize: '1.25rem', + borderRadius: '0.5em', + border: '0px', +}; + +export default function UITextInput({ + value, + onChangeText, +}: { + value: string; + onChangeText: (text: string) => void; +}) { + return ( + <input + style={baseStyle} + value={value} + onChange={(e) => onChangeText(e.target.value)} + /> + ); +}