mirror of
https://github.com/myfatemi04/wheelshare-frontend.git
synced 2025-04-16 00:50:18 -04:00
carpool ui revamp
This commit is contained in:
parent
a0527855da
commit
e27f62701c
|
@ -1,16 +1,16 @@
|
|||
import { createContext, useCallback, useEffect, useMemo } from 'react';
|
||||
import { createContext, useCallback, useEffect } from 'react';
|
||||
import {
|
||||
cancelCarpoolInvite,
|
||||
getCarpool,
|
||||
leaveCarpool,
|
||||
sendCarpoolInvite,
|
||||
} from '../api';
|
||||
import { useMe } from '../hooks';
|
||||
import { ICarpool } from '../types';
|
||||
import UILink from '../UI/UILink';
|
||||
import UISecondaryBox from '../UI/UISecondaryBox';
|
||||
import useImmutable from '../useImmutable';
|
||||
import CarpoolDetails from './CarpoolDetails';
|
||||
import InvitationsAndRequests from './InvitationsAndRequests';
|
||||
import CarpoolTopButtons from './CarpoolTopButtons';
|
||||
import MemberList from './MemberList';
|
||||
|
||||
type CarpoolState = {
|
||||
|
@ -35,13 +35,7 @@ export const CarpoolContext = createContext({
|
|||
});
|
||||
|
||||
export default function Carpool({ id }: { id: number }) {
|
||||
const [carpool, setCarpool] = useImmutable<CarpoolState>({
|
||||
id,
|
||||
name: '',
|
||||
event: {} as ICarpool['event'],
|
||||
members: [],
|
||||
invitations: {},
|
||||
});
|
||||
const [carpool, setCarpool] = useImmutable<CarpoolState | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
getCarpool(id).then((carpool) => {
|
||||
|
@ -78,16 +72,19 @@ export default function Carpool({ id }: { id: number }) {
|
|||
|
||||
const cancelInvite = useCallback(
|
||||
(user: { id: number; name: string }) => {
|
||||
if (!carpool) {
|
||||
return null;
|
||||
}
|
||||
cancelCarpoolInvite(id, user.id)
|
||||
.then(() => {
|
||||
delete carpool.invitations[user.id];
|
||||
})
|
||||
.catch(console.error);
|
||||
},
|
||||
[carpool.invitations, id]
|
||||
[carpool, id]
|
||||
);
|
||||
|
||||
const eventId = carpool.event.id;
|
||||
const eventId = carpool?.event.id;
|
||||
|
||||
const leave = useCallback(() => {
|
||||
if (eventId) {
|
||||
|
@ -99,13 +96,6 @@ export default function Carpool({ id }: { id: number }) {
|
|||
}
|
||||
}, [eventId, id]);
|
||||
|
||||
const me = useMe();
|
||||
|
||||
const isMember = useMemo(
|
||||
() => carpool.members.some((m) => m.id === me?.id),
|
||||
[carpool.members, me?.id]
|
||||
);
|
||||
|
||||
if (!carpool) {
|
||||
return <>Loading...</>;
|
||||
}
|
||||
|
@ -120,17 +110,13 @@ export default function Carpool({ id }: { id: number }) {
|
|||
}}
|
||||
>
|
||||
<UISecondaryBox style={{ width: '100%', alignItems: 'center' }}>
|
||||
{carpool ? (
|
||||
<>
|
||||
<h1 style={{ marginBottom: '0rem' }}>{carpool.name}</h1>
|
||||
<h2 style={{ marginBottom: '0rem' }}>{carpool.event.name}</h2>
|
||||
{isMember && <InvitationsAndRequests />}
|
||||
<CarpoolDetails />
|
||||
<MemberList />
|
||||
</>
|
||||
) : (
|
||||
<h2>Loading</h2>
|
||||
)}
|
||||
<h1>{carpool.name}</h1>
|
||||
<UILink href={'/events/' + carpool.event.id}>
|
||||
{carpool.event.name}
|
||||
</UILink>
|
||||
<CarpoolTopButtons />
|
||||
<CarpoolDetails />
|
||||
<MemberList />
|
||||
</UISecondaryBox>
|
||||
</CarpoolContext.Provider>
|
||||
);
|
||||
|
|
|
@ -7,7 +7,7 @@ import { CarpoolContext } from './Carpool';
|
|||
export default function CarpoolDetails() {
|
||||
const { carpool } = useContext(CarpoolContext);
|
||||
return (
|
||||
<div style={{ fontSize: '1.5rem', fontWeight: 400 }}>
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
color: '#303030',
|
||||
|
|
22
src/components/Carpool/CarpoolTopButtons.tsx
Normal file
22
src/components/Carpool/CarpoolTopButtons.tsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { useContext, useMemo } from 'react';
|
||||
import { useMe } from '../hooks';
|
||||
import { CarpoolContext } from './Carpool';
|
||||
import CarpoolTopButtonsMembersOnly from './CarpoolTopButtonsMembersOnly';
|
||||
import CarpoolTopButtonsNonMembersOnly from './CarpoolTopButtonsNonMembersOnly';
|
||||
|
||||
export default function CarpoolTopButtons() {
|
||||
const me = useMe();
|
||||
const { carpool } = useContext(CarpoolContext);
|
||||
const members = carpool.members;
|
||||
|
||||
const isMember = useMemo(
|
||||
() => members.some(({ id }) => id === me?.id),
|
||||
[me?.id, members]
|
||||
);
|
||||
|
||||
if (isMember) {
|
||||
return <CarpoolTopButtonsMembersOnly />;
|
||||
} else {
|
||||
return <CarpoolTopButtonsNonMembersOnly />;
|
||||
}
|
||||
}
|
43
src/components/Carpool/CarpoolTopButtonsMembersOnly.tsx
Normal file
43
src/components/Carpool/CarpoolTopButtonsMembersOnly.tsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
import MailOutlineIcon from '@material-ui/icons/MailOutline';
|
||||
import PersonAddIcon from '@material-ui/icons/PersonAdd';
|
||||
import EventBusyIcon from '@material-ui/icons/EventBusy';
|
||||
import { useContext } from 'react';
|
||||
import useToggle from '../useToggle';
|
||||
import { CarpoolContext } from './Carpool';
|
||||
import InvitationList from './InvitationList';
|
||||
|
||||
const spanStyle = {
|
||||
padding: '0.5rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
};
|
||||
|
||||
export default function CarpoolTopButtonsMembersOnly() {
|
||||
const [invitationsOpen, toggleInvitationsOpen] = useToggle(false);
|
||||
const { leave } = useContext(CarpoolContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
margin: '0.5rem 0',
|
||||
}}
|
||||
>
|
||||
<span style={spanStyle} onClick={console.log}>
|
||||
<MailOutlineIcon style={{ marginRight: '0.5rem' }} /> 1 request
|
||||
</span>
|
||||
<span style={spanStyle} onClick={toggleInvitationsOpen}>
|
||||
<PersonAddIcon style={{ marginRight: '0.5rem' }} /> Invite
|
||||
</span>
|
||||
<span style={spanStyle} onClick={leave}>
|
||||
<EventBusyIcon style={{ marginRight: '0.5rem' }} /> Leave
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{invitationsOpen && <InvitationList />}
|
||||
</>
|
||||
);
|
||||
}
|
90
src/components/Carpool/CarpoolTopButtonsNonMembersOnly.tsx
Normal file
90
src/components/Carpool/CarpoolTopButtonsNonMembersOnly.tsx
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { useCallback, useContext } from 'react';
|
||||
import { lightgrey } from '../../lib/colors';
|
||||
import { useInvitationState } from '../../state/Notifications/NotificationsHooks';
|
||||
import { NotificationsContext } from '../../state/Notifications/NotificationsProvider';
|
||||
import { useMe } from '../hooks';
|
||||
import UIButton from '../UI/UIButton';
|
||||
import { CarpoolContext } from './Carpool';
|
||||
|
||||
const defaultMe = { id: 0, name: '' };
|
||||
const greyButtonStyle = {
|
||||
backgroundColor: lightgrey,
|
||||
flex: 1,
|
||||
margin: '0.5rem',
|
||||
};
|
||||
|
||||
export default function CarpoolTopButtonsNonMembersOnly() {
|
||||
const { carpool } = useContext(CarpoolContext);
|
||||
const members = carpool.members;
|
||||
|
||||
const {
|
||||
sendCarpoolRequest,
|
||||
cancelCarpoolRequest,
|
||||
acceptCarpoolInvite,
|
||||
denyCarpoolInvite,
|
||||
} = useContext(NotificationsContext);
|
||||
|
||||
const me = useMe() || defaultMe;
|
||||
|
||||
const sendRequest = useCallback(() => {
|
||||
sendCarpoolRequest(carpool.id);
|
||||
}, [carpool.id, sendCarpoolRequest]);
|
||||
|
||||
const cancelRequest = useCallback(() => {
|
||||
cancelCarpoolRequest(carpool.id);
|
||||
}, [carpool.id, cancelCarpoolRequest]);
|
||||
|
||||
const acceptInvitation = useCallback(() => {
|
||||
acceptCarpoolInvite(carpool.id).then(() => {
|
||||
members.push(me);
|
||||
});
|
||||
}, [acceptCarpoolInvite, carpool.id, members, me]);
|
||||
|
||||
const denyInvitation = useCallback(() => {
|
||||
denyCarpoolInvite(carpool.id).then(() => {
|
||||
members.push(me);
|
||||
});
|
||||
}, [carpool.id, denyCarpoolInvite, me, members]);
|
||||
|
||||
const invitationState = useInvitationState(carpool.id);
|
||||
return (
|
||||
<>
|
||||
{invitationState === 'requested' ? (
|
||||
<UIButton
|
||||
style={{ backgroundColor: lightgrey, margin: '0.5rem' }}
|
||||
onClick={cancelRequest}
|
||||
>
|
||||
Cancel request to join
|
||||
</UIButton>
|
||||
) : invitationState === 'none' ? (
|
||||
<UIButton
|
||||
style={{ backgroundColor: lightgrey, margin: '0.5rem' }}
|
||||
onClick={sendRequest}
|
||||
>
|
||||
Request to join
|
||||
</UIButton>
|
||||
) : (
|
||||
<>
|
||||
<span style={{ marginTop: '0.5rem' }}>
|
||||
You've been invited to this carpool!
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
margin: '0.5rem 0',
|
||||
}}
|
||||
>
|
||||
<UIButton onClick={acceptInvitation} style={greyButtonStyle}>
|
||||
Accept
|
||||
</UIButton>
|
||||
<UIButton onClick={denyInvitation} style={greyButtonStyle}>
|
||||
Decline
|
||||
</UIButton>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
import { lightgrey } from '../../lib/colors';
|
||||
import UIButton from '../UI/UIButton';
|
||||
import InvitationList from './InvitationList';
|
||||
import MailOutlineIcon from '@material-ui/icons/MailOutline';
|
||||
import PersonAddIcon from '@material-ui/icons/PersonAdd';
|
||||
import useToggle from '../useToggle';
|
||||
|
||||
export default function InvitationsAndRequests() {
|
||||
const [invitationsOpen, toggleInvitationsOpen] = useToggle(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
margin: '0.5rem 0',
|
||||
}}
|
||||
>
|
||||
{/* Requests */}
|
||||
<UIButton
|
||||
style={{
|
||||
marginRight: '0.25rem',
|
||||
backgroundColor: lightgrey,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
onClick={console.log}
|
||||
>
|
||||
<MailOutlineIcon style={{ marginRight: '0.5rem' }} /> 1 request
|
||||
</UIButton>
|
||||
{/* Invitations */}
|
||||
<UIButton
|
||||
style={{
|
||||
marginLeft: '0.25rem',
|
||||
backgroundColor: lightgrey,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
onClick={toggleInvitationsOpen}
|
||||
>
|
||||
<PersonAddIcon style={{ marginRight: '0.5rem' }} /> Invite
|
||||
</UIButton>
|
||||
</div>
|
||||
|
||||
{invitationsOpen && <InvitationList />}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,12 +1,5 @@
|
|||
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
|
||||
import { useCallback } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useInvitationState } from '../../state/Notifications/NotificationsHooks';
|
||||
import { NotificationsContext } from '../../state/Notifications/NotificationsProvider';
|
||||
import { lightgrey } from '../../lib/colors';
|
||||
import { useMe } from '../hooks';
|
||||
import UIButton from '../UI/UIButton';
|
||||
import { CarpoolContext } from './Carpool';
|
||||
|
||||
function MemberRow({ member }: { member: { id: number; name: string } }) {
|
||||
|
@ -18,50 +11,26 @@ function MemberRow({ member }: { member: { id: number; name: string } }) {
|
|||
);
|
||||
}
|
||||
|
||||
function formatOthers(hiddenMemberCount: number) {
|
||||
if (hiddenMemberCount === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (hiddenMemberCount === 1) {
|
||||
return '1 other...';
|
||||
}
|
||||
|
||||
return `${hiddenMemberCount} others...`;
|
||||
}
|
||||
|
||||
const shownMembersCount = 2;
|
||||
|
||||
const defaultMe = { id: 0, name: '' };
|
||||
|
||||
export default function MemberList() {
|
||||
const { leave, carpool } = useContext(CarpoolContext);
|
||||
const { carpool } = useContext(CarpoolContext);
|
||||
const members = carpool.members;
|
||||
const membersToShow = members.slice(0, shownMembersCount);
|
||||
const hiddenMemberCount = members.length - membersToShow.length;
|
||||
|
||||
const {
|
||||
sendCarpoolRequest,
|
||||
cancelCarpoolRequest,
|
||||
acceptCarpoolInvite,
|
||||
denyCarpoolInvite,
|
||||
} = useContext(NotificationsContext);
|
||||
const invitationState = useInvitationState(carpool.id);
|
||||
|
||||
const me = useMe() || defaultMe;
|
||||
|
||||
const sendRequest = useCallback(() => {
|
||||
sendCarpoolRequest(carpool.id);
|
||||
}, [carpool.id, sendCarpoolRequest]);
|
||||
|
||||
const cancelRequest = useCallback(() => {
|
||||
cancelCarpoolRequest(carpool.id);
|
||||
}, [carpool.id, cancelCarpoolRequest]);
|
||||
|
||||
const acceptInvitation = useCallback(() => {
|
||||
acceptCarpoolInvite(carpool.id).then(() => {
|
||||
members.push(me);
|
||||
});
|
||||
}, [acceptCarpoolInvite, carpool.id, members, me]);
|
||||
|
||||
const denyInvitation = useCallback(() => {
|
||||
denyCarpoolInvite(carpool.id).then(() => {
|
||||
members.push(me);
|
||||
});
|
||||
}, [carpool.id, denyCarpoolInvite, me, members]);
|
||||
|
||||
const isMember = useMemo(() => {
|
||||
return members.some(({ id }) => id === me?.id);
|
||||
}, [me?.id, members]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
|
@ -71,48 +40,17 @@ export default function MemberList() {
|
|||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<h3 style={{ marginBlockEnd: '0' }}>Members</h3>
|
||||
<h2 style={{ marginBlockEnd: '0.5rem' }}>Members</h2>
|
||||
{members.length > 0 ? (
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
{membersToShow.map((member) => (
|
||||
<MemberRow member={member} key={member.id} />
|
||||
))}
|
||||
{hiddenMemberCount > 0 &&
|
||||
(hiddenMemberCount === 1
|
||||
? hiddenMemberCount + ' other...'
|
||||
: hiddenMemberCount + ' others...')}
|
||||
{formatOthers(hiddenMemberCount)}
|
||||
</div>
|
||||
) : (
|
||||
'This carpool has no members.'
|
||||
)}
|
||||
|
||||
{isMember ? (
|
||||
<UIButton onClick={leave} style={{ backgroundColor: lightgrey }}>
|
||||
Leave
|
||||
</UIButton>
|
||||
) : invitationState === 'requested' ? (
|
||||
<UIButton onClick={cancelRequest}>Cancel request to join</UIButton>
|
||||
) : invitationState === 'none' ? (
|
||||
<UIButton onClick={sendRequest}>Request to join</UIButton>
|
||||
) : (
|
||||
<span>
|
||||
You've been invited to this carpool!
|
||||
<div style={{ display: 'flex', width: '100%', textAlign: 'center' }}>
|
||||
<UIButton
|
||||
onClick={acceptInvitation}
|
||||
style={{ backgroundColor: lightgrey, flex: 1, margin: '0.5rem' }}
|
||||
>
|
||||
Accept
|
||||
</UIButton>
|
||||
<UIButton
|
||||
onClick={denyInvitation}
|
||||
style={{ backgroundColor: lightgrey, flex: 1, margin: '0.5rem' }}
|
||||
>
|
||||
Deny
|
||||
</UIButton>
|
||||
</div>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -123,8 +123,11 @@ export async function getGroups(): Promise<IGroup[]> {
|
|||
return await get('/groups');
|
||||
}
|
||||
|
||||
export async function deleteGroup(id: number) {
|
||||
await delete$('/groups/' + id);
|
||||
export async function deleteGroup(
|
||||
id: number
|
||||
): Promise<{ status: 'success' | 'error' }> {
|
||||
const { status } = await delete$('/groups/' + id);
|
||||
return { status };
|
||||
}
|
||||
|
||||
export async function createGroup(name: string): Promise<{ id: number }> {
|
||||
|
|
Loading…
Reference in New Issue
Block a user