18.14 Forwarding Unauthenticated Users
BuildControls.js
src\components\Burger\BuildControls\BuildControls.js
import React from "react";
import BuildControl from "./BuildControl/BuildControl";
import classes from "./BuildControls.module.css";
const controls = [
{ label: "Salad", type: "salad" },
{ label: "Bacon", type: "bacon" },
{ label: "Cheese", type: "cheese" },
{ label: "Meat", type: "meat" },
];
const buildControls = (props) => (
<div className={classes.BuildControls}>
<p>
Current Price: <strong>{props.price.toFixed(2)}</strong>
</p>
{controls.map((ctrl) => (
<BuildControl
key={ctrl.label}
label={ctrl.label}
added={() => props.ingredientAdded(ctrl.type)}
removed={() => props.ingredientRemoved(ctrl.type)}
disabled={props.disabled[ctrl.type]}
/>
))}
<button
className={classes.OrderButton}
disabled={!props.purchasable}
onClick={props.ordered}
>
{props.isAuth ? "ORDER NOW" : "SIGN UP TO ORDER"}
</button>
</div>
);
export default buildControls;
NavigationItems.js
src\components\Navigation\NavigationItems\NavigationItems.js
import React from "react";
import NavigationItem from "./NavigationItem/NavigationItem";
import classes from "./NavigationItems.module.css";
const navigationItems = (props) => (
<ul className={classes.NavigationItems}>
<NavigationItem link="/" exact>
Burger Builder
</NavigationItem>
{props.isAuthenticated ? (
<NavigationItem link="/orders">Orders</NavigationItem>
) : null}
{!props.isAuthenticated ? (
<NavigationItem link="/auth">Authenticate</NavigationItem>
) : (
<NavigationItem link="/logout">Logout</NavigationItem>
)}
</ul>
);
export default navigationItems;
Auth.js
src\containers\Auth\Auth.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import Button from "../../components/UI/Button/Button";
import Input from "../../components/UI/Input/Input";
import Spinner from "../../components/UI/Spinner/Spinner";
import * as actions from "../../store/actions/index";
import classes from "./Auth.module.css";
class Auth extends Component {
state = {
controls: {
email: {
elementType: "input",
elementConfig: {
type: "email",
placeholder: "Mail Address",
},
value: "",
validation: {
required: true,
isEmail: true,
},
valid: false,
touched: false,
},
password: {
elementType: "input",
elementConfig: {
type: "password",
placeholder: "Password",
},
value: "",
validation: {
required: true,
minLength: 6,
},
valid: false,
touched: false,
},
},
isSignup: true,
};
checkValidity(value, rules) {
let isValid = true;
if (!rules) {
return true;
}
if (rules.required) {
isValid = value.trim() !== "" && isValid;
}
if (rules.minLength) {
isValid = value.length >= rules.minLength && isValid;
}
if (rules.maxLength) {
isValid = value.length <= rules.maxLength && isValid;
}
if (rules.isEmail) {
const pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
isValid = pattern.test(value) && isValid;
}
if (rules.isNumeric) {
const pattern = /^\d+$/;
isValid = pattern.test(value) && isValid;
}
return isValid;
}
inputChangedHandler = (event, controlName) => {
const updatedControls = {
...this.state.controls,
[controlName]: {
...this.state.controls[controlName],
value: event.target.value,
valid: this.checkValidity(
event.target.value,
this.state.controls[controlName].validation
),
touched: true,
},
};
this.setState({ controls: updatedControls });
};
submitHandler = (event) => {
event.preventDefault();
this.props.onAuth(
this.state.controls.email.value,
this.state.controls.password.value,
this.state.isSignup
);
};
switchAuthModeHandler = () => {
this.setState((prevState) => {
return { isSignup: !prevState.isSignup };
});
};
render() {
const formElementsArray = [];
for (let key in this.state.controls) {
formElementsArray.push({
id: key,
config: this.state.controls[key],
});
}
let form = formElementsArray.map((formElement) => (
<Input
key={formElement.id}
elementType={formElement.config.elementType}
elementConfig={formElement.config.elementConfig}
value={formElement.config.value}
invalid={!formElement.config.valid}
shouldValidate={formElement.config.validation}
touched={formElement.config.touched}
changed={(event) => this.inputChangedHandler(event, formElement.id)}
/>
));
if (this.props.loading) {
form = <Spinner />;
}
let errorMessage = null;
if (this.props.error) {
errorMessage = <p>{this.props.error.message}</p>;
}
let authRedirect = null;
if (this.props.isAuthenticated) {
authRedirect = <Redirect to="/" />;
}
return (
<div className={classes.Auth}>
{authRedirect}
{errorMessage}
<form onSubmit={this.submitHandler}>
{form}
<Button btnType="Success">Submit</Button>
<Button clicked={this.switchAuthModeHandler} btnType="Danger">
SWITCH TO {this.state.isSignup ? "SIGNIN" : "SIGNUP"}
</Button>
</form>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.auth.loading,
error: state.auth.error,
isAuthenticated: state.auth.token !== null,
};
};
const mapDispatchToProps = (dispatch) => {
return {
onAuth: (email, password, isSignup) =>
dispatch(actions.auth(email, password, isSignup)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Auth);
BurgerBuilder.js
src\containers\BurgerBuilder\BurgerBuilder.js
import React, { Component, Fragment } from "react";
import { connect } from "react-redux";
import axios from "../../axios-orders";
import BuildControls from "../../components/Burger/BuildControls/BuildControls";
import Burger from "../../components/Burger/Burger";
import OrderSummary from "../../components/Burger/OrderSummary/OrderSummary";
import Modal from "../../components/UI/Modal/Modal";
import Spinner from "../../components/UI/Spinner/Spinner";
import withErrorHandler from "../../hoc/withErrorHandler/withErrorHandler";
import * as actions from "../../store/actions/index";
class BurgerBuilder extends Component {
// constructor(props) {
// super(props);
// this.state = {...}
// }
state = {
purchasing: false,
};
componentDidMount() {
console.log(this.props);
this.props.onInitIngredients();
}
updatePurchaseState(ingredients) {
const sum = Object.keys(ingredients)
.map((igKey) => {
return ingredients[igKey];
})
.reduce((sum, el) => {
return sum + el;
}, 0);
return sum > 0;
}
purchaseHandler = () => {
if (this.props.isAuthenticated) {
this.setState({ purchasing: true });
} else {
this.props.history.push("/auth");
}
};
purchaseCancelHandler = () => {
this.setState({ purchasing: false });
};
purchaseContinueHandler = () => {
this.props.onInitPurchase();
this.props.history.push("/checkout");
};
render() {
const disabledInfo = {
...this.props.ings,
};
for (let key in disabledInfo) {
disabledInfo[key] = disabledInfo[key] <= 0;
}
let orderSummary = null;
let burger = this.props.error ? (
<p>Ingredients can't be loaded!</p>
) : (
<Spinner />
);
if (this.props.ings) {
burger = (
<Fragment>
<Burger ingredients={this.props.ings} />
<BuildControls
ingredientAdded={this.props.onIgredientAdded}
ingredientRemoved={this.props.onIgredientRemoved}
disabled={disabledInfo}
purchasable={this.updatePurchaseState(this.props.ings)}
ordered={this.purchaseHandler}
isAuth={this.props.isAuthenticated}
price={this.props.price}
/>
</Fragment>
);
orderSummary = (
<OrderSummary
ingredients={this.props.ings}
purchaseCancelled={this.purchaseCancelHandler}
purchaseContinued={this.purchaseContinueHandler}
price={this.props.price}
/>
);
}
return (
<Fragment>
<Modal
show={this.state.purchasing}
modalClosed={this.purchaseCancelHandler}
>
{orderSummary}
</Modal>
{burger}
</Fragment>
);
}
}
const mapStateToProps = (state) => {
return {
ings: state.burgerBuilder.ingredients,
price: state.burgerBuilder.totalPrice,
error: state.burgerBuilder.error,
isAuthenticated: state.auth.token !== null,
};
};
const mapDispatchToProps = (dispatch) => {
return {
onIgredientAdded: (ingName) => dispatch(actions.addIngredient(ingName)),
onIgredientRemoved: (ingName) =>
dispatch(actions.removeIngredient(ingName)),
onInitIngredients: () => dispatch(actions.initIngredients()),
onInitPurchase: () => dispatch(actions.purchaseInit()),
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withErrorHandler(BurgerBuilder, axios));