all repos — caroster @ 313dd5f41e70cb7c57988fe4e0dd361d444e9ed7

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

🐛 Fixes after PO demo
Tim Izzo tim@octree.ch
Mon, 04 Mar 2024 14:08:41 +0000
commit

313dd5f41e70cb7c57988fe4e0dd361d444e9ed7

parent

c5b71a4fb82c8963c8a99496ccaaa639c16546b5

M backend/src/api/email/locales/en.jsonbackend/src/api/email/locales/en.json

@@ -16,6 +16,14 @@ "DeletedYourTrip": {

"title": "<%= event.name %> - Your trip has been removed", "content": "Your trip <%= travel.vehicleName %> has been removed by an administrator from [<%= event.name %>](<%= host %>/e/<%= event.uuid %>)." }, + "DeletedFromTrip": { + "title": "<%= event.name %> - You have been removed from car", + "content": "You have been removed from car <%= travel.vehicleName %> for [<%= event.name %>](<%= host %>/e/<%= event.uuid %>)." + }, + "DeletedFromTrip": { + "title": "<%= event.name %> - You have been removed from car", + "content": "You have been removed from car <%= travel.vehicleName %> for [<%= event.name %>](<%= host %>/e/<%= event.uuid %>)." + }, "NewPassengerInYourTrip": { "title": "<%= event.name %> - A passenger has been added to your trip", "content": "A passenger has been added to your trip on [<%= event.name %>](<%= host %>/e/<%= event.uuid %>)"

@@ -38,7 +46,7 @@ "content": "## There is something new in your event \"<%= event.name %>\"\n\n⏳ Count of passengers looking for a seat : <%= waitingListCount %>\n🚗 Count of cars : <%= travelsCount %>\n🆕 Count of new cars: <%= newTravelsCount %>\n\nLink to your Caroster: <%= host %>/e/<%= event.uuid %>\n\nYou receive this e-mail because you are the creator of this event."

}, "ContactTripCreator": { "title": "<%= event.name %> - Contact trip driver", - "content": "To organize your journey to <%= event.name %>, please contact the driver of the trip you've registered.\n\n**Car: <%= travel.vehicleName %>**\nDeparture: <%= travel.meeting %>\nDate/time: <%= datetime %>\nContact: <%= travel.phone_mumber %>" + "content": "To organize your journey to <%= event.name %>, please contact the driver of the trip you've registered.\n\n**Car: <%= travel.vehicleName %>**\nDeparture: <%= travel.meeting %>\nDate/time: <%= datetime %>\nPhone: <%= travel.phone_mumber | 'Not provided' %>\nE-mail: <%= driver.email %>" }, "EnabledCarosterPlus": { "title": "<%= event.name %> - Caroster+ is now active for your event",
M backend/src/api/email/locales/fr.jsonbackend/src/api/email/locales/fr.json

@@ -16,6 +16,14 @@ "DeletedYourTrip": {

"title": "<%= event.name %> - Votre voiture a été supprimée", "content": "Votre trajet <%= travel.vehicleName %> a été supprimé par un administrateur de l'événement [<%= event.name %>](<%= host %>/e/<%= event.uuid %>). \n Il n'est plus disponible pour l'événement et les passagers ont été informés." }, + "DeletedFromTrip": { + "title": "<%= event.name %> - Vous avez été retiré(e) d'une voiture", + "content": "Vous avez été retiré(e) de la voiture <%= travel.vehicleName %> pour l'événement [<%= event.name %>](<%= host %>/e/<%= event.uuid %>)." + }, + "DeletedFromTrip": { + "title": "<%= event.name %> - Vous avez été retiré(e) d'une voiture", + "content": "Vous avez été retiré(e) de la voiture <%= travel.vehicleName %> pour l'événement [<%= event.name %>](<%= host %>/e/<%= event.uuid %>)." + }, "NewPassengerInYourTrip": { "title": "<%= event.name %> - Un passager a été ajouté à votre trajet", "content": "Un passager a été ajouté à votre trajet pour [<%= event.name %>](<%= host %>/e/<%= event.uuid %>)."

@@ -38,7 +46,7 @@ "content": "## Il y a du nouveau dans votre Ă©vĂ©nement \"<%= event.name %>\"\n\n⏳ Nombre de passagers en recherche d'une place : <%= waitingListCount %>\n🚗 Nombre de voitures : <%= travelsCount %>\n🆕 Nombre de nouvelles voitures : <%= newTravelsCount %>\n\nLien vers votre Caroster: <%= host %>/e/<%= event.uuid %>\n\nVous recevez cet e-mail car vous ĂȘtes le crĂ©ateur de cet Ă©vĂ©nement."

}, "ContactTripCreator": { "title": "<%= event.name %> - Contacter la conductrice ou le conducteur du trajet", - "content": "Afin d'organiser votre voyage pour [<%= event.name %>](<%= host %>/e/<%= event.uuid %>), merci de contacter la conductrice ou le conducteur du trajet pour lequel vous vous ĂȘtes inscritâž±e.\n\n**Voiture: <%= travel.vehicleName %>**\nDĂ©part: <%= travel.meeting %>\nDate/heure: <%= datetime %>\nContact: <%= travel.phone_mumber %>" + "content": "Afin d'organiser votre voyage pour [<%= event.name %>](<%= host %>/e/<%= event.uuid %>), merci de contacter la conductrice ou le conducteur du trajet pour lequel vous vous ĂȘtes inscritâž±e.\n\n**Voiture: <%= travel.vehicleName %>**\nDĂ©part: <%= travel.meeting %>\nDate/heure: <%= datetime %>\nTĂ©lĂ©phone: <%= travel.phone_mumber || 'Non prĂ©cisĂ©' %>\nE-mail: <%= driver.email %>" }, "EnabledCarosterPlus": { "title": "<%= event.name %> - Caroster+ a Ă©tĂ© activĂ© pour votre Ă©vĂ©nement",
M backend/src/api/notification/content-types/notification/schema.jsonbackend/src/api/notification/content-types/notification/schema.json

@@ -19,6 +19,7 @@ "NewPassengerInYourTrip",

"NewTrip", "DeletedTrip", "DeletedYourTrip", + "DeletedFromTrip", "AddedAsAdmin", "EventCreated", "EventEnded",
M backend/src/api/passenger/policies/check-deletion.tsbackend/src/api/passenger/policies/check-deletion.ts

@@ -6,7 +6,13 @@ const passenger = await strapi.entityService.findOne(

"api::passenger.passenger", passengerId, { - populate: ["event", "user"], + populate: { + event: true, + user: true, + travel: { + populate: ["user"], + }, + }, } );

@@ -21,10 +27,20 @@ else if (!passenger.user) return true;

const admins = event.administrators?.split(/, ?/) || []; const isAdmin = [...admins, event.email].includes(user.email); - if (isAdmin) { - // TODO Create notification to passenger's linked user + const isDriver = passenger.travel?.user?.id === user.id; + + // If remove self + if (passenger.user.id == user.id) return true; + else if (isDriver || isAdmin) { + await strapi.entityService.create("api::notification.notification", { + data: { + type: "DeletedFromTrip", + event: event.id, + user: passenger.user.id, + payload: { travel: passenger.travel }, + }, + }); return true; - } else if (passenger.user.id == user.id) return true; - else return false; + } else return false; } };
M backend/src/graphql/passenger/createPassenger.tsbackend/src/graphql/passenger/createPassenger.ts

@@ -32,7 +32,15 @@ const createdPassenger = await strapi.entityService.create(

"api::passenger.passenger", { data: passengerInput, - populate: ["event", "user", "travel"], + populate: { + event: true, + user: true, + travel: { + populate: { + user: true, + }, + }, + }, } );

@@ -41,6 +49,7 @@ const enabledModules = createdPassenger.event?.enabled_modules as string[];

const isCarosterPlus = enabledModules?.includes("caroster-plus"); if (isCarosterPlus && createdPassenger.user) { const travel = createdPassenger.travel; + const driver = travel.user; const datetime = travel.departure ? moment(travel.departure) .locale(createdPassenger.user.lang || "en")

@@ -52,7 +61,7 @@ type: "ContactTripCreator",

event: createdPassenger.event.id, user: createdPassenger.user.id, // @ts-expect-error - payload: { travel, datetime }, + payload: { travel, driver, datetime }, }, }); }
M backend/types/generated/contentTypes.d.tsbackend/types/generated/contentTypes.d.ts

@@ -966,6 +966,7 @@ 'NewPassengerInYourTrip',

'NewTrip', 'DeletedTrip', 'DeletedYourTrip', + 'DeletedFromTrip', 'AddedAsAdmin', 'EventCreated', 'EventEnded',
M frontend/containers/LoginGoogle/index.tsxfrontend/containers/LoginGoogle/index.tsx

@@ -1,6 +1,7 @@

import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import {useTheme} from '@mui/material/styles'; +import {signIn} from 'next-auth/react'; import {useTranslation} from 'react-i18next'; const LoginGoogle = () => {

@@ -12,7 +13,7 @@ <Button

variant="outlined" color="primary" fullWidth - href="/api/connect/google" + onClick={() => signIn('google', {callbackUrl: '/dashboard'})} > <Box component="img"
M frontend/containers/PassengersList/index.tsxfrontend/containers/PassengersList/index.tsx

@@ -39,16 +39,13 @@ }

const PassengersList = (props: Props) => { const {passengers, Button, onClick, onPress, travel} = props; - const theme = useTheme(); - - let list = passengers; return ( <Root sx={{padding: theme.spacing(0, 0, 1, 0)}}> <List disablePadding> - {!!list && - list.map((passenger, index) => ( + {!!passengers && + passengers.map((passenger, index) => ( <ListItem sx={{paddingRight: theme.spacing(12)}} key={index}
M frontend/containers/Travel/index.tsxfrontend/containers/Travel/index.tsx

@@ -50,7 +50,7 @@ const isInTravel = travel.attributes.passengers?.data.some(

passenger => passenger.attributes.user?.data?.id === `${userId}` ); return isInTravel; - }, [travel, userId]); + }, [travel, userId, connected]); if (!travel) return null;

@@ -93,7 +93,7 @@ )}

{travel.attributes.passengers.data.length > 0 && <Divider />} <PassengersList passengers={travel.attributes.passengers.data} - onClick={actions.sendPassengerToWaitingList} + onClick={actions.removePassengerFromTravel} travel={travel} Button={({onClick, passenger}) => canDeletePassenger({
M frontend/containers/Travel/useActions.tsxfrontend/containers/Travel/useActions.tsx

@@ -10,6 +10,7 @@ EventByUuidDocument,

useUpdatePassengerMutation, TravelInput, TravelEntity, + useDeletePassengerMutation, } from '../../generated/graphql'; interface Props {

@@ -25,6 +26,25 @@ const clearToast = useToastStore(s => s.clearToast);

const [updateTravelMutation] = useUpdateTravelMutation(); const [deleteTravelMutation] = useDeleteTravelMutation(); const [updatePassenger] = useUpdatePassengerMutation(); + const [deletePassenger] = useDeletePassengerMutation(); + + const removePassengerFromTravel = async (passengerId: string) => { + const isCarosterPlus = event.enabled_modules.includes('caroster-plus'); + if (isCarosterPlus) { + try { + await deletePassenger({ + variables: { + id: passengerId, + }, + refetchQueries: ['eventByUUID'], + }); + addToast(t`travel.passengers.removed`); + } catch (error) { + console.error(error); + addToast(t('travel.errors.cant_remove_passenger')); + } + } else return sendPassengerToWaitingList(passengerId); + }; const sendPassengerToWaitingList = async (passengerId: string) => { try {

@@ -39,7 +59,7 @@ },

refetchQueries: ['eventByUUID'], }); addToast( - t('travel.moved_to_waiting_list'), + t('travel.passengers.moved_to_waiting_list'), <Link href={`/e/${event.uuid}/waitingList`} passHref> <Button size="small"

@@ -98,7 +118,7 @@ addToast(t('travel.errors.cant_remove'));

} }; - return {sendPassengerToWaitingList, updateTravel, removeTravel}; + return {removePassengerFromTravel, updateTravel, removeTravel}; }; export default useActions;
M frontend/locales/en.jsonfrontend/locales/en.json

@@ -132,6 +132,7 @@ "notification.type.AddedAsAdmin.content": "You have been promoted as administrator to the event.",

"notification.type.PassengerJoinTrip.content": "A new passenger wishes to contact you to travel with you.", "notification.type.ContactTripCreator.content": "Contact the driver to organize your trip.", "notification.type.EnabledCarosterPlus.content": "Caroster+ has been enabled for your event.", + "notification.type.DeletedFromTrip.content": "You have been removed from a trip.", "passenger.actions.place": "Assign", "passenger.actions.remove_alert": "Are you sure you want to remove <italic> <bold> {{name}} </bold> </italic> from the waitlist?", "passenger.availability.seats": "{{count}} seat available",
M frontend/locales/fr.jsonfrontend/locales/fr.json

@@ -132,6 +132,7 @@ "notification.type.AddedAsAdmin.content": "Vous avez été promu administrateur.",

"notification.type.PassengerJoinTrip.content": "Un passager souhaite prendre contact pour voyager avec vous.", "notification.type.ContactTripCreator.content": "Contactez la conductrice ou le conducteur pour organiser votre trajet.", "notification.type.EnabledCarosterPlus.content": "Caroster+ a été activé pour votre événement.", + "notification.type.DeletedFromTrip.content": "Vous avez été retiré(e) d'un trajet.", "passenger.actions.place": "Placer", "passenger.actions.remove_alert": "Voulez-vous vraiment supprimer <italic><bold>{{name}}</bold></italic> de la liste d'attente ?", "passenger.availability.seats": "{{count}} place disponible",

@@ -249,12 +250,13 @@ "travel.errors.cant_update": "Impossible de modifier la voiture",

"travel.fields.details": "Notes", "travel.fields.meeting_point": "Lieu de rencontre", "travel.fields.phone": "Contact", - "travel.moved_to_waiting_list": "Le passager a été déplacé dans la liste d'attente.", "travel.passengers.add": "Ajouter un passager", "travel.passengers.add_me": "S'ajouter", "travel.passengers.registered": "Inscrit!", "travel.passengers.add_someone": "Ajouter quelqu'un", "travel.passengers.remove": "Retirer", + "travel.passengers.removed": "Le passager a été retiré de la voiture.", + "travel.passengers.moved_to_waiting_list": "Le passager a été déplacé dans la liste d'attente.", "travel.passengers.add_to_car": "Ajouter à la voiture", "travel.passengers.add_to_travel": "Ajouter au trajet", "travel.passengers.add_to_waitingList": "Ajouter à la liste d'attente",
M frontend/locales/nl.jsonfrontend/locales/nl.json

@@ -117,6 +117,7 @@ "notification.type.NewPassengerInYourTrip.content": "",

"notification.type.NewTrip.content": "", "notification.type.DeletedTrip.content": "", "notification.type.DeletedYourTrip.content": "", + "notification.type.DeletedFromTrip.content": "", "notification.type.AddedAsAdmin.content": "", "notification.type.ContactTripCreator.content": "", "notification.type.EnabledCarosterPlus.content": "",
M frontend/locales/pl.jsonfrontend/locales/pl.json

@@ -120,6 +120,7 @@ "notification.type.NewPassengerInYourTrip.content": "",

"notification.type.NewTrip.content": "", "notification.type.DeletedTrip.content": "", "notification.type.DeletedYourTrip.content": "", + "notification.type.DeletedFromTrip.content": "", "notification.type.AddedAsAdmin.content": "", "notification.type.ContactTripCreator.content": "", "notification.type.EnabledCarosterPlus.content": "",
M frontend/locales/sv.jsonfrontend/locales/sv.json

@@ -117,6 +117,7 @@ "notification.type.NewPassengerInYourTrip.content": "",

"notification.type.NewTrip.content": "", "notification.type.DeletedTrip.content": "", "notification.type.DeletedYourTrip.content": "", + "notification.type.DeletedFromTrip.content": "", "notification.type.AddedAsAdmin.content": "", "notification.type.ContactTripCreator.content": "", "notification.type.EnabledCarosterPlus.content": "",
M frontend/pages/api/nauth/[...nextauth].jsfrontend/pages/api/nauth/[...nextauth].js

@@ -45,11 +45,19 @@ const {token, user, account} = params;

// Google Auth if (account?.provider === 'google') { - const strapiUrl = 'http://localhost:1337'; const response = await fetch( `${STRAPI_URL}/api/auth/${account.provider}/callback?access_token=${account?.access_token}` ); const data = await response.json(); + + if (data.error) { + console.error( + `Error from Strapi on authentication with Google: `, + data.error + ); + throw new Error(data.error?.message || data.error); + } + token.id = data.user.id; token.jwt = data.jwt; token.email = data.user.email;
M frontend/pages/e/[uuid]/alerts.tsxfrontend/pages/e/[uuid]/alerts.tsx

@@ -55,6 +55,13 @@ notFound: true,

}; } + const isCarosterPlus = + event?.attributes?.enabled_modules.includes('caroster-plus'); + if (!isCarosterPlus) + return { + notFound: true, + }; + try { const {data} = await apolloClient.query({ query: TripAlertDocument,
M frontend/pages/e/[uuid]/waitingList.tsxfrontend/pages/e/[uuid]/waitingList.tsx

@@ -70,6 +70,13 @@ notFound: true,

}; } + const isCarosterPlus = + event?.attributes?.enabled_modules.includes('caroster-plus'); + if (isCarosterPlus) + return { + notFound: true, + }; + return { props: { eventUUID: uuid,