all repos — caroster @ 88d8a2b5aa242ff2964f361e868e820c23153d86

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

🐛 Fix #122
Tim Izzo tim@octree.ch
Fri, 18 Jun 2021 18:11:42 +0200
commit

88d8a2b5aa242ff2964f361e868e820c23153d86

parent

62dba9246686f50004e12bc33dd33073fd58ba45

M backend/extensions/users-permissions/controllers/User.jsbackend/extensions/users-permissions/controllers/User.js

@@ -31,10 +31,17 @@ const validPassword = await strapi.plugins[

'users-permissions' ].services.user.validatePassword(old_password, user.password); if (!validPassword) throw new Error('Auth.form.error.password.matching'); - delete ctx.request.body.old_password; } + const currentUser = await strapi.plugins[ + 'users-permissions' + ].services.user.fetch({id: user.id}); + + const updatedEvents = events + ? [...currentUser.events, ...events] + : currentUser.events; + const data = await strapi.plugins['users-permissions'].services.user.edit( {id: user.id}, removeUndefined({

@@ -43,7 +50,7 @@ email,

password, firstName, lastName, - events, + events: updatedEvents, }) );
M backend/package.jsonbackend/package.json

@@ -8,7 +8,8 @@ "develop": "strapi develop",

"start": "strapi start", "build": "strapi build", "strapi": "strapi", - "test": "echo 'DO TESTS!!!'" + "test": "echo 'DO TESTS!!!'", + "console": "PORT=1338 yarn strapi console" }, "devDependencies": { "babel-eslint": "^10.1.0",
M frontend/containers/AddToMyEventDialog/index.jsfrontend/containers/AddToMyEventDialog/index.js

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

-import React, {useState} from 'react'; +import {forwardRef} from 'react'; +import {useRouter} from 'next/router'; import Dialog from '@material-ui/core/Dialog'; import DialogTitle from '@material-ui/core/DialogTitle'; import DialogActions from '@material-ui/core/DialogActions';

@@ -10,23 +11,20 @@ import Slide from '@material-ui/core/Slide';

import Button from '@material-ui/core/Button'; import IconButton from '@material-ui/core/IconButton'; import {useTranslation} from 'react-i18next'; -import {Redirect} from 'react-router-dom'; - -const Transition = React.forwardRef(function Transition(props, ref) { - return <Slide direction="up" ref={ref} {...props} />; -}); +import useAddToEvents from '../../hooks/useAddToEvents'; const AddToMyEventDialog = ({event, open, onClose}) => { const {t} = useTranslation(); - const [redirectTo, setRedirectTo] = useState(null); + const router = useRouter(); const classes = useStyles(); - if (!event) return null; + const {addToEvent} = useAddToEvents(); - if (redirectTo) { - return ( - <Redirect push to={{pathname: redirectTo, state: {event: event.id}}} /> - ); - } + const onRedirect = path => { + addToEvent(event.id); + router.push(path); + }; + + if (!event) return null; return ( <Dialog open={open} TransitionComponent={Transition} onClose={onClose}>

@@ -46,12 +44,15 @@ }}

/> </DialogContent> <DialogActions> - <Button id="AddToMyEventLogin" onClick={() => setRedirectTo('/login')}> + <Button + id="AddToMyEventLogin" + onClick={() => onRedirect(`/auth/login`)} + > {t('event.add_to_my_events.login')} </Button> <Button id="AddToMyEventRegister" - onClick={() => setRedirectTo('/register')} + onClick={() => onRedirect(`/auth/register`)} color="primary" > {t('event.add_to_my_events.register')}

@@ -61,6 +62,10 @@ </Dialog>

); }; +const Transition = forwardRef(function Transition(props, ref) { + return <Slide direction="up" ref={ref} {...props} />; +}); + const useStyles = makeStyles(theme => ({ close: { position: 'absolute',

@@ -68,4 +73,5 @@ top: theme.spacing(1),

right: theme.spacing(0.5), }, })); + export default AddToMyEventDialog;
M frontend/containers/Car/index.jsfrontend/containers/Car/index.js

@@ -3,12 +3,12 @@ import {makeStyles} from '@material-ui/core/styles';

import Divider from '@material-ui/core/Divider'; import Paper from '@material-ui/core/Paper'; import {useTranslation} from 'react-i18next'; -import useProfile from '../../hooks/useProfile'; import PassengersList from '../PassengersList'; import HeaderEditing from './HeaderEditing'; import Header from './Header'; import useEventStore from '../../stores/useEventStore'; import useToastStore from '../../stores/useToastStore'; +import useAddToEvents from '../../hooks/useAddToEvents'; import { useUpdateCarMutation, useUpdateEventMutation,

@@ -18,11 +18,11 @@ const Car = ({car}) => {

const classes = useStyles(); const {t} = useTranslation(); const event = useEventStore(s => s.event); - const {addEvent} = useProfile(); const addToast = useToastStore(s => s.addToast); const [isEditing, toggleEditing] = useReducer(i => !i, false); const [updateEvent] = useUpdateEventMutation(); const [updateCar] = useUpdateCarMutation(); + const {addToEvent} = useAddToEvents(); if (!car) return null;

@@ -36,7 +36,7 @@ passengers: [...(car.passengers || []), passenger],

}, }, }); - addEvent(event); + addToEvent(event.id); } catch (error) { console.error(error); }
M frontend/containers/EventBar/index.jsfrontend/containers/EventBar/index.js

@@ -38,7 +38,7 @@ router.push({

pathname: '/register', state: {event: event?.id}, }); - const signIn = () => router.push('/login'); + const signIn = () => router.push('/auth/login'); const goToDashboard = () => router.push('/dashboard'); const goProfile = () => router.push('/profile');
M frontend/containers/NewCarDialog/index.tsxfrontend/containers/NewCarDialog/index.tsx

@@ -11,7 +11,7 @@ import Typography from '@material-ui/core/Typography';

import {makeStyles} from '@material-ui/core/styles'; import moment from 'moment'; import {useTranslation} from 'react-i18next'; -import useProfile from '../../hooks/useProfile'; +import useAddToEvents from '../../hooks/useAddToEvents'; import useEventStore from '../../stores/useEventStore'; import useToastsStore from '../../stores/useToastStore'; import {useCreateCarMutation} from '../../generated/graphql';

@@ -20,8 +20,8 @@ const NewCarDialog = ({open, toggle}) => {

const {t} = useTranslation(); const classes = useStyles(); const addToast = useToastsStore(s => s.addToast); + const addToEvent = useAddToEvents(); const event = useEventStore(s => s.event); - const {addEvent} = useProfile(); const [createCar] = useCreateCarMutation({refetchQueries: ['event']}); // States

@@ -49,7 +49,7 @@ event: event.id,

}, }, }); - addEvent(event); + addToEvent(event.id); addToast(t('car.creation.created')); toggle();

@@ -57,7 +57,7 @@ // Clear states

setName(''); setSeats(4); setMeeting(''); - setDate(moment()); + setDate(moment().format('YYYY-MM-DD')); setPhone(''); setDetails(''); } catch (error) {
M frontend/containers/SignInForm/index.jsfrontend/containers/SignInForm/index.js

@@ -15,6 +15,7 @@ import useLoginForm from '../../hooks/useLoginForm';

import useToastsStore from '../../stores/useToastStore'; import useAuthStore from '../../stores/useAuthStore'; import useLoginWithProvider from '../../hooks/useLoginWithProvider'; +import useAddToEvents from '../../hooks/useAddToEvents'; const SignIn = () => { const {t} = useTranslation();

@@ -27,6 +28,7 @@ const [email, setEmail] = useState('');

const [password, setPassword] = useState(''); const addToast = useToastsStore(s => s.addToast); const {login, loading} = useLoginForm(email, password); + const {saveStoredEvents} = useAddToEvents(); useEffect(() => { if (token) router.replace('/dashboard');

@@ -41,8 +43,7 @@ const onSubmit = async e => {

e.preventDefault?.(); try { await login(); - // TODO add to my event if saved in local storage - // TODO remove from local storage. + saveStoredEvents(); router.push('/'); } catch (error) { handleAuthError(error);
M frontend/containers/SignUpForm/index.jsfrontend/containers/SignUpForm/index.js

@@ -11,6 +11,7 @@ import {makeStyles} from '@material-ui/core/styles';

import useToastsStore from '../../stores/useToastStore'; import {useRegisterMutation} from '../../generated/graphql'; import useAuthStore from '../../stores/useAuthStore'; +import useAddToEvents from '../../hooks/useAddToEvents'; const SignUp = () => { const {t} = useTranslation();

@@ -26,6 +27,7 @@ const [lastName, setLastName] = useState('');

const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [register] = useRegisterMutation(); + const {saveStoredEvents} = useAddToEvents(); const canSubmit = useMemo( () =>

@@ -48,6 +50,7 @@ },

}); setToken(data.register.jwt); setUser(data.register.user); + saveStoredEvents(); router.push('/dashboard'); } catch (error) { const strapiError = getStrapiError(error);

@@ -140,8 +143,11 @@ </form>

); }; -const getStrapiError = error => - error?.graphQLErrors?.[0].extensions.exception.data.message[0].messages[0].id; +const getStrapiError = error => { + if (error.message?.[0]?.messages?.[0]) return error.message[0].messages[0].id; + return error?.graphQLErrors?.[0].extensions.exception.data.message[0] + .messages[0].id; +}; const useStyles = makeStyles(theme => ({ content: {
M frontend/containers/WaitingList/index.jsfrontend/containers/WaitingList/index.js

@@ -6,7 +6,7 @@ import Paper from '@material-ui/core/Paper';

import Divider from '@material-ui/core/Divider'; import {makeStyles} from '@material-ui/core/styles'; import {Trans, useTranslation} from 'react-i18next'; -import useProfile from '../../hooks/useProfile'; +import useAddToEvents from '../../hooks/useAddToEvents'; import PassengersList from '../PassengersList'; import RemoveDialog from '../RemoveDialog'; import CarDialog from './CarDialog';

@@ -22,7 +22,7 @@ const classes = useStyles();

const {t} = useTranslation(); const event = useEventStore(s => s.event); const addToast = useToastStore(s => s.addToast); - const {addEvent} = useProfile(); + const addToEvent = useAddToEvents(); const [isEditing, toggleEditing] = useReducer(i => !i, false); const [removing, setRemoving] = useState(null); const [adding, setAdding] = useState(null);

@@ -44,13 +44,13 @@ try {

await updateEvent({ variables: {id: event.id, eventUpdate: {waiting_list: waitingList}}, }); - addEvent(event); + addToEvent(event.id); } catch (error) { console.error(error); addToast(t(i18nError)); } }, - [event, addEvent] // eslint-disable-line + [event, addToEvent] // eslint-disable-line ); const addPassenger = useCallback(
A frontend/hooks/useAddToEvents.ts

@@ -0,0 +1,55 @@

+import {useCallback} from 'react'; +import {useUpdateMeMutation} from '../generated/graphql'; +import useAuthStore from '../stores/useAuthStore'; +import create from 'zustand'; + +type Store = { + eventsToBeAdded: string[]; + addEvent: (eventId: string) => void; + clear: () => void; +}; + +const store = create<Store>((set, get) => ({ + eventsToBeAdded: [], + addEvent: eventId => + set({eventsToBeAdded: [...get().eventsToBeAdded, eventId]}), + clear: () => set({eventsToBeAdded: []}), +})); + +const useAddToEvents = () => { + const [updateProfile] = useUpdateMeMutation(); + const isAuth = useAuthStore(s => !!s.token); + const eventsToBeAdded = store(s => s.eventsToBeAdded); + const addEvent = store(s => s.addEvent); + const clearStore = store(s => s.clear); + + const saveStoredEvents = useCallback(() => { + console.log('SAVE STORED EVENTS', {eventsToBeAdded}); + if (eventsToBeAdded.length > 0) { + updateProfile({ + variables: { + userUpdate: { + events: eventsToBeAdded, + }, + }, + }); + clearStore(); + } + }, [eventsToBeAdded]); + + const addToEvent = (eventId: string) => { + if (isAuth) { + updateProfile({ + variables: { + userUpdate: { + events: [eventId], + }, + }, + }); + } else addEvent(eventId); + }; + + return {saveStoredEvents, addToEvent}; +}; + +export default useAddToEvents;
M frontend/hooks/useProfile.jsfrontend/hooks/useProfile.js

@@ -9,30 +9,17 @@ const [profile, setProfile] = useState();

const [fetchProfile, {data}] = useProfileLazyQuery(); useEffect(() => { - if (token) fetchProfile(); + if (token) { + fetchProfile(); + } }, [token]); useEffect(() => { if (data) setProfile(data.me?.profile); }, [data]); - // // TODO is useless ? - // const addEvent = async event => { - // try { - // if (!profile) - // throw new Error(`Can't add event to logged user: profile empty`); - // if (!profile?.events?.some(({id}) => id === event.id)) - // await strapi.services.users.update('me', { - // events: [...profile.events, event.id], - // }); - // } catch (error) { - // console.error(error); - // } - // }; - return { profile, - // addEvent, connected: !!token, user: user, isReady: typeof profile !== 'undefined',
M frontend/pages/auth/reset.tsxfrontend/pages/auth/reset.tsx

@@ -24,7 +24,7 @@ variables: {code: code as string, password, passwordConfirmation},

}); setPasswordError(''); addToast(t('lost_password.change_success')); - router.push('/login'); + router.push('/auth/login'); } catch (err) { if (err.message === 'Bad Request') setPasswordError(t('generic.errors.unknown'));
M frontend/pages/e/[eventId].tsxfrontend/pages/e/[eventId].tsx

@@ -26,11 +26,9 @@ const addToast = useToastStore(s => s.addToast);

const setEvent = useEventStore(s => s.setEvent); const eventUpdate = useEventStore(s => s.event); const setIsEditing = useEventStore(s => s.setIsEditing); - const { - data: {event} = {}, - loading, - error, - } = useEventQuery({variables: {id: eventId}}); + const {data: {event} = {}, loading, error} = useEventQuery({ + variables: {id: eventId}, + }); const [updateEvent] = useUpdateEventMutation(); const [isAddToMyEvent, setIsAddToMyEvent] = useState(false); const [openNewCar, toggleNewCar] = useReducer(i => !i, false);

@@ -85,11 +83,11 @@ />

<CarColumns toggleNewCar={toggleNewCar} /> <Fab onClick={toggleNewCar} open={openNewCar} aria-label="add-car" /> <NewCarDialog open={openNewCar} toggle={toggleNewCar} /> - {/* <AddToMyEventDialog + <AddToMyEventDialog event={event} open={isAddToMyEvent} onClose={() => setIsAddToMyEvent(false)} - /> */} + /> </Layout> ); };