all repos — caroster @ 8aa457368c11cb22d47eb7d30d22adec0e68f32d

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

🐛 Fixes after PO & UX reviews
Simon Mulquin simon@octree.ch
Mon, 28 Feb 2022 15:01:45 +0000
commit

8aa457368c11cb22d47eb7d30d22adec0e68f32d

parent

094a8c427e49795ce503594385599a43d41ca2bc

M frontend/containers/Languages/withLanguagesSelection.tsxfrontend/containers/Languages/withLanguagesSelection.tsx

@@ -19,7 +19,7 @@ (

LanguageSelectionComponent: ( args: LanguageSelectionComponentProps ) => JSX.Element - ) => + ) => () => { const language = useLangStore(s => s.language); const setLanguage = useLangStore(s => s.setLanguage);
M frontend/containers/NewPassengerDialog/AddPassengerCommonFields.tsxfrontend/containers/NewPassengerDialog/AddPassengerCommonFields.tsx

@@ -10,10 +10,11 @@ interface Props {

name: string; setName: (name: string) => void; email: string; + emailError: boolean; setEmail: (email: string) => void; } -const AddPassengerCommonFields = ({name, setName, email, setEmail}: Props) => { +const AddPassengerCommonFields = ({name, setName, email, emailError, setEmail}: Props) => { const {t} = useTranslation(); const classes = useStyles();

@@ -54,6 +55,8 @@ variant="outlined"

size="small" fullWidth label="" + error={email && emailError} + helperText={email && t('travel.passengers.email_helpertext')} placeholder={t('travel.passengers.email_placeholder')} /> </Box>
M frontend/containers/NewPassengerDialog/AddPassengerToTravel.tsxfrontend/containers/NewPassengerDialog/AddPassengerToTravel.tsx

@@ -13,6 +13,7 @@ import AddPassengerCommonFields from './AddPassengerCommonFields';

import useStyles from './useStyles'; import useToastStore from '../../stores/useToastStore'; import usePassengersActions from '../../hooks/usePassengersActions'; +import {validateEmail} from './validation'; interface Props { travel: TravelType;

@@ -30,6 +31,7 @@

// States const [name, setName] = useState(''); const [email, setEmail] = useState(''); + const emailValidated = validateEmail(email); const canAddPassenger = !!name; const {addPassengerToTravel} = usePassengersActions();

@@ -74,6 +76,7 @@ </DialogTitle>

<DialogContent className={classes.dialogContent}> <AddPassengerCommonFields email={email} + emailError={!emailValidated} setEmail={setEmail} name={name} setName={setName}
M frontend/containers/NewPassengerDialog/AddPassengerToWaitingList.tsxfrontend/containers/NewPassengerDialog/AddPassengerToWaitingList.tsx

@@ -16,6 +16,7 @@ import SubmitButton from './SubmitButton';

import Transition from './Transition'; import AddPassengerCommonFields from './AddPassengerCommonFields'; import useStyles from './useStyles'; +import { validateEmail } from './validation'; interface Props { toggle: () => void;

@@ -33,6 +34,7 @@

// States const [name, setName] = useState(''); const [email, setEmail] = useState(''); + const emailValidated = validateEmail(email); const [location, setlocation] = useState(''); const canAddPassenger = !!name && !!email; const {user} = useProfile();

@@ -97,6 +99,7 @@ <DialogContent className={classes.dialogContent}>

{!addSelf && ( <AddPassengerCommonFields email={email} + emailError={!emailValidated} setEmail={setEmail} name={name} setName={setName}
A frontend/containers/NewPassengerDialog/validation.ts

@@ -0,0 +1,7 @@

+export const validateEmail = (email: string) => { + return String(email) + .toLowerCase() + .match( + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + ); +};
M frontend/containers/VehicleChoiceDialog/index.tsxfrontend/containers/VehicleChoiceDialog/index.tsx

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

import VehicleItem from './VehicleItem'; import Typography from '@material-ui/core/Typography'; import {VehicleFieldsFragment} from '../../generated/graphql'; +import Icon from '@material-ui/core/Icon'; interface Props { open: boolean;

@@ -44,7 +45,12 @@ open={open}

onClose={toggle} TransitionComponent={Transition} > - <DialogTitle>{t('travel.vehicle.title')}</DialogTitle> + <DialogTitle> + {t('travel.vehicle.title')} + <Icon className={classes.closeIcon} onClick={toggle} aria-label="close"> + close + </Icon> + </DialogTitle> <DialogContent dividers className={classes.content}> {(vehicles && vehicles.length != 0 && ( <List>

@@ -100,8 +106,17 @@ new: {

maxWidth: '300px', }, empty: { - padding: theme.spacing(2, 3) - } + padding: theme.spacing(2, 3), + }, + closeIcon: { + position: 'absolute', + top: theme.spacing(2), + right: theme.spacing(2), + cursor: 'pointer', + padding: theme.spacing(0.5), + width: theme.spacing(4), + height: theme.spacing(4), + }, })); export default VehicleChoiceDialog;
M frontend/containers/WaitingList/TravelDialog.tsxfrontend/containers/WaitingList/TravelDialog.tsx

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

import IconButton from '@material-ui/core/IconButton'; import Icon from '@material-ui/core/Icon'; import Box from '@material-ui/core/Box'; -import Container from '@material-ui/core/Container'; import {makeStyles} from '@material-ui/core/styles'; import {useTranslation} from 'react-i18next'; import {ComponentPassengerPassenger, Travel} from '../../generated/graphql';
M frontend/i18n.tsfrontend/i18n.ts

@@ -2,6 +2,7 @@ import i18n from 'i18next';

import {initReactI18next} from 'react-i18next'; import translationFr from './locales/fr.json'; import translationEn from './locales/en.json'; +import {Enum_Userspermissionsuser_Lang} from './generated/graphql'; const resources = { fr: {

@@ -12,7 +13,17 @@ translation: translationEn,

}, }; -const getUserLng = () => typeof window !== 'undefined' && typeof window.navigator !== 'undefined' ? navigator.language : 'en'; +export const getUserLng = () => { + if ( + typeof window !== 'undefined' && + typeof window.navigator !== 'undefined' + ) { + if (navigator.language === 'fr' || navigator.language.includes('fr-')) { + return Enum_Userspermissionsuser_Lang.Fr + } + } + return Enum_Userspermissionsuser_Lang.En +}; i18n .use(initReactI18next) // passes i18n down to react-i18next
M frontend/locales/en.jsonfrontend/locales/en.json

@@ -165,9 +165,10 @@ "location": "Meeting place",

"location_helper": "Indicate your preferred departure location", "location_placeholder": "Meeting place (optionnal)", "email": "Email", - "email_placeholder": "email", + "email_placeholder": "Email", + "email_helpertext": "Email is not valid", "name": "Name", - "name_placeholder": "name" + "name_placeholder": "Name" }, "errors": { "cant_create": "Unable to create the car",
M frontend/locales/fr.jsonfrontend/locales/fr.json

@@ -166,6 +166,7 @@ "location_helper": "Indiquez votre lieu de départ de préférence",

"location_placeholder": "Lieu de rencontre (optionnel)", "email": "Email", "email_placeholder": "Email", + "email_helpertext": "Email non valide", "name": "Nom", "name_placeholder": "Nom" },

@@ -193,7 +194,7 @@ "noDate_plural": "Carosters sans date"

}, "noEvent": { "title": "Bienvenue sur Caroster", - "text_html": "Ici, vous y verrez <strong>les carosters auxquels vous participer</strong>, pour commencer créer un Caroster !", + "text_html": "Ici, vous y verrez <strong>les carosters auxquels vous participez</strong>, pour commencer créer un Caroster !", "create_event": "$t(menu.new_event)" } },
M frontend/pages/_app.tsxfrontend/pages/_app.tsx

@@ -16,6 +16,7 @@ import 'moment/locale/fr-ch';

import '../i18n'; import {useTranslation} from 'react-i18next'; import useAuthStore from '../stores/useAuthStore'; +import {getUserLng} from '../i18n'; moment.locale('fr-ch');

@@ -27,15 +28,10 @@ const {i18n} = useTranslation();

const language = useLangStore(s => s.language); const setLanguage = useLangStore(s => s.setLanguage); - const i18nLang = i18n.language.split('-')[1] ?? i18n.language; + const i18nLang = i18n.language.split('-')[1]; useEffect(() => { - if (i18nLang === 'FR') { - setLanguage(Enum_Userspermissionsuser_Lang.Fr); - } else { - // Fallback language - setLanguage(Enum_Userspermissionsuser_Lang.En); - } + setLanguage(getUserLng()); }, []); useEffect(() => {