Added sign in errors and logos.

This commit is contained in:
Patrick Fic
2020-08-11 20:25:50 -07:00
parent 767233cea3
commit 11d92e9aea
13 changed files with 257 additions and 86 deletions

View File

@@ -3,24 +3,22 @@
"name": "imexmobile", "name": "imexmobile",
"slug": "imexmobile", "slug": "imexmobile",
"version": "1.0.0", "version": "1.0.0",
"orientation": "portrait", "orientation": "both",
"icon": "./assets/icon.png", "icon": "./assets/icon240.png",
"splash": { "splash": {
"image": "./assets/splash.png", "image": "./assets/logo1024.png",
"resizeMode": "contain", "resizeMode": "contain",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"updates": { "updates": {
"fallbackToCacheTimeout": 0 "fallbackToCacheTimeout": 0
}, },
"assetBundlePatterns": [ "assetBundlePatterns": ["**/*"],
"**/*"
],
"ios": { "ios": {
"supportsTablet": true "supportsTablet": true
}, },
"web": { "web": {
"favicon": "./assets/favicon.png" "favicon": "./assets/logo240.png"
} }
} }
} }

BIN
assets/logo1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/logo240.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -21,6 +21,32 @@
<folder_node> <folder_node>
<name>translation</name> <name>translation</name>
<children> <children>
<folder_node>
<name>app</name>
<children>
<concept_node>
<name>title</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node> <folder_node>
<name>general</name> <name>general</name>
<children> <children>
@@ -200,6 +226,74 @@
</concept_node> </concept_node>
</children> </children>
</folder_node> </folder_node>
<folder_node>
<name>errors</name>
<children>
<concept_node>
<name>emailformat</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>usernotfound</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>wrongpassword</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node> <folder_node>
<name>fields</name> <name>fields</name>
<children> <children>

View File

@@ -1,26 +1,34 @@
import { Formik } from "formik"; import { Formik } from "formik";
import { import {
Input,
Header,
Item,
Label,
Form,
Button, Button,
Text,
Container, Container,
Content, Content,
Form,
Input,
Item,
H1,
Label,
Text,
} from "native-base"; } from "native-base";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { SafeAreaView, TextInput, View } from "react-native"; import { StyleSheet, View, ActivityIndicator, Image } from "react-native";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { emailSignInStart, signOutStart } from "../../redux/user/user.actions"; import { emailSignInStart } from "../../redux/user/user.actions";
import { selectCurrentUser } from "../../redux/user/user.selectors"; import {
import { StyleSheet } from "react-native"; selectCurrentUser,
selectSignInError,
selectSigningIn,
} from "../../redux/user/user.selectors";
import SignInErrorAlertComponent from "../sign-in-error-alert/sign-in-error-alert.component";
import styles from "../styles";
import Logo from "../../assets/logo240.png";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
signInError: selectSignInError,
signingIn: selectSigningIn,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
@@ -28,7 +36,7 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(emailSignInStart({ email, password })), dispatch(emailSignInStart({ email, password })),
}); });
export function SignIn({ emailSignInStart }) { export function SignIn({ emailSignInStart, signInError, signingIn }) {
const { t } = useTranslation(); const { t } = useTranslation();
const formSubmit = (values) => { const formSubmit = (values) => {
@@ -39,42 +47,45 @@ export function SignIn({ emailSignInStart }) {
return ( return (
<Container> <Container>
<Content <Content
scrollEnabled={false}
padder padder
contentContainerStyle={styles.contentContainer} contentContainerStyle={styles.contentContainer__centered}
style={styles.content} style={localStyles.content}
> >
<View style={styles.evenlySpacedRow}>
<Image style={localStyles.logo} source={Logo} />
<H1>{t("app.title")}</H1>
</View>
<Formik <Formik
initialValues={{ email: "", password: "" }} initialValues={{ email: "", password: "" }}
onSubmit={formSubmit} onSubmit={formSubmit}
> >
{({ handleChange, handleBlur, handleSubmit, values }) => ( {({ handleChange, handleBlur, handleSubmit, values }) => (
<View> <View>
<Form> <Item>
<Item> <Label>{t("signin.fields.email")}</Label>
<Label>{t("signin.fields.email")}</Label> <Input
<Input autoCapitalize="none"
autoCapitalize="none" keyboardType="email-address"
keyboardType="email-address" onChangeText={handleChange("email")}
onChangeText={handleChange("email")} onBlur={handleBlur("email")}
onBlur={handleBlur("email")} value={values.email}
value={values.email} />
/> </Item>
</Item> <Item>
<Label>{t("signin.fields.password")}</Label>
<Item> <Input
<Label>{t("signin.fields.password")}</Label> secureTextEntry={true}
<Input onChangeText={handleChange("password")}
secureTextEntry={true} onBlur={handleBlur("password")}
onChangeText={handleChange("password")} value={values.password}
onBlur={handleBlur("password")} />
value={values.password} </Item>
/> <SignInErrorAlertComponent />
</Item> <Button full onPress={handleSubmit}>
<Text>{t("signin.actions.signin")}</Text>
<Button full onPress={handleSubmit}> {signingIn ? <ActivityIndicator size="large" /> : null}
<Text>{t("signin.actions.signin")}</Text> </Button>
</Button>
</Form>
</View> </View>
)} )}
</Formik> </Formik>
@@ -83,19 +94,11 @@ export function SignIn({ emailSignInStart }) {
); );
} }
const styles = StyleSheet.create({ const localStyles = StyleSheet.create({
contentContainer: {
justifyContent: "center",
flex: 1,
},
content: { content: {
paddingBottom: 150, paddingBottom: 150,
// flex: 1,
// backgroundColor: "#fff",
// alignItems: "center",
//justifyContent: "space-between",
// //justifyContent: "center",
}, },
logo: { width: 100, height: 100 },
}); });
export default connect(mapStateToProps, mapDispatchToProps)(SignIn); export default connect(mapStateToProps, mapDispatchToProps)(SignIn);

View File

@@ -0,0 +1,52 @@
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Container, Content, Text } from "native-base";
import { View, StyleSheet } from "react-native";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectSignInError } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
signInError: selectSignInError,
});
export function SignInErrorAlertComponent({ signInError }) {
const [errorText, setErrorText] = useState("");
const { t } = useTranslation();
useEffect(() => {
let text;
if (signInError && signInError.code)
switch (signInError.code) {
case "auth/user-not-found":
text = t("signin.errors.usernotfound");
break;
case "auth/invalid-email":
text = t("signin.errors.emailformat");
break;
case "auth/wrong-password":
text = t("signin.errors.wrongpassword");
break;
default:
text = signInError.code + " " + signInError.message;
break;
}
setErrorText(text);
}, [signInError, setErrorText]);
return (
<View>
{errorText ? <Text style={localStyles.alert}>{errorText}</Text> : null}
</View>
);
}
export default connect(mapStateToProps, null)(SignInErrorAlertComponent);
const localStyles = StyleSheet.create({
alert: {
color: "red",
textAlign: "center",
margin: 15,
padding: 15,
},
});

15
components/styles.js Normal file
View File

@@ -0,0 +1,15 @@
import { StyleSheet } from "react-native";
import { Row } from "native-base";
export default StyleSheet.create({
contentContainer__centered: {
justifyContent: "center",
flex: 1,
},
evenlySpacedRow: {
flexDirection: "row",
justifyContent: "space-evenly",
alignItems: "center",
},
});

View File

@@ -6,39 +6,23 @@ const INITIAL_STATE = {
}, },
bodyshop: null, bodyshop: null,
fingerprint: null, fingerprint: null,
signingIn: false,
error: null, error: null,
conflict: false, conflict: false,
passwordreset: {
email: null,
error: null,
success: false,
},
}; };
const userReducer = (state = INITIAL_STATE, action) => { const userReducer = (state = INITIAL_STATE, action) => {
switch (action.type) { switch (action.type) {
// case UserActionTypes.VALIDATE_PASSWORD_RESET_START: case UserActionTypes.EMAIL_SIGN_IN_START:
// case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START: return {
// return { ...state,
// ...state, signingIn: true,
// passwordreset: { error: null,
// email: action.payload, };
// error: null,
// success: false,
// },
// };
// case UserActionTypes.VALIDATE_PASSWORD_RESET_FAILURE:
// case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_FAILURE:
// return { ...state, passwordreset: { error: action.payload } };
// case UserActionTypes.VALIDATE_PASSWORD_RESET_SUCCESS:
// case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_SUCCESS:
// return {
// ...state,
// passwordreset: { ...state.passwordreset, success: true },
// };
case UserActionTypes.SIGN_IN_SUCCESS: case UserActionTypes.SIGN_IN_SUCCESS:
return { return {
...state, ...state,
signingIn: false,
currentUser: action.payload, currentUser: action.payload,
error: null, error: null,
}; };
@@ -54,11 +38,7 @@ const userReducer = (state = INITIAL_STATE, action) => {
error: null, error: null,
currentUser: { authorized: false }, currentUser: { authorized: false },
}; };
// case UserActionTypes.SET_USER_LANGUAGE:
// return {
// ...state,
// language: action.payload,
// };
case UserActionTypes.UPDATE_USER_DETAILS_SUCCESS: case UserActionTypes.UPDATE_USER_DETAILS_SUCCESS:
return { return {
...state, ...state,
@@ -75,6 +55,7 @@ const userReducer = (state = INITIAL_STATE, action) => {
case UserActionTypes.EMAIL_SIGN_UP_FAILURE: case UserActionTypes.EMAIL_SIGN_UP_FAILURE:
return { return {
...state, ...state,
signingIn: false,
error: action.payload, error: action.payload,
}; };
default: default:

View File

@@ -26,3 +26,8 @@ export const selectPasswordReset = createSelector(
[selectUser], [selectUser],
(user) => user.passwordreset (user) => user.passwordreset
); );
export const selectSigningIn = createSelector(
[selectUser],
(user) => user.signingIn
);

View File

@@ -1,6 +1,5 @@
const UserActionTypes = { const UserActionTypes = {
SET_CURRENT_USER: "SET_CURRENT_USER", SET_CURRENT_USER: "SET_CURRENT_USER",
GOOGLE_SIGN_IN_START: "GOOGLE_SIGN_IN_START",
SIGN_IN_SUCCESS: "SIGN_IN_SUCCESS", SIGN_IN_SUCCESS: "SIGN_IN_SUCCESS",
SIGN_IN_FAILURE: "SIGN_IN_FAILURE", SIGN_IN_FAILURE: "SIGN_IN_FAILURE",
EMAIL_SIGN_IN_START: "EMAIL_SIGN_IN_START", EMAIL_SIGN_IN_START: "EMAIL_SIGN_IN_START",

View File

@@ -1,5 +1,8 @@
{ {
"translation": { "translation": {
"app": {
"title": "ImEX Mobile"
},
"general": { "general": {
"actions": { "actions": {
"signout": "Sign Out" "signout": "Sign Out"
@@ -27,6 +30,11 @@
"actions": { "actions": {
"signin": "Sign In" "signin": "Sign In"
}, },
"errors": {
"emailformat": "The email you have entered is not formatted correctly. ",
"usernotfound": "No user found.",
"wrongpassword": "The password you entered is not correct."
},
"fields": { "fields": {
"email": "Email", "email": "Email",
"password": "Password" "password": "Password"

View File

@@ -1,5 +1,8 @@
{ {
"translation": { "translation": {
"app": {
"title": ""
},
"general": { "general": {
"actions": { "actions": {
"signout": "" "signout": ""
@@ -27,6 +30,11 @@
"actions": { "actions": {
"signin": "" "signin": ""
}, },
"errors": {
"emailformat": "",
"usernotfound": "",
"wrongpassword": ""
},
"fields": { "fields": {
"email": "Email", "email": "Email",
"password": "" "password": ""

View File

@@ -1,5 +1,8 @@
{ {
"translation": { "translation": {
"app": {
"title": ""
},
"general": { "general": {
"actions": { "actions": {
"signout": "" "signout": ""
@@ -27,6 +30,11 @@
"actions": { "actions": {
"signin": "" "signin": ""
}, },
"errors": {
"emailformat": "",
"usernotfound": "",
"wrongpassword": ""
},
"fields": { "fields": {
"email": "Email", "email": "Email",
"password": "" "password": ""