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 {
|
import {
|
||||||
cancelCarpoolInvite,
|
cancelCarpoolInvite,
|
||||||
getCarpool,
|
getCarpool,
|
||||||
leaveCarpool,
|
leaveCarpool,
|
||||||
sendCarpoolInvite,
|
sendCarpoolInvite,
|
||||||
} from '../api';
|
} from '../api';
|
||||||
import { useMe } from '../hooks';
|
|
||||||
import { ICarpool } from '../types';
|
import { ICarpool } from '../types';
|
||||||
|
import UILink from '../UI/UILink';
|
||||||
import UISecondaryBox from '../UI/UISecondaryBox';
|
import UISecondaryBox from '../UI/UISecondaryBox';
|
||||||
import useImmutable from '../useImmutable';
|
import useImmutable from '../useImmutable';
|
||||||
import CarpoolDetails from './CarpoolDetails';
|
import CarpoolDetails from './CarpoolDetails';
|
||||||
import InvitationsAndRequests from './InvitationsAndRequests';
|
import CarpoolTopButtons from './CarpoolTopButtons';
|
||||||
import MemberList from './MemberList';
|
import MemberList from './MemberList';
|
||||||
|
|
||||||
type CarpoolState = {
|
type CarpoolState = {
|
||||||
|
@ -35,13 +35,7 @@ export const CarpoolContext = createContext({
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function Carpool({ id }: { id: number }) {
|
export default function Carpool({ id }: { id: number }) {
|
||||||
const [carpool, setCarpool] = useImmutable<CarpoolState>({
|
const [carpool, setCarpool] = useImmutable<CarpoolState | null>(null);
|
||||||
id,
|
|
||||||
name: '',
|
|
||||||
event: {} as ICarpool['event'],
|
|
||||||
members: [],
|
|
||||||
invitations: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCarpool(id).then((carpool) => {
|
getCarpool(id).then((carpool) => {
|
||||||
|
@ -78,16 +72,19 @@ export default function Carpool({ id }: { id: number }) {
|
||||||
|
|
||||||
const cancelInvite = useCallback(
|
const cancelInvite = useCallback(
|
||||||
(user: { id: number; name: string }) => {
|
(user: { id: number; name: string }) => {
|
||||||
|
if (!carpool) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
cancelCarpoolInvite(id, user.id)
|
cancelCarpoolInvite(id, user.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
delete carpool.invitations[user.id];
|
delete carpool.invitations[user.id];
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
},
|
},
|
||||||
[carpool.invitations, id]
|
[carpool, id]
|
||||||
);
|
);
|
||||||
|
|
||||||
const eventId = carpool.event.id;
|
const eventId = carpool?.event.id;
|
||||||
|
|
||||||
const leave = useCallback(() => {
|
const leave = useCallback(() => {
|
||||||
if (eventId) {
|
if (eventId) {
|
||||||
|
@ -99,13 +96,6 @@ export default function Carpool({ id }: { id: number }) {
|
||||||
}
|
}
|
||||||
}, [eventId, id]);
|
}, [eventId, id]);
|
||||||
|
|
||||||
const me = useMe();
|
|
||||||
|
|
||||||
const isMember = useMemo(
|
|
||||||
() => carpool.members.some((m) => m.id === me?.id),
|
|
||||||
[carpool.members, me?.id]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!carpool) {
|
if (!carpool) {
|
||||||
return <>Loading...</>;
|
return <>Loading...</>;
|
||||||
}
|
}
|
||||||
|
@ -120,17 +110,13 @@ export default function Carpool({ id }: { id: number }) {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<UISecondaryBox style={{ width: '100%', alignItems: 'center' }}>
|
<UISecondaryBox style={{ width: '100%', alignItems: 'center' }}>
|
||||||
{carpool ? (
|
<h1>{carpool.name}</h1>
|
||||||
<>
|
<UILink href={'/events/' + carpool.event.id}>
|
||||||
<h1 style={{ marginBottom: '0rem' }}>{carpool.name}</h1>
|
{carpool.event.name}
|
||||||
<h2 style={{ marginBottom: '0rem' }}>{carpool.event.name}</h2>
|
</UILink>
|
||||||
{isMember && <InvitationsAndRequests />}
|
<CarpoolTopButtons />
|
||||||
<CarpoolDetails />
|
<CarpoolDetails />
|
||||||
<MemberList />
|
<MemberList />
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<h2>Loading</h2>
|
|
||||||
)}
|
|
||||||
</UISecondaryBox>
|
</UISecondaryBox>
|
||||||
</CarpoolContext.Provider>
|
</CarpoolContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { CarpoolContext } from './Carpool';
|
||||||
export default function CarpoolDetails() {
|
export default function CarpoolDetails() {
|
||||||
const { carpool } = useContext(CarpoolContext);
|
const { carpool } = useContext(CarpoolContext);
|
||||||
return (
|
return (
|
||||||
<div style={{ fontSize: '1.5rem', fontWeight: 400 }}>
|
<div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
color: '#303030',
|
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 AccountCircleIcon from '@material-ui/icons/AccountCircle';
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { useContext } 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';
|
import { CarpoolContext } from './Carpool';
|
||||||
|
|
||||||
function MemberRow({ member }: { member: { id: number; name: string } }) {
|
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 shownMembersCount = 2;
|
||||||
|
|
||||||
const defaultMe = { id: 0, name: '' };
|
|
||||||
|
|
||||||
export default function MemberList() {
|
export default function MemberList() {
|
||||||
const { leave, carpool } = useContext(CarpoolContext);
|
const { carpool } = useContext(CarpoolContext);
|
||||||
const members = carpool.members;
|
const members = carpool.members;
|
||||||
const membersToShow = members.slice(0, shownMembersCount);
|
const membersToShow = members.slice(0, shownMembersCount);
|
||||||
const hiddenMemberCount = members.length - membersToShow.length;
|
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -71,48 +40,17 @@ export default function MemberList() {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h3 style={{ marginBlockEnd: '0' }}>Members</h3>
|
<h2 style={{ marginBlockEnd: '0.5rem' }}>Members</h2>
|
||||||
{members.length > 0 ? (
|
{members.length > 0 ? (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
{membersToShow.map((member) => (
|
{membersToShow.map((member) => (
|
||||||
<MemberRow member={member} key={member.id} />
|
<MemberRow member={member} key={member.id} />
|
||||||
))}
|
))}
|
||||||
{hiddenMemberCount > 0 &&
|
{formatOthers(hiddenMemberCount)}
|
||||||
(hiddenMemberCount === 1
|
|
||||||
? hiddenMemberCount + ' other...'
|
|
||||||
: hiddenMemberCount + ' others...')}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
'This carpool has no members.'
|
'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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,8 +123,11 @@ export async function getGroups(): Promise<IGroup[]> {
|
||||||
return await get('/groups');
|
return await get('/groups');
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteGroup(id: number) {
|
export async function deleteGroup(
|
||||||
await delete$('/groups/' + id);
|
id: number
|
||||||
|
): Promise<{ status: 'success' | 'error' }> {
|
||||||
|
const { status } = await delete$('/groups/' + id);
|
||||||
|
return { status };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createGroup(name: string): Promise<{ id: number }> {
|
export async function createGroup(name: string): Promise<{ id: number }> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user