add component for accepting/denying requests

This commit is contained in:
Michael Fatemi 2021-07-24 18:25:54 -04:00
parent 6f2d53270d
commit 54ed65a037
6 changed files with 170 additions and 37 deletions

View File

@ -1,6 +1,8 @@
import { createContext, useCallback, useEffect } from 'react';
import {
acceptCarpoolRequest,
cancelCarpoolInvite,
denyCarpoolRequest,
getCarpool,
leaveCarpool,
sendCarpoolInvite,
@ -25,13 +27,19 @@ type CarpoolState = {
export const CarpoolContext = createContext({
carpool: {} as CarpoolState,
sendInvite: (user: { id: number; name: string }) => {
async sendInvite(user: { id: number; name: string }) {
console.error('not implemented: sendInvite');
},
cancelInvite: (user: { id: number; name: string }) => {
async cancelInvite(user: { id: number; name: string }) {
console.error('not implemented: cancelInvite');
},
leave: () => {
async acceptRequest(userId: number) {
console.error('not implemented: acceptRequest');
},
async denyRequest(userId: number) {
console.error('not implemented: denyRequest');
},
leave() {
console.error('not implemented: leave');
},
});
@ -55,46 +63,83 @@ export default function Carpool({ id }: { id: number }) {
});
}, [id, setCarpool]);
const acceptRequest = useCallback(
async (userId: number) => {
if (!carpool) {
console.error(
'Trying to accept request when carpool has not been loaded.'
);
return;
}
await acceptCarpoolRequest(id, userId);
const invite = carpool.invitations[userId];
const name = invite.user.name;
delete carpool.invitations[userId];
carpool.members.push({ id: userId, name });
},
[carpool, id]
);
const denyRequest = useCallback(
async (userId: number) => {
if (!carpool) {
console.error(
'Trying to deny request when carpool has not been loaded.'
);
return;
}
await denyCarpoolRequest(id, userId);
delete carpool.invitations[userId];
},
[carpool, id]
);
const sendInvite = useCallback(
(user: { id: number; name: string }) => {
if (carpool) {
sendCarpoolInvite(id, user.id)
.then(() => {
carpool.invitations[user.id] = { isRequest: false, user };
})
.catch(console.error);
} else {
async (user: { id: number; name: string }) => {
if (!carpool) {
console.error(
'Trying to send invite when carpool has not been loaded.'
);
return;
}
try {
await sendCarpoolInvite(id, user.id);
carpool.invitations[user.id] = { isRequest: false, user };
} catch (e) {
console.error(e);
}
},
[carpool, id]
);
const cancelInvite = useCallback(
(user: { id: number; name: string }) => {
async (user: { id: number; name: string }) => {
if (!carpool) {
return null;
console.error(
'Trying to cancel invite when carpool has not been loaded.'
);
return;
}
cancelCarpoolInvite(id, user.id)
.then(() => {
delete carpool.invitations[user.id];
})
.catch(console.error);
try {
await cancelCarpoolInvite(id, user.id);
} catch (e) {
console.error(e);
}
delete carpool.invitations[user.id];
},
[carpool, id]
);
const eventId = carpool?.event.id;
const leave = useCallback(() => {
const leave = useCallback(async () => {
if (eventId) {
leaveCarpool(id)
.then(() => {
window.location.href = '/events/' + eventId;
})
.catch(console.error);
try {
await leaveCarpool(id);
window.location.href = '/events/' + eventId;
} catch (e) {
console.error(e);
}
}
}, [eventId, id]);
@ -108,6 +153,8 @@ export default function Carpool({ id }: { id: number }) {
carpool,
sendInvite,
cancelInvite,
acceptRequest,
denyRequest,
leave,
}}
>

View File

@ -5,16 +5,19 @@ import { useContext } from 'react';
import useToggle from '../useToggle';
import { CarpoolContext } from './Carpool';
import InvitationList from './InvitationList';
import RequestList from './RequestList';
const spanStyle = {
padding: '0.5rem',
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
};
userSelect: 'none',
} as const;
export default function CarpoolTopButtonsMembersOnly() {
const [invitationsOpen, toggleInvitationsOpen] = useToggle(false);
const [requestsOpen, toggleRequestsOpen] = useToggle(false);
const { leave } = useContext(CarpoolContext);
return (
@ -26,8 +29,8 @@ export default function CarpoolTopButtonsMembersOnly() {
margin: '0.5rem 0',
}}
>
<span style={spanStyle} onClick={console.log}>
<MailOutlineIcon style={{ marginRight: '0.5rem' }} /> 1 request
<span style={spanStyle} onClick={toggleRequestsOpen}>
<MailOutlineIcon style={{ marginRight: '0.5rem' }} /> View requests
</span>
<span style={spanStyle} onClick={toggleInvitationsOpen}>
<PersonAddIcon style={{ marginRight: '0.5rem' }} /> Invite
@ -38,6 +41,7 @@ export default function CarpoolTopButtonsMembersOnly() {
</div>
{invitationsOpen && <InvitationList />}
{requestsOpen && <RequestList />}
</>
);
}

View File

@ -0,0 +1,77 @@
import { useMemo, useState } from 'react';
import { useCallback } from 'react';
import { useContext } from 'react';
import { lightgrey } from '../../lib/colors';
import UIButton from '../UI/UIButton';
import { CarpoolContext } from './Carpool';
function RequestRow({ user }: { user: { id: number; name: string } }) {
const { acceptRequest, denyRequest } = useContext(CarpoolContext);
const [pending, setPending] = useState(false);
const acceptCallback = useCallback(() => {
if (pending) {
return;
}
setPending(true);
acceptRequest(user.id)
.catch(console.error)
.finally(() => setPending(false));
}, [acceptRequest, pending, user.id]);
const denyCallback = useCallback(() => {
if (pending) {
return;
}
setPending(true);
denyRequest(user.id)
.catch(console.error)
.finally(() => setPending(false));
}, [denyRequest, pending, user.id]);
return (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ flex: 2 }}>{user.name}</div>
<div style={{ flex: 1 }}>
<UIButton
onClick={acceptCallback}
style={{ backgroundColor: lightgrey, padding: '0.5rem' }}
>
Accept
</UIButton>
</div>
<div style={{ flex: 1 }}>
<UIButton
onClick={denyCallback}
style={{ backgroundColor: lightgrey, padding: '0.5rem' }}
>
Decline
</UIButton>
</div>
</div>
);
}
export default function RequestList() {
const { carpool } = useContext(CarpoolContext);
const requestingUsers = useMemo(() => {
return Object.keys(carpool.invitations)
.filter((key) => carpool.invitations[key as unknown as number].isRequest)
.map((key) => carpool.invitations[key as unknown as number].user);
}, [carpool.invitations]);
return (
<>
<h1>Requests</h1>
{requestingUsers.length > 0 ? (
requestingUsers.map((user) => <RequestRow key={user.id} user={user} />)
) : (
<>Nobody's requested to join yet</>
)}
<br />
<br />
</>
);
}

View File

@ -1,5 +1,10 @@
import { useCallback } from 'react';
import { acceptInvite, acceptRequest, denyInvite, denyRequest } from '../api';
import {
acceptInvite,
acceptCarpoolRequest,
denyInvite,
denyCarpoolRequest,
} from '../api';
import { IInvitation } from '../types';
import UIButton from '../UI/UIButton';
@ -11,11 +16,11 @@ export default function Notification({
const carpoolId = notification.carpool.id;
const acceptReq = useCallback(() => {
acceptRequest(carpoolId, notification.user.id);
acceptCarpoolRequest(carpoolId, notification.user.id);
}, [carpoolId, notification.user.id]);
const rejectReq = useCallback(() => {
denyRequest(carpoolId, notification.user.id);
denyCarpoolRequest(carpoolId, notification.user.id);
}, [carpoolId, notification.user.id]);
const acceptInv = useCallback(() => {
@ -30,12 +35,12 @@ export default function Notification({
return (
<div className="notification">
{notification.user.name}
{notification.user.name}{' '}
{notification.isRequest ? (
<span> request you to join </span>
<span>requested to join</span>
) : (
<span> invited you to join </span>
)}
<span>invited you to join</span>
)}{' '}
{notification.carpool.name + ' at ' + sentTime.toLocaleString()}
{notification.isRequest ? (
<div className="notification-buttons" style={{ display: 'flex' }}>

View File

@ -5,7 +5,7 @@ const baseStyle: CSSProperties = {
borderRadius: '0.5em',
textTransform: 'uppercase',
fontWeight: 500,
marginTop: '0.5em',
margin: '0.5em',
cursor: 'pointer',
userSelect: 'none',
};

View File

@ -148,7 +148,7 @@ export async function getNotifications() {
return await get('/users/@me/received_requests_and_invites');
}
export async function acceptRequest(carpoolId: number, userId: number) {
export async function acceptCarpoolRequest(carpoolId: number, userId: number) {
return await post(`/carpools/${carpoolId}/accept_request`, { userId });
}
@ -156,7 +156,7 @@ export async function acceptInvite(carpoolId: number) {
return await post(`/carpools/${carpoolId}/accept_invite`, {});
}
export async function denyRequest(carpoolId: number, userId: number) {
export async function denyCarpoolRequest(carpoolId: number, userId: number) {
return await post(`/carpools/${carpoolId}/deny_request`, { userId });
}