Fixed up general layout of manage page + root + styled login page.

This commit is contained in:
Patrick Fic
2020-06-10 22:07:03 -07:00
parent afbec7d79e
commit cec3fec481
14 changed files with 269 additions and 105 deletions

View File

@@ -5081,6 +5081,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>login</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>refresh</name>
<definition_loaded>false</definition_loaded>
@@ -5548,6 +5569,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>password</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>search</name>
<definition_loaded>false</definition_loaded>
@@ -5632,6 +5674,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>username</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>yes</name>
<definition_loaded>false</definition_loaded>

View File

@@ -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);

View File

@@ -0,0 +1,3 @@
.breadcrumb-container {
margin: 1rem 4rem;
}

View File

@@ -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>
);
}

View 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;
}

View File

@@ -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>

View File

@@ -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);

View 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);
}

View File

@@ -1,10 +1,12 @@
import { Elements } from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";
import { BackTop, Layout } from "antd";
import React, { lazy, Suspense, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Route, Switch } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { client } from "../../App/App.container";
import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component";
import ChatAffixContainer from "../../components/chat-affix/chat-affix.container";
import ConflictComponent from "../../components/conflict/conflict.component";
@@ -15,14 +17,9 @@ import FooterComponent from "../../components/footer/footer.component";
import HeaderContainer from "../../components/header/header.container";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
import {
selectInstanceConflict,
selectBodyshop,
} from "../../redux/user/user.selectors";
import "./manage.page.styles.scss";
import { loadStripe } from "@stripe/stripe-js";
import { client } from "../../App/App.container";
import { QUERY_STRIPE_ID } from "../../graphql/bodyshop.queries";
import { selectInstanceConflict } from "../../redux/user/user.selectors";
import "./manage.page.styles.scss";
const ManageRootPage = lazy(() =>
import("../manage-root/manage-root.page.container")
@@ -113,7 +110,7 @@ const ShopCsiPageContainer = lazy(() =>
import("../shop-csi/shop-csi.container.page")
);
const { Header, Content, Footer } = Layout;
const { Content, Footer } = Layout;
const stripePromise = new Promise((resolve, reject) => {
client.query({ query: QUERY_STRIPE_ID }).then((resp) => {
@@ -137,10 +134,11 @@ export function Manage({ match, conflict }) {
}, [t]);
return (
<Layout style={{ minHeight: "100vh" }}>
<Layout className='layout-container'>
<HeaderContainer />
<BreadCrumbs />
<Content className='content-container' style={{ padding: "0em 4em 4em" }}>
<Content className='content-container'>
<FcmNotification />
<ErrorBoundary>
{conflict ? (
@@ -150,7 +148,6 @@ export function Manage({ match, conflict }) {
fallback={
<LoadingSpinner message={t("general.labels.loadingapp")} />
}>
<BreadCrumbs />
<EnterInvoiceModalContainer />
<EmailOverlayContainer />
<TimeTicketModalContainer />
@@ -302,13 +299,15 @@ export function Manage({ match, conflict }) {
</Suspense>
)}
</ErrorBoundary>
<ChatAffixContainer />
<BackTop />
</Content>
<Footer>
<FooterComponent />
</Footer>
<ChatAffixContainer />
<BackTop />
{
// <Footer>
// <FooterComponent />
// </Footer>
}
</Layout>
);
}

View File

@@ -1 +1,10 @@
.content-container { overflow-y : scroll; }
.content-container {
overflow-y: auto;
margin: 0.5rem 1.5rem;
padding: 1.5rem;
background: #fff;
}
.layout-container {
height: 100vh;
}

View File

@@ -3,14 +3,7 @@ import SignIn from "../../components/sign-in-form/sign-in-form.component";
export default () => {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "middle",
padding: "4em",
}}
>
<div>
<SignIn />
</div>
);

View File

@@ -345,6 +345,7 @@
"create": "Create",
"delete": "Delete",
"edit": "Edit",
"login": "Login",
"refresh": "Refresh",
"reset": "Reset to original.",
"save": "Save",
@@ -365,14 +366,16 @@
"loading": "Loading...",
"loadingapp": "Loading Bodyshop.app",
"loadingshop": "Loading shop data...",
"loggingin": "Logging you in...",
"loggingin": "Authorizing...",
"na": "N/A",
"no": "No",
"out": "Out",
"password": "Password",
"search": "Search...",
"selectdate": "Select date...",
"text": "Text",
"unknown": "Unknown",
"username": "Username",
"yes": "Yes"
},
"languages": {

View File

@@ -345,6 +345,7 @@
"create": "",
"delete": "Borrar",
"edit": "Editar",
"login": "",
"refresh": "",
"reset": "Restablecer a original.",
"save": "Salvar",
@@ -369,10 +370,12 @@
"na": "N / A",
"no": "",
"out": "Afuera",
"password": "",
"search": "Buscar...",
"selectdate": "",
"text": "",
"unknown": "Desconocido",
"username": "",
"yes": ""
},
"languages": {

View File

@@ -345,6 +345,7 @@
"create": "",
"delete": "Effacer",
"edit": "modifier",
"login": "",
"refresh": "",
"reset": "Rétablir l'original.",
"save": "sauvegarder",
@@ -369,10 +370,12 @@
"na": "N / A",
"no": "",
"out": "En dehors",
"password": "",
"search": "Chercher...",
"selectdate": "",
"text": "",
"unknown": "Inconnu",
"username": "",
"yes": ""
},
"languages": {