Merge branch 'staging' into main

This commit is contained in:
Michael Fatemi 2021-08-22 19:18:31 -04:00
commit bfed3cdfb4
8 changed files with 110 additions and 4 deletions

View File

@ -20,6 +20,7 @@ const CarpoolPage = lazy(() => import('./Carpool/CarpoolPage'));
const EventPage = lazy(() => import('./Event/EventPage')); const EventPage = lazy(() => import('./Event/EventPage'));
const GroupPage = lazy(() => import('./Group/GroupPage')); const GroupPage = lazy(() => import('./Group/GroupPage'));
const GroupSharedLinkResolver = lazy(() => import('./GroupSharedLinkResolver')); const GroupSharedLinkResolver = lazy(() => import('./GroupSharedLinkResolver'));
const ProfileForSelf = lazy(() => import('./ProfileForSelf/ProfileForSelf'));
const style: CSSProperties = { const style: CSSProperties = {
display: 'flex', display: 'flex',
@ -65,6 +66,7 @@ export default function App() {
<Switch> <Switch>
<Route path="/" exact component={WheelShare} /> <Route path="/" exact component={WheelShare} />
<Route path="/error-report" component={ErrorReport} /> <Route path="/error-report" component={ErrorReport} />
<Route path="/me" exact component={ProfileForSelf} />
<Route <Route
path="/join/:code" path="/join/:code"
component={GroupSharedLinkResolver} component={GroupSharedLinkResolver}

View File

@ -3,6 +3,7 @@ import { createContext } from 'react';
export type User = { export type User = {
name: string; name: string;
id: number; id: number;
bio: string;
email?: string; email?: string;
}; };

View File

@ -10,9 +10,11 @@ import EventCarpools from './EventCarpools';
import { useMutableEvent } from './EventHooks'; import { useMutableEvent } from './EventHooks';
import EventSignups from './EventSignups'; import EventSignups from './EventSignups';
const defaultMe = { id: 0, name: '', bio: '' };
export default function EventInterestForm() { export default function EventInterestForm() {
const event = useMutableEvent(); const event = useMutableEvent();
const me = useMe() || { id: 0, name: '' }; const me = useMe() || defaultMe;
const placeIdRef = useRef<string | null>(null); const placeIdRef = useRef<string | null>(null);
const canDriveRef = useRef(false); const canDriveRef = useRef(false);
const [note, setNote] = useState(''); const [note, setNote] = useState('');
@ -48,7 +50,7 @@ export default function EventInterestForm() {
const details = await getPlaceDetails(placeId); const details = await getPlaceDetails(placeId);
event.signups[me.id] = { event.signups[me.id] = {
user: { id: me.id, name: me.name }, user: me,
placeId, placeId,
...details, ...details,
canDrive, canDrive,
@ -56,7 +58,7 @@ export default function EventInterestForm() {
}; };
} else { } else {
event.signups[me.id] = { event.signups[me.id] = {
user: { id: me.id, name: me.name }, user: me,
placeId: null, placeId: null,
latitude: null, latitude: null,
longitude: null, longitude: null,
@ -66,7 +68,7 @@ export default function EventInterestForm() {
}; };
} }
}, },
[event.id, event.signups, me.id, me.name] [event.id, event.signups, me]
); );
const removeSignup = useCallback(async () => { const removeSignup = useCallback(async () => {

View File

@ -59,6 +59,8 @@ function EventSignup({ signup }: { signup: IEventSignup }) {
> >
<span> <span>
<b>{user.name}</b> <b>{user.name}</b>
{user.bio && `, ${user.bio}`}
<br />
{extraDistance && ` +${extraDistance.toFixed(1)} miles`}{' '} {extraDistance && ` +${extraDistance.toFixed(1)} miles`}{' '}
{signup.canDrive && ' (can drive)'} {signup.canDrive && ' (can drive)'}
{signup.note && ( {signup.note && (

View File

@ -30,6 +30,7 @@ export default function Header() {
{me.name} {me.name}
{me.email && ` (${me.email})`} {me.email && ` (${me.email})`}
<UIPressable onClick={logout}>Log out</UIPressable> <UIPressable onClick={logout}>Log out</UIPressable>
<a href="/me">Profile</a>
<br /> <br />
{notifications.length > 0 ? ( {notifications.length > 0 ? (
<Notifications <Notifications

View File

@ -0,0 +1,93 @@
import { useCallback, useEffect, useState } from 'react';
import { updateBio } from '../api';
import {
AsyncCallbackStatus,
useAsyncCallback,
} from '../Event/EventAdminControls';
import { useAuth } from '../hooks';
import UIButton from '../UI/UIButton';
import UITextInput from '../UI/UITextInput';
export default function ProfileForSelf() {
const [editingBio, setEditingBio] = useState(false);
const [temporaryBio, setTemporaryBio] = useState('');
const { user: me, refresh: refreshLocalUser } = useAuth();
const [onClickedSaveBio, onClickedSaveBioStatus] = useAsyncCallback(
useCallback(
async (temporaryBio: string) => {
await updateBio(temporaryBio);
refreshLocalUser();
setEditingBio(false);
},
[refreshLocalUser]
)
);
useEffect(() => {
if (me?.bio) {
setTemporaryBio(me?.bio);
}
}, [me?.bio]);
if (!me) {
return null;
}
return (
<div style={{ minWidth: '16rem', width: '20rem' }}>
<h1>{me.name}</h1>
<p>{me.bio}</p>
{editingBio ? (
<>
{onClickedSaveBioStatus === AsyncCallbackStatus.REJECTED && (
<p>Error saving bio.</p>
)}
{onClickedSaveBioStatus !== AsyncCallbackStatus.PENDING ? (
<>
<UITextInput
onChangeText={setTemporaryBio}
value={temporaryBio}
style={{
border: '2px solid grey',
width: '100%',
}}
/>
<UIButton
onClick={() => onClickedSaveBio(temporaryBio)}
style={{
backgroundColor: '#f8f8f8',
width: '100%',
}}
>
Save
</UIButton>
</>
) : (
<UIButton
onClick={() => {}}
style={{
backgroundColor: '#f8f8f8',
width: '100%',
}}
>
Saving...
</UIButton>
)}
</>
) : (
<>
<UIButton
onClick={() => setEditingBio(true)}
style={{
backgroundColor: '#f8f8f8',
width: '100%',
}}
>
Edit Bio
</UIButton>
</>
)}
</div>
);
}

View File

@ -312,3 +312,7 @@ export async function sendErrorReport(error: string) {
throw new Error(response.statusText); throw new Error(response.statusText);
} }
} }
export async function updateBio(bio: string) {
return await post('/users/@me/bio', { bio });
}

View File

@ -101,6 +101,7 @@ export type IEventSignupBase = {
user: { user: {
id: number; id: number;
name: string; name: string;
bio: string;
}; };
canDrive: boolean; canDrive: boolean;
note: string; note: string;