Fixed up general layout of manage page + root + styled login page.
This commit is contained in:
@@ -1,32 +1,36 @@
|
||||
import React from "react";
|
||||
import { HomeFilled } from "@ant-design/icons";
|
||||
import { Breadcrumb } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBreadcrumbs } from "../../redux/application/application.selectors";
|
||||
import { Link } from "react-router-dom";
|
||||
import { HomeFilled } from "@ant-design/icons";
|
||||
import "./breadcrumbs.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
breadcrumbs: selectBreadcrumbs,
|
||||
});
|
||||
|
||||
export function BreadCrumbs({ breadcrumbs }) {
|
||||
return (
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>
|
||||
<Link to={`/manage`}>
|
||||
<HomeFilled />
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
{breadcrumbs.map((item) =>
|
||||
item.link ? (
|
||||
<Breadcrumb.Item key={item.label}>
|
||||
<Link to={item.link}>{item.label} </Link>
|
||||
</Breadcrumb.Item>
|
||||
) : (
|
||||
<Breadcrumb.Item key={item.label}>{item.label}</Breadcrumb.Item>
|
||||
)
|
||||
)}
|
||||
</Breadcrumb>
|
||||
<div className='breadcrumb-container'>
|
||||
<Breadcrumb separator='>'>
|
||||
<Breadcrumb.Item>
|
||||
<Link to={`/manage`}>
|
||||
<HomeFilled />
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
{breadcrumbs.map((item) =>
|
||||
item.link ? (
|
||||
<Breadcrumb.Item key={item.label}>
|
||||
<Link to={item.link}>{item.label} </Link>
|
||||
</Breadcrumb.Item>
|
||||
) : (
|
||||
<Breadcrumb.Item key={item.label}>{item.label}</Breadcrumb.Item>
|
||||
)
|
||||
)}
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, null)(BreadCrumbs);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.breadcrumb-container {
|
||||
margin: 1rem 4rem;
|
||||
}
|
||||
@@ -6,21 +6,22 @@ import Icon, {
|
||||
GlobalOutlined,
|
||||
HomeFilled,
|
||||
TeamOutlined,
|
||||
UserOutlined
|
||||
} from "@ant-design/icons";
|
||||
import { Avatar, Col, Menu, Row, Layout } from "antd";
|
||||
import { Avatar, Col, Layout, Menu, Row } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaCalendarAlt, FaCarCrash } from "react-icons/fa";
|
||||
import { connect } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import UserImage from "../../assets/User.svg";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { signOutStart } from "../../redux/user/user.actions";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
selectCurrentUser
|
||||
} from "../../redux/user/user.selectors";
|
||||
import "./header.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -37,6 +38,32 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
signOutStart: () => dispatch(signOutStart()),
|
||||
});
|
||||
|
||||
const logoSpan = {
|
||||
xs: {
|
||||
span: 0,
|
||||
},
|
||||
md: {
|
||||
span: 1,
|
||||
},
|
||||
lg: {
|
||||
span: 2,
|
||||
},
|
||||
};
|
||||
|
||||
const menuSpan = {
|
||||
xs: {
|
||||
span: 24,
|
||||
},
|
||||
md: {
|
||||
span: 22,
|
||||
offset: 1,
|
||||
},
|
||||
lg: {
|
||||
span: 21,
|
||||
offset: 1,
|
||||
},
|
||||
};
|
||||
|
||||
function Header({
|
||||
bodyshop,
|
||||
handleMenuClick,
|
||||
@@ -47,12 +74,14 @@ function Header({
|
||||
setPaymentContext,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { Header } = Layout;
|
||||
|
||||
return (
|
||||
<Layout.Header>
|
||||
<Row align='middle'>
|
||||
<Col span={4}>
|
||||
<Header>
|
||||
<Row>
|
||||
<Col {...logoSpan}>
|
||||
<img
|
||||
className='header-shop-logo'
|
||||
alt={bodyshop ? bodyshop.shopname : "ImEX Online Logo"}
|
||||
src={
|
||||
bodyshop && bodyshop.logo_img_path
|
||||
@@ -61,8 +90,12 @@ function Header({
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
<Menu mode='horizontal' onClick={handleMenuClick}>
|
||||
<Col {...menuSpan}>
|
||||
<Menu
|
||||
mode='horizontal'
|
||||
theme='dark'
|
||||
className='header-main-menu'
|
||||
onClick={handleMenuClick}>
|
||||
<Menu.Item key='home'>
|
||||
<Link to='/manage'>
|
||||
<HomeFilled />
|
||||
@@ -114,7 +147,6 @@ function Header({
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
|
||||
<Menu.SubMenu
|
||||
title={
|
||||
<span>
|
||||
@@ -141,7 +173,6 @@ function Header({
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
|
||||
<Menu.SubMenu
|
||||
title={
|
||||
<span>
|
||||
@@ -194,7 +225,6 @@ function Header({
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
|
||||
<Menu.SubMenu title={t("menus.header.shop")}>
|
||||
<Menu.Item key='shop'>
|
||||
<Link to='/manage/shop'>{t("menus.header.shop_config")}</Link>
|
||||
@@ -213,21 +243,26 @@ function Header({
|
||||
<Link to='/manage/shop/csi'>{t("menus.header.shop_csi")}</Link>
|
||||
</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
</Menu>
|
||||
</Col>
|
||||
<Col span={4}>
|
||||
<Menu>
|
||||
<Menu.SubMenu
|
||||
title={
|
||||
<div>
|
||||
<Avatar
|
||||
size='medium'
|
||||
alt='Avatar'
|
||||
src={
|
||||
currentUser.photoURL ? currentUser.photoURL : UserImage
|
||||
}
|
||||
style={{ margin: "10px" }}
|
||||
/>
|
||||
{currentUser.photoURL ? (
|
||||
<Avatar
|
||||
src={currentUser.photoURL}
|
||||
style={{
|
||||
margin: "10px",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Avatar
|
||||
style={{
|
||||
backgroundColor: "#87d068",
|
||||
margin: "10px",
|
||||
}}
|
||||
icon={<UserOutlined />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{currentUser.displayName || t("general.labels.unknown")}
|
||||
</div>
|
||||
}>
|
||||
@@ -260,7 +295,7 @@ function Header({
|
||||
</Menu>
|
||||
</Col>
|
||||
</Row>
|
||||
</Layout.Header>
|
||||
</Header>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
9
client/src/components/header/header.styles.scss
Normal file
9
client/src/components/header/header.styles.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
.header-shop-logo {
|
||||
background-size: cover;
|
||||
max-width: 100%;
|
||||
max-height: 3.5rem;
|
||||
}
|
||||
.header-main-menu {
|
||||
width: 80vw;
|
||||
float: left;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useElements, useStripe, CardElement } from "@stripe/react-stripe-js";
|
||||
import { useElements, useStripe } from "@stripe/react-stripe-js";
|
||||
import { Form, Modal } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import PaymentForm from "../payment-form/payment-form.container";
|
||||
import axios from "axios";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
paymentModal: selectPayment,
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -38,7 +37,7 @@ function InvoiceEnterModalContainer({
|
||||
error: null,
|
||||
cardComplete: false,
|
||||
});
|
||||
const [stripeState, setStripeState] = stripeStateArr;
|
||||
const stripeState = stripeStateArr[0];
|
||||
|
||||
const cardValid = !!!stripeState.error && stripeState.cardComplete;
|
||||
|
||||
@@ -105,14 +104,12 @@ function InvoiceEnterModalContainer({
|
||||
onCancel={handleCancel}
|
||||
afterClose={() => form.resetFields()}
|
||||
okButtonProps={{ loading: loading, disabled: !cardValid }}
|
||||
destroyOnClose
|
||||
>
|
||||
destroyOnClose>
|
||||
<Form
|
||||
onFinish={handleFinish}
|
||||
autoComplete={"off"}
|
||||
form={form}
|
||||
initialValues={{ jobid: context.jobId }}
|
||||
>
|
||||
initialValues={{ jobid: context.jobId }}>
|
||||
<PaymentForm form={form} stripeStateArr={stripeStateArr} />
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import { LockOutlined, UserOutlined } from "@ant-design/icons";
|
||||
import { Button, Form, Input } from "antd";
|
||||
import { Button, Form, Input, Typography } from "antd";
|
||||
import React from "react";
|
||||
import { useApolloClient } from "react-apollo";
|
||||
import { connect } from "react-redux";
|
||||
import { Redirect } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import Logo from "../../assets/logo240.png";
|
||||
import ImEXOnlineLogo from "../../assets/logo240.png";
|
||||
import { UPSERT_USER } from "../../graphql/user.queries";
|
||||
import { emailSignInStart } from "../../redux/user/user.actions";
|
||||
import {
|
||||
selectCurrentUser,
|
||||
selectSignInError,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import "./sign-in-form.styles.scss";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -23,16 +26,18 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(emailSignInStart({ email, password })),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(function SignInComponent({ emailSignInStart, currentUser, signInError }) {
|
||||
export function SignInComponent({
|
||||
emailSignInStart,
|
||||
currentUser,
|
||||
signInError,
|
||||
}) {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const handleFinish = (values) => {
|
||||
const { email, password } = values;
|
||||
emailSignInStart(email, password);
|
||||
};
|
||||
const [form] = Form.useForm();
|
||||
|
||||
if (currentUser.authorized === true) {
|
||||
apolloClient
|
||||
@@ -49,38 +54,48 @@ export default connect(
|
||||
});
|
||||
}
|
||||
|
||||
const handleLogin = () => {
|
||||
form.submit();
|
||||
};
|
||||
|
||||
if (currentUser.authorized === true) return <Redirect to='/manage' />;
|
||||
return (
|
||||
<div style={{ width: "450px" }}>
|
||||
{currentUser.authorized === true ? <Redirect to="/manage?" /> : null}
|
||||
|
||||
<img src={Logo} height="100" width="100" alt="Bodyshop.app" />
|
||||
|
||||
<Form onFinish={handleFinish}>
|
||||
<div className='login-container'>
|
||||
<div className='login-logo-container'>
|
||||
<img src={ImEXOnlineLogo} height='100' width='100' alt='ImEX Online' />
|
||||
<Typography.Title>{t("titles.app")}</Typography.Title>
|
||||
</div>
|
||||
<Form onFinish={handleFinish} form={form} size='large'>
|
||||
<Form.Item
|
||||
name="email"
|
||||
rules={[{ required: true, message: "Please input your email!" }]}
|
||||
>
|
||||
name='email'
|
||||
rules={[
|
||||
{ required: true, message: t("general.validation.required") },
|
||||
]}>
|
||||
<Input
|
||||
prefix={<UserOutlined className="site-form-item-icon" />}
|
||||
placeholder="Username"
|
||||
prefix={<UserOutlined />}
|
||||
placeholder={t("general.labels.username")}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{ required: true, message: "Please input your Password!" }]}
|
||||
>
|
||||
name='password'
|
||||
rules={[
|
||||
{ required: true, message: t("general.validation.required") },
|
||||
]}>
|
||||
<Input
|
||||
prefix={<LockOutlined className="site-form-item-icon" />}
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
prefix={<LockOutlined />}
|
||||
type='password'
|
||||
placeholder={t("general.labels.password")}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Log in
|
||||
{signInError ? (
|
||||
<AlertComponent type='error' message={signInError.message} />
|
||||
) : null}
|
||||
<Button className='login-btn' type='primary' htmlType='submit'>
|
||||
{t("general.actions.login")}
|
||||
</Button>
|
||||
|
||||
{signInError ? <div>{signInError.message}</div> : null}
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SignInComponent);
|
||||
|
||||
28
client/src/components/sign-in-form/sign-in-form.styles.scss
Normal file
28
client/src/components/sign-in-form/sign-in-form.styles.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
.login-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 2rem;
|
||||
form {
|
||||
width: 75vw;
|
||||
max-width: 20rem;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
//Required as it is position inside form.
|
||||
.login-btn {
|
||||
margin: 1.5rem 0rem;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user