all repos — caroster @ d093130068a7eaa39a600bd411181a85f168dc74

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

🌐 Identify user lang to send emails for anonymous #488
Tim Izzo tim@octree.ch
Thu, 15 Feb 2024 22:44:51 +0000
commit

d093130068a7eaa39a600bd411181a85f168dc74

parent

ec2276de0c9fc726e11e5be10ba90e54216f1cec

M backend/src/api/event/content-types/event/lifecycles.tsbackend/src/api/event/content-types/event/lifecycles.ts

@@ -11,8 +11,7 @@ },

async afterCreate({ result }) { await strapi .service("api::email.email") - // TODO Set dynamic lang (but how ?) - .sendEmailNotif(result.email, "EventCreated", "en", { + .sendEmailNotif(result.email, "EventCreated", result.lang, { event: result, }); },
M backend/src/api/event/content-types/event/schema.jsonbackend/src/api/event/content-types/event/schema.json

@@ -20,6 +20,11 @@ "email": {

"type": "string", "required": true }, + "lang": { + "type": "enumeration", + "enum": ["fr", "en"], + "default": "en" + }, "date": { "type": "date" },

@@ -67,9 +72,7 @@ "type": "float"

}, "enabled_modules": { "type": "customField", - "options": [ - "caroster-plus" - ], + "options": ["caroster-plus"], "customField": "plugin::multi-select.multi-select" }, "administrators": {
M backend/src/api/event/services/event.tsbackend/src/api/event/services/event.ts

@@ -34,8 +34,7 @@ .getWaitingPassengers(event);

await strapi .service("api::email.email") - // TODO Set dynamic lang (but how ?) - .sendEmailNotif(event.email, "EventRecap", "en", { + .sendEmailNotif(event.email, "EventRecap", event.lang, { event, waitingListCount: waitingPassengers?.length || 0, travelsCount: event.travels?.length || 0,

@@ -51,8 +50,7 @@ (passenger) => passenger.travel

).length; await strapi .service("api::email.email") - // TODO Set dynamic lang (but how ?) - .sendEmailNotif(event.email, "EventEnded", "en", { + .sendEmailNotif(event.email, "EventEnded", event.lang, { event, travelsCount, passengersCount,
M backend/types/generated/contentTypes.d.tsbackend/types/generated/contentTypes.d.ts

@@ -811,6 +811,7 @@ };

attributes: { name: Attribute.String & Attribute.Required; email: Attribute.String & Attribute.Required; + lang: Attribute.Enumeration<['fr', 'en']> & Attribute.DefaultTo<'en'>; date: Attribute.Date; address: Attribute.Text; position: Attribute.JSON;
A frontend/components/LangSelector/index.tsx

@@ -0,0 +1,29 @@

+import FormControl from '@mui/material/FormControl'; +import {Enum_Event_Lang} from '../../generated/graphql'; +import Select from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; +import {useTranslation} from 'react-i18next'; + +type Props = { + value: Enum_Event_Lang; + onChange: (lang: Enum_Event_Lang) => void; +}; + +const LangSelector = (props: Props) => { + const {t} = useTranslation(); + return ( + <FormControl fullWidth> + <Select + labelId="lang-selector" + id="lang-selector" + variant="standard" + value={props.value} + onChange={e => props.onChange(e.target.value)} + > + <MenuItem value={'fr'}>{t`PROTECTED.languages.fr`}</MenuItem> + <MenuItem value={'en'}>{t`PROTECTED.languages.en`}</MenuItem> + </Select> + </FormControl> + ); +}; +export default LangSelector;
M frontend/containers/CreateEvent/Step2.tsxfrontend/containers/CreateEvent/Step2.tsx

@@ -10,8 +10,15 @@ import {DatePicker} from '@mui/x-date-pickers/DatePicker';

import {useTranslation} from 'react-i18next'; import useToastStore from '../../stores/useToastStore'; import PlaceInput from '../PlaceInput'; +import {EventEntity, EventInput} from '../../generated/graphql'; -const Step2 = ({event, addToEvent, createEvent}) => { +interface Props { + event: EventInput; + addToEvent: (eventData: EventInput) => void; + createEvent: (eventData: EventInput) => Promise<EventEntity>; +} + +const Step2 = ({event, addToEvent, createEvent}: Props) => { const {t} = useTranslation(); const theme = useTheme(); const router = useRouter();

@@ -26,11 +33,11 @@ const [description, setDescription] = useState(event.description ?? '');

const [loading, setLoading] = useState(false); const onCreate = async evt => { - if (evt.preventDefault) evt.preventDefault(); + evt.preventDefault?.(); if (loading) return; setLoading(true); const eventData = { - date: !date ? null : moment(date).format('YYYY-MM-DD'), + date: date ? moment(date).format('YYYY-MM-DD') : null, address, longitude, latitude,

@@ -39,7 +46,7 @@ };

addToEvent(eventData); const result = await createEvent(eventData); if (!result) addToast(t('event.errors.cant_create')); - else router.push(`/e/${result.uuid}`); + else router.push(`/e/${result.attributes.uuid}`); setLoading(false); return; };

@@ -60,9 +67,9 @@ place={address}

latitude={event.latitude} longitude={event.longitude} onSelect={({place, latitude, longitude}) => { - setAddress(place); - setLatitude(latitude); - setLongitude(longitude); + setAddress(place); + setLatitude(latitude); + setLongitude(longitude); }} /> <TextField
M frontend/containers/CreateEvent/index.tsxfrontend/containers/CreateEvent/index.tsx

@@ -2,33 +2,40 @@ import {useState, useReducer} from 'react';

import useAddToEvents from '../../hooks/useAddToEvents'; import Step1 from './Step1'; import Step2 from './Step2'; -import {ProfileDocument, useCreateEventMutation} from '../../generated/graphql'; +import { + EventInput, + ProfileDocument, + useCreateEventMutation, +} from '../../generated/graphql'; +import useLocale from '../../hooks/useLocale'; const STEPS = [Step1, Step2]; const CreateEvent = () => { const [step, setStep] = useState(0); - const [event, addToEvent] = useReducer(eventReducer, {}); + const [event, addToEvent] = useReducer(eventReducer, {} as EventInput); const [sendEvent] = useCreateEventMutation(); const {addToEvent: addToUserEvents} = useAddToEvents(); + const {locale} = useLocale(); const Step = STEPS[step]; - const createEvent = async eventData => { + const createEvent = async (eventData: EventInput) => { try { - const variables = { - ...event, - ...eventData, - }; const {data} = await sendEvent({ - variables, + variables: { + eventData: { + ...event, + ...eventData, + lang: locale, + }, + }, refetchQueries: [ProfileDocument], }); - const {id, attributes} = data.createEvent.data; - addToUserEvents(id); - return {id, ...attributes}; + const createdEvent = data.createEvent.data; + addToUserEvents(createdEvent.id); + return createdEvent; } catch (err) { console.error(err); - return false; } };
M frontend/generated/graphql.tsxfrontend/generated/graphql.tsx

@@ -203,6 +203,11 @@ publish = 'publish',

unpublish = 'unpublish' } +export enum Enum_Event_Lang { + en = 'en', + fr = 'fr' +} + export enum Enum_Notification_Type { AddedAsAdmin = 'AddedAsAdmin', DeletedTrip = 'DeletedTrip',

@@ -232,6 +237,7 @@ date?: Maybe<Scalars['Date']['output']>;

description?: Maybe<Scalars['String']['output']>; email: Scalars['String']['output']; enabled_modules?: Maybe<Scalars['JSON']['output']>; + lang?: Maybe<Enum_Event_Lang>; latitude?: Maybe<Scalars['Float']['output']>; longitude?: Maybe<Scalars['Float']['output']>; name: Scalars['String']['output'];

@@ -284,6 +290,7 @@ description?: InputMaybe<StringFilterInput>;

email?: InputMaybe<StringFilterInput>; enabled_modules?: InputMaybe<JsonFilterInput>; id?: InputMaybe<IdFilterInput>; + lang?: InputMaybe<StringFilterInput>; latitude?: InputMaybe<FloatFilterInput>; longitude?: InputMaybe<FloatFilterInput>; name?: InputMaybe<StringFilterInput>;

@@ -305,6 +312,7 @@ date?: InputMaybe<Scalars['Date']['input']>;

description?: InputMaybe<Scalars['String']['input']>; email?: InputMaybe<Scalars['String']['input']>; enabled_modules?: InputMaybe<Scalars['JSON']['input']>; + lang?: InputMaybe<Enum_Event_Lang>; latitude?: InputMaybe<Scalars['Float']['input']>; longitude?: InputMaybe<Scalars['Float']['input']>; name?: InputMaybe<Scalars['String']['input']>;

@@ -2061,21 +2069,14 @@

export type ResetPasswordMutation = { __typename?: 'Mutation', resetPassword?: { __typename?: 'UsersPermissionsLoginPayload', jwt?: string | null, user: { __typename?: 'UsersPermissionsMe', id: string, username: string, email?: string | null, confirmed?: boolean | null } } | null }; -export type EventFieldsFragment = { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null }; +export type EventFieldsFragment = { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, lang?: Enum_Event_Lang | null, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null }; export type CreateEventMutationVariables = Exact<{ - name: Scalars['String']['input']; - email: Scalars['String']['input']; - date?: InputMaybe<Scalars['Date']['input']>; - address?: InputMaybe<Scalars['String']['input']>; - latitude?: InputMaybe<Scalars['Float']['input']>; - longitude?: InputMaybe<Scalars['Float']['input']>; - description?: InputMaybe<Scalars['String']['input']>; - newsletter?: InputMaybe<Scalars['Boolean']['input']>; + eventData: EventInput; }>; -export type CreateEventMutation = { __typename?: 'Mutation', createEvent?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null } | null } | null }; +export type CreateEventMutation = { __typename?: 'Mutation', createEvent?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, lang?: Enum_Event_Lang | null, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null } | null } | null }; export type UpdateEventMutationVariables = Exact<{ uuid: Scalars['String']['input'];

@@ -2083,7 +2084,7 @@ eventUpdate: EventInput;

}>; -export type UpdateEventMutation = { __typename?: 'Mutation', updateEventByUUID?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null } | null } | null }; +export type UpdateEventMutation = { __typename?: 'Mutation', updateEventByUUID?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, lang?: Enum_Event_Lang | null, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null } | null } | null }; export type AddEventAdminMutationVariables = Exact<{ eventId: Scalars['ID']['input'];

@@ -2106,7 +2107,7 @@ uuid: Scalars['String']['input'];

}>; -export type EventByUuidQuery = { __typename?: 'Query', eventByUUID?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null } | null } | null }; +export type EventByUuidQuery = { __typename?: 'Query', eventByUUID?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', uuid?: string | null, name: string, description?: string | null, enabled_modules?: any | null, email: string, lang?: Enum_Event_Lang | null, administrators?: Array<string | null> | null, date?: any | null, address?: string | null, latitude?: number | null, longitude?: number | null, position?: any | null, waitingPassengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, email?: string | null, location?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null, travels?: { __typename?: 'TravelRelationResponseCollection', data: Array<{ __typename?: 'TravelEntity', id?: string | null, attributes?: { __typename?: 'Travel', meeting?: string | null, meeting_latitude?: number | null, meeting_longitude?: number | null, departure?: any | null, details?: string | null, vehicleName?: string | null, phone_number?: string | null, seats?: number | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null } | null } | null, passengers?: { __typename?: 'PassengerRelationResponseCollection', data: Array<{ __typename?: 'PassengerEntity', id?: string | null, attributes?: { __typename?: 'Passenger', name: string, location?: string | null, email?: string | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', firstName?: string | null, lastName?: string | null } | null } | null } | null } | null }> } | null } | null }> } | null } | null } | null } | null }; export type ModuleQueryVariables = Exact<{ locale: Scalars['I18NLocaleCode']['input'];

@@ -2230,6 +2231,7 @@ name

description enabled_modules email + lang administrators date address

@@ -2596,10 +2598,8 @@ export type ResetPasswordMutationHookResult = ReturnType<typeof useResetPasswordMutation>;

export type ResetPasswordMutationResult = Apollo.MutationResult<ResetPasswordMutation>; export type ResetPasswordMutationOptions = Apollo.BaseMutationOptions<ResetPasswordMutation, ResetPasswordMutationVariables>; export const CreateEventDocument = gql` - mutation createEvent($name: String!, $email: String!, $date: Date, $address: String, $latitude: Float, $longitude: Float, $description: String, $newsletter: Boolean) { - createEvent( - data: {name: $name, email: $email, date: $date, latitude: $latitude, longitude: $longitude, address: $address, description: $description, newsletter: $newsletter} - ) { + mutation createEvent($eventData: EventInput!) { + createEvent(data: $eventData) { data { ...EventFields }

@@ -2621,14 +2621,7 @@ *

* @example * const [createEventMutation, { data, loading, error }] = useCreateEventMutation({ * variables: { - * name: // value for 'name' - * email: // value for 'email' - * date: // value for 'date' - * address: // value for 'address' - * latitude: // value for 'latitude' - * longitude: // value for 'longitude' - * description: // value for 'description' - * newsletter: // value for 'newsletter' + * eventData: // value for 'eventData' * }, * }); */
M frontend/graphql/event.gqlfrontend/graphql/event.gql

@@ -6,6 +6,7 @@ name

description enabled_modules email + lang administrators date address

@@ -73,28 +74,8 @@ }

} } -mutation createEvent( - $name: String! - $email: String! - $date: Date - $address: String - $latitude: Float - $longitude: Float - $description: String - $newsletter: Boolean -) { - createEvent( - data: { - name: $name - email: $email - date: $date - latitude: $latitude - longitude: $longitude - address: $address - description: $description - newsletter: $newsletter - } - ) { +mutation createEvent($eventData: EventInput!) { + createEvent(data: $eventData) { data { ...EventFields }
M frontend/locales/en.jsonfrontend/locales/en.json

@@ -65,6 +65,7 @@ "event.fields.empty": "Not specified",

"event.fields.link": "Share link", "event.fields.link_desc": "Share this link with other people", "event.fields.name": "Name of the event", + "event.fields.lang": "Language", "event.fields.share": "Share", "event.no_other_travel.title": "There are currently no other car", "event.no_travel.desc": "1. Subscribe to the waiting list\n2. Share the event\n3. You will be notified when a new travel is added",
M frontend/locales/fr.jsonfrontend/locales/fr.json

@@ -65,6 +65,7 @@ "event.fields.empty": "Non précisé",

"event.fields.link": "Lien de partage", "event.fields.link_desc": "Partager l'évènement à d'autres personnes", "event.fields.name": "Nom de l'événement", + "event.fields.lang": "Langue", "event.fields.share": "Partager", "event.no_other_travel.title": "Pas d'autres voitures pour le moment", "event.no_travel.desc": "1. Inscrivez-vous dans la liste d’attente \n2. Partagez l’événement \n3. Vous serez notifié lorsqu’un nouveau trajet sera ajouté",
M frontend/locales/nl.jsonfrontend/locales/nl.json

@@ -56,6 +56,7 @@ "event.fields.empty": "Niet opgegeven",

"event.fields.link": "Link delen", "event.fields.link_desc": "Deel deze link met anderen", "event.fields.name": "Afspraaknaam", + "event.fields.lang": "", "event.fields.share": "Delen", "event.no_other_travel.title": "Er is momenteel geen andere auto", "event.no_travel.desc": "1. Zet uzelf op de wachtlijst;\n2. Deel de afspraak;\n3. Ontvang een melding zodra er een reis beschikbaar is.",
M frontend/locales/pl.jsonfrontend/locales/pl.json

@@ -59,6 +59,7 @@ "event.fields.empty": "Nie określono",

"event.fields.link": "Udostępnij link", "event.fields.link_desc": "Udostępnij ten link innym osobom", "event.fields.name": "Nazwa wydarzenia", + "event.fields.lang": "", "event.fields.share": "Udostępnij", "event.no_other_travel.title": "Obecnie nie ma żadnych innych samochodów", "event.no_travel.desc": "1. Zasubskrybuj listę oczekujących\n2. Udostępnij wydarzenie\n3. Dostaniesz powiadomienie kiedy zostanie dodana nowa podróż",
M frontend/locales/sv.jsonfrontend/locales/sv.json

@@ -56,6 +56,7 @@ "event.fields.empty": "",

"event.fields.link": "", "event.fields.link_desc": "", "event.fields.name": "", + "event.fields.lang": "", "event.fields.share": "", "event.no_other_travel.title": "", "event.no_travel.desc": "",
M frontend/pages/e/[uuid]/details.tsxfrontend/pages/e/[uuid]/details.tsx

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

import moment from 'moment'; import Tooltip from '@mui/material/Tooltip'; import IconButton from '@mui/material/IconButton'; -import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import Link from '@mui/material/Link'; import Card from '@mui/material/Card';

@@ -19,6 +18,7 @@ import {useTranslation} from 'react-i18next';

import pageUtils from '../../../lib/pageUtils'; import ShareEvent from '../../../containers/ShareEvent'; import PlaceInput from '../../../containers/PlaceInput'; +import LangSelector from '../../../components/LangSelector'; import usePermissions from '../../../hooks/usePermissions'; import useEventStore from '../../../stores/useEventStore'; import useToastStore from '../../../stores/useToastStore';

@@ -54,7 +54,15 @@

const onSave = async e => { try { const {uuid, ...data} = event; - const {id, travels, waitingPassengers, __typename, ...input} = data; + const { + id, + travels, + waitingPassengers, + __typename, + administrators, + passengers, + ...input + } = data; await updateEvent({ variables: { uuid,

@@ -130,7 +138,7 @@ </Typography>

{canEditEventDetails() && modifyButton} <Box pt={2} pr={1.5}> <Typography variant="overline">{t('event.fields.name')}</Typography> - <Typography variant="body1"> + <Typography> {isEditing ? ( <TextField size="small"

@@ -141,7 +149,7 @@ name="name"

id="EditEventName" /> ) : ( - <Typography variant="body1" id="EventName"> + <Typography id="EventName"> {event.name ?? t('event.fields.empty')} </Typography> )}

@@ -150,7 +158,7 @@ </Box>

<Box pt={2} pr={1.5}> <Typography variant="overline">{t('event.fields.date')}</Typography> {isEditing ? ( - <Typography variant="body1"> + <Typography> <DatePicker slotProps={{ textField: {

@@ -171,7 +179,7 @@ />

</Typography> ) : ( <Box position="relative"> - <Typography variant="body1" id="EventDate"> + <Typography id="EventDate"> {event.date ? moment(event.date).format('DD/MM/YYYY') : t('event.fields.empty')}

@@ -206,7 +214,7 @@ }

/> ) : ( <Box position="relative"> - <Typography variant="body1" id="EventAddress" sx={{pr: 3}}> + <Typography id="EventAddress" sx={{pr: 3}}> {event.address ? ( <Link target="_blank"

@@ -238,7 +246,7 @@ <Typography variant="overline">

{t('event.fields.description')} </Typography> {isEditing ? ( - <Typography variant="body1"> + <Typography> <TextField fullWidth multiline

@@ -251,8 +259,23 @@ name="description"

/> </Typography> ) : ( - <Typography variant="body1" id="EventDescription" sx={{pr: 3}}> + <Typography id="EventDescription" sx={{pr: 3}}> {event.description ?? t('event.fields.empty')} + </Typography> + )} + </Box> + <Box pt={2} pr={1.5}> + <Typography variant="overline">{t('event.fields.lang')}</Typography> + {isEditing ? ( + <LangSelector + value={event.lang} + onChange={lang => setEventUpdate({lang})} + /> + ) : ( + <Typography id="EventLang" sx={{pr: 3}}> + {event.lang + ? t(`PROTECTED.languages.${event.lang}`) + : t('event.fields.empty')} </Typography> )} </Box>