all repos — caroster @ 123ddd8569ab8d7686c6a10da890601a4d6b3191

[Octree] Group carpool to your event https://caroster.io

feat: ✨ Improve 'Add myself' feature

#337
Simon Mulquin simon@octree.ch
Mon, 19 Sep 2022 09:54:41 +0000
commit

123ddd8569ab8d7686c6a10da890601a4d6b3191

parent

3f2559b63a59a0b6a88ad12faf48ada7d36937a2

M backend/.strapi-updater.jsonbackend/.strapi-updater.json

@@ -1,5 +1,5 @@

{ "latest": "4.3.8", - "lastUpdateCheck": 1663340063052, + "lastUpdateCheck": 1663575220337, "lastNotification": 1663340063046 }
A backend/src/graphql/passenger/createPassenger.ts

@@ -0,0 +1,102 @@

+const createPassenger = { + description: "Create a passenger", + async resolve(_root, args) { + const { data: passengerInput } = args; + + const { user: userId, travel: travelId } = passengerInput; + + try { + //Avoid duplicity when the connected users add themself to a new car + if (userId && travelId) { + const travel = await strapi.entityService.findOne( + "api::travel.travel", + travelId, + { populate: ["event"] } + ); + + const userPassengersIds = ( + await strapi.entityService.findMany("api::passenger.passenger", { + filters: { + user: userId, + }, + }) + ).map((userPassenger) => userPassenger.id); + + const travelsIdsBelongingToUserInEvent = ( + await strapi.entityService.findMany("api::travel.travel", { + filters: { + event: travel.event.id, + passengers: { id: { $containsi: userPassengersIds } }, + }, + }) + ).map((travel) => travel.id); + + const userDuplicatesinEvent = await strapi.entityService.findMany( + "api::passenger.passenger", + { + filters: { + $or: [ + { + event: travel.event.id, + user: userId, + }, + { + travel: { id: { $in: travelsIdsBelongingToUserInEvent } }, + user: userId, + }, + ], + }, + } + ); + + if (userDuplicatesinEvent.length > 0) { + const [existingPassenger, ...duplicated] = userDuplicatesinEvent; + + await Promise.all( + duplicated?.map(async (passenger) => { + await strapi.entityService.delete( + "api::passenger.passenger", + passenger.id + ); + }) + ); + + return makeResponse({ + operation: strapi.entityService.update( + "api::passenger.passenger", + existingPassenger.id, + { data: { ...passengerInput, event: null } } + ), + args, + }); + } + } + + return makeResponse({ + operation: await strapi.entityService.create( + "api::passenger.passenger", + { + data: passengerInput, + } + ), + args, + }); + } catch (error) { + console.log(error); + throw new Error("Couldn't create the passenger"); + } + }, +}; + +const makeResponse = async ({ operation, args }) => { + const { toEntityResponse } = strapi + .plugin("graphql") + .service("format").returnTypes; + + return toEntityResponse(await operation, { + args, + resourceUID: "api::passenger.passenger", + }); +}; + +export default createPassenger;
M backend/src/graphql/passenger/index.tsbackend/src/graphql/passenger/index.ts

@@ -1,3 +1,5 @@

+import createPassenger from "./createPassenger"; + export default [ ({ nexus, strapi }) => ({ resolvers: {

@@ -47,6 +49,9 @@ resourceUID: "api::vehicle.vehicle",

}); }, }, + }, + Mutation: { + createPassenger }, }, }),
M frontend/containers/PassengersList/Passenger.tsxfrontend/containers/PassengersList/Passenger.tsx

@@ -12,17 +12,17 @@

interface Props { passenger?: PassengerEntity; button?: ReactNode; - isVehicle?: boolean; + isTravel?: boolean; } const Passenger = (props: Props) => { - const {passenger, button, isVehicle} = props; + const {passenger, button, isTravel} = props; const {t} = useTranslation(); const classes = useStyles(); const {userId} = useProfile(); const isUser = `${userId}` === passenger?.attributes.user?.data?.id; - const showLocation = isVehicle ? false : passenger.attributes.location; + const showLocation = isTravel ? false : passenger.attributes.location; if (passenger) { return (
M frontend/containers/PassengersList/index.tsxfrontend/containers/PassengersList/index.tsx

@@ -14,7 +14,6 @@ onClick: () => void;

disabled?: boolean; }) => JSX.Element; disabled?: boolean; - isVehicle?: boolean; isTravel?: boolean; places?: number; onPress?: (passengerId: string) => void;

@@ -22,7 +21,7 @@ onClick?: (passengerId: string) => void;

} const PassengersList = (props: Props) => { - const {passengers, places, Button, onClick, onPress, disabled, isVehicle} = + const {passengers, places, Button, onClick, onPress, disabled, isTravel} = props; const classes = useStyles(); let list = passengers;

@@ -49,7 +48,7 @@ >

<Passenger key={index} passenger={passenger} - isVehicle={isVehicle} + isTravel={isTravel} button={ <Button onClick={() => onClick && onClick(passenger.id)}
M frontend/containers/Travel/index.tsxfrontend/containers/Travel/index.tsx

@@ -1,4 +1,4 @@

-import {useReducer} from 'react'; +import {useMemo, useReducer} from 'react'; import {makeStyles} from '@material-ui/core/styles'; import Divider from '@material-ui/core/Divider'; import Paper from '@material-ui/core/Paper';

@@ -9,11 +9,11 @@ import AddPassengerButtons from '../AddPassengerButtons';

import HeaderEditing from './HeaderEditing'; import Header from './Header'; import useActions from './useActions'; +import useProfile from '../../hooks/useProfile'; interface Props { travel: TravelType & {id: string}; getAddPassengerFunction: (addSelf: boolean) => () => void; - canAddSelf: boolean; } const Travel = (props: Props) => {

@@ -21,10 +21,20 @@ const {travel} = props;

const classes = useStyles(); const [isEditing, toggleEditing] = useReducer(i => !i, false); const actions = useActions({travel}); + const {userId, connected} = useProfile(); if (!travel) return null; const disableNewPassengers = travel.passengers.data?.length >= travel.seats; + const canAddSelf = useMemo(() => { + if (!connected) return false; + const isInTravel = travel.passengers?.data.some( + passenger => passenger.attributes.user?.data?.id === `${userId}` + ); + + return !isInTravel; + }, [travel, userId]); + return ( <Paper className={classes.root}> {isEditing ? (

@@ -35,7 +45,7 @@ )}

<Divider /> <AddPassengerButtons getOnClickFunction={props.getAddPassengerFunction} - canAddSelf={props.canAddSelf} + canAddSelf={canAddSelf} variant="travel" disabled={disableNewPassengers} />

@@ -45,11 +55,10 @@ <PassengersList

passengers={travel.passengers.data} places={travel?.seats} onClick={actions.sendPassengerToWaitingList} - isVehicle + isTravel Button={({onClick}: {onClick: () => void}) => ( <ClearButton icon="close" onClick={onClick} tabIndex={-1} /> )} - isTravel /> )} </Paper>
M frontend/containers/TravelColumns/index.tsxfrontend/containers/TravelColumns/index.tsx

@@ -1,4 +1,4 @@

-import {useMemo, useRef, useState} from 'react'; +import {useRef, useState} from 'react'; import {makeStyles} from '@material-ui/core/styles'; import Container from '@material-ui/core/Container'; import Slider from 'react-slick';

@@ -27,7 +27,7 @@ const slider = useRef(null);

const {t} = useTranslation(); const addToast = useToastStore(s => s.addToast); const {addToEvent} = useAddToEvents(); - const {profile, userId, connected} = useProfile(); + const {profile, userId} = useProfile(); const classes = useStyles(); const [newPassengerTravelContext, toggleNewPassengerToTravel] = useState<{ travel: TravelType;

@@ -35,19 +35,6 @@ } | null>(null);

const {addPassenger} = usePassengersActions(); const sortedTravels = travels?.slice().sort(sortTravels); - const canAddSelf = useMemo(() => { - if (!connected) return false; - const isInWaitingList = event?.waitingPassengers?.data.some( - passenger => passenger.attributes.user?.data?.id === `${userId}` - ); - const isInTravel = event?.travels?.data.some(travel => - travel.attributes.passengers?.data.some( - passenger => passenger.attributes.user?.data?.id === `${userId}` - ) - ); - return !(isInWaitingList || isInTravel); - }, [event, userId]); - const addSelfToTravel = async (travel: TravelType) => { try { await addPassenger({

@@ -85,7 +72,6 @@ >

<Travel travel={travel} {...props} - canAddSelf={canAddSelf} getAddPassengerFunction={(addSelf: boolean) => () => addSelf ? addSelfToTravel(travel)