Added tech routing paths and basic structure of landing page + sign in + reducers BOD-95
This commit is contained in:
@@ -13646,6 +13646,179 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>tech</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>clockin</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>clockout</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>home</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>joblookup</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>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>logout</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>productionboard</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>productionlist</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>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
@@ -16483,6 +16656,58 @@
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>tech</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>loggedin</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>notloggedin</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>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>templates</name>
|
||||
<children>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Grid } from "antd";
|
||||
import "antd/dist/antd.css";
|
||||
import React, { lazy, Suspense, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -7,11 +8,11 @@ import { createStructuredSelector } from "reselect";
|
||||
import ErrorBoundary from "../components/error-boundary/error-boundary.component";
|
||||
//Component Imports
|
||||
import LoadingSpinner from "../components/loading-spinner/loading-spinner.component";
|
||||
import TechPageContainer from "../pages/tech/tech.page.container";
|
||||
import { checkUserSession } from "../redux/user/user.actions";
|
||||
import { selectCurrentUser } from "../redux/user/user.selectors";
|
||||
import PrivateRoute from "../utils/private-route";
|
||||
import "./App.styles.scss";
|
||||
import { Grid } from "antd";
|
||||
|
||||
const LandingPage = lazy(() => import("../pages/landing/landing.page"));
|
||||
const ManagePage = lazy(() => import("../pages/manage/manage.page.container"));
|
||||
@@ -35,7 +36,7 @@ export function App({ checkUserSession, currentUser }) {
|
||||
|
||||
const b = Grid.useBreakpoint();
|
||||
console.log("Breakpoints:", b);
|
||||
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (currentUser.authorized === null) {
|
||||
@@ -56,6 +57,11 @@ export function App({ checkUserSession, currentUser }) {
|
||||
path='/manage'
|
||||
component={ManagePage}
|
||||
/>
|
||||
<PrivateRoute
|
||||
isAuthorized={currentUser.authorized}
|
||||
path='/tech'
|
||||
component={TechPageContainer}
|
||||
/>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
</Switch>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Card, Statistic } from "antd";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { Statistic, Card } from "antd";
|
||||
import moment from "moment";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -12,25 +12,21 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
});
|
||||
|
||||
export function ScoreboardDayStats({ bodyshop, date, entries }) {
|
||||
const {
|
||||
lastNumberWorkingDays,
|
||||
dailyPaintTarget,
|
||||
dailyBodyTarget,
|
||||
} = bodyshop.scoreboard_target;
|
||||
const { dailyPaintTarget, dailyBodyTarget } = bodyshop.scoreboard_target;
|
||||
|
||||
let totalHrs = 0;
|
||||
//let totalHrs = 0;
|
||||
const paintHrs = entries.reduce((acc, value) => {
|
||||
totalHrs = +value.painthrs;
|
||||
// totalHrs = +value.painthrs;
|
||||
return acc + value.painthrs;
|
||||
}, 0);
|
||||
|
||||
const bodyHrs = entries.reduce((acc, value) => {
|
||||
totalHrs = +value.bodyhrs;
|
||||
//totalHrs = +value.bodyhrs;
|
||||
return acc + value.bodyhrs;
|
||||
}, 0);
|
||||
|
||||
return (
|
||||
<div className="imex-flex-row__margin">
|
||||
<div className='imex-flex-row__margin'>
|
||||
<Card title={moment(date).format("D - ddd")}>
|
||||
<Statistic
|
||||
valueStyle={{ color: dailyBodyTarget > bodyHrs ? "red" : "green" }}
|
||||
|
||||
@@ -5,7 +5,7 @@ import ScoreboardLastDays from "../scoreboard-last-days/scoreboard-last-days.com
|
||||
import ScoreboardTargetsTable from "../scoreboard-targets-table/scoreboard-targets-table.component";
|
||||
|
||||
export default function ScoreboardDisplayComponent({ scoreboardSubscription }) {
|
||||
const { loading, error, data } = scoreboardSubscription;
|
||||
const { data } = scoreboardSubscription;
|
||||
|
||||
const scoreBoardlist = (data && data.scoreboard) || [];
|
||||
console.log("ScoreboardDisplayComponent -> scoreBoardlist", scoreBoardlist);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { CalendarOutlined } from "@ant-design/icons";
|
||||
import { Col, Row, Statistic } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import * as Util from "./scoreboard-targets-table.util";
|
||||
import { Row, Col, Card, Statistic } from "antd";
|
||||
import { CalendarOutlined } from "@ant-design/icons";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -35,7 +35,7 @@ export function ScoreboardTargetsTable({ bodyshop }) {
|
||||
<Statistic
|
||||
title={t("scoreboard.labels.dailytarget")}
|
||||
value={bodyshop.scoreboard_target.dailyBodyTarget}
|
||||
prefix="B"
|
||||
prefix='B'
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}>
|
||||
@@ -70,7 +70,7 @@ export function ScoreboardTargetsTable({ bodyshop }) {
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={bodyshop.scoreboard_target.dailyPaintTarget}
|
||||
prefix="P"
|
||||
prefix='P'
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import moment from "moment";
|
||||
import momentbd from "moment-business-days";
|
||||
import moment from "moment-business-days";
|
||||
|
||||
moment.updateLocale("ca", {
|
||||
workingWeekdays: [1, 2, 3, 4, 5],
|
||||
|
||||
29
client/src/components/tech-header/tech-header.component.jsx
Normal file
29
client/src/components/tech-header/tech-header.component.jsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Layout, Typography } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const { Header } = Layout;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function TechHeader({ technician }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Header style={{ textAlign: "center" }}>
|
||||
<Typography.Title style={{ color: "#fff" }}>
|
||||
{!!technician
|
||||
? t("tech.labels.loggedin", { name: technician.name })
|
||||
: t("tech.labels.notloggedin")}
|
||||
</Typography.Title>
|
||||
</Header>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechHeader);
|
||||
59
client/src/components/tech-login/tech-login.component.jsx
Normal file
59
client/src/components/tech-login/tech-login.component.jsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { Button, Form, Input } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { loginStart } from "../../redux/tech/tech.actions";
|
||||
import {
|
||||
selectLoginError,
|
||||
selectTechnician,
|
||||
} from "../../redux/tech/tech.selectors";
|
||||
import "./tech-login.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
loginError: selectLoginError,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
loginStart: (user) => dispatch(loginStart(user)),
|
||||
});
|
||||
|
||||
export function TechLogin({ technician, loginError, loginStart }) {
|
||||
const { t } = useTranslation();
|
||||
const handleFinish = (values) => {
|
||||
loginStart(values);
|
||||
};
|
||||
return (
|
||||
<div className='tech-login-container'>
|
||||
<Form onFinish={handleFinish}>
|
||||
<Form.Item
|
||||
label={t("tech.fields.username")}
|
||||
name='date'
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}>
|
||||
<Input size='large' />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("tech.fields.password")}
|
||||
name='date'
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}>
|
||||
<Input.Password size='large' />
|
||||
<Button htmlType='submit' className='login-btn'>
|
||||
{t("general.actions.login")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechLogin);
|
||||
16
client/src/components/tech-login/tech-login.styles.scss
Normal file
16
client/src/components/tech-login/tech-login.styles.scss
Normal file
@@ -0,0 +1,16 @@
|
||||
.tech-login-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 2rem;
|
||||
form {
|
||||
width: 75vw;
|
||||
max-width: 30rem;
|
||||
}
|
||||
.login-btn {
|
||||
margin: 1.5rem 0rem;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
}
|
||||
67
client/src/components/tech-sider/tech-sider.component.jsx
Normal file
67
client/src/components/tech-sider/tech-sider.component.jsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import Icon, { SearchOutlined } from "@ant-design/icons";
|
||||
import { Layout, Menu } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FiLogIn, FiLogOut } from "react-icons/fi";
|
||||
import { MdTimer, MdTimerOff } from "react-icons/md";
|
||||
import { connect } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
const { Sider } = Layout;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function TechSider({ technician }) {
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const { t } = useTranslation();
|
||||
const onCollapse = (collapsed) => {
|
||||
setCollapsed(collapsed);
|
||||
};
|
||||
|
||||
return (
|
||||
<Sider collapsible collapsed={collapsed} onCollapse={onCollapse}>
|
||||
<Menu theme='dark' defaultSelectedKeys={["1"]} mode='inline'>
|
||||
<Menu.Item
|
||||
key='1'
|
||||
disabled={!!technician}
|
||||
icon={<Icon component={FiLogIn} />}>
|
||||
<Link to={`/tech/login`}>{t("menus.tech.login")}</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key='2' disabled={!!!technician} icon={<SearchOutlined />}>
|
||||
<Link to={`/tech/lookup`}>{t("menus.tech.joblookup")}</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key='3'
|
||||
disabled={!!!technician}
|
||||
icon={<Icon component={MdTimer} />}>
|
||||
<Link to={`/tech/clockin`}>{t("menus.tech.clockin")}</Link>
|
||||
</Menu.Item>{" "}
|
||||
<Menu.Item
|
||||
key='4'
|
||||
disabled={!!!technician}
|
||||
icon={<Icon component={MdTimerOff} />}>
|
||||
<Link to={`/tech/clockout`}>{t("menus.tech.clockout")}</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key='5' disabled={!!!technician} icon={<SearchOutlined />}>
|
||||
<Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key='6' disabled={!!!technician} icon={<SearchOutlined />}>
|
||||
<Link to={`/tech/board`}> {t("menus.tech.productionboard")}</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key='7'
|
||||
disabled={!!!technician}
|
||||
icon={<Icon component={FiLogOut} />}>
|
||||
<Link to={`/tech/logout`}>{t("menus.tech.logout")}</Link>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Sider>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechSider);
|
||||
70
client/src/pages/tech/tech.page.component.jsx
Normal file
70
client/src/pages/tech/tech.page.component.jsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import { BackTop, Layout } from "antd";
|
||||
import React, { lazy, Suspense, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
||||
import FcmNotification from "../../components/fcm-notification/fcm-notification.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import TechHeader from "../../components/tech-header/tech-header.component";
|
||||
import TechSider from "../../components/tech-sider/tech-sider.component";
|
||||
import "./tech.page.styles.scss";
|
||||
|
||||
const ManageRootPage = lazy(() =>
|
||||
import("../manage-root/manage-root.page.container")
|
||||
);
|
||||
const JobsPage = lazy(() => import("../jobs/jobs.page"));
|
||||
|
||||
const TimeTicketModalContainer = lazy(() =>
|
||||
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
||||
);
|
||||
const PrintCenterModalContainer = lazy(() =>
|
||||
import("../../components/print-center-modal/print-center-modal.container")
|
||||
);
|
||||
const TechLogin = lazy(() =>
|
||||
import("../../components/tech-login/tech-login.component")
|
||||
);
|
||||
|
||||
const { Content } = Layout;
|
||||
|
||||
export default function TechPage({ match }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.app");
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Layout className='tech-layout-container'>
|
||||
<TechSider />
|
||||
<Layout>
|
||||
<TechHeader />
|
||||
<Content className='tech-content-container'>
|
||||
<FcmNotification />
|
||||
<ErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
<LoadingSpinner message={t("general.labels.loadingapp")} />
|
||||
}>
|
||||
<TimeTicketModalContainer />
|
||||
<PrintCenterModalContainer />
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}`}
|
||||
component={ManageRootPage}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/login`}
|
||||
component={TechLogin}
|
||||
/>
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
|
||||
<BackTop />
|
||||
</Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
30
client/src/pages/tech/tech.page.container.jsx
Normal file
30
client/src/pages/tech/tech.page.container.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { useQuery } from "@apollo/react-hooks";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||
import { setBodyshop } from "../../redux/user/user.actions";
|
||||
import TechPage from "./tech.page.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBodyshop: (bs) => dispatch(setBodyshop(bs)),
|
||||
});
|
||||
|
||||
export function TechPageContainer({ setBodyshop, match }) {
|
||||
const { loading, error, data } = useQuery(QUERY_BODYSHOP, {
|
||||
fetchPolicy: "network-only",
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
if (data) setBodyshop(data.bodyshops[0]);
|
||||
}, [data, setBodyshop]);
|
||||
|
||||
if (loading)
|
||||
return <LoadingSpinner message={t("general.labels.loadingshop")} />;
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
return <TechPage match={match} />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(TechPageContainer);
|
||||
9
client/src/pages/tech/tech.page.styles.scss
Normal file
9
client/src/pages/tech/tech.page.styles.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
.tech-content-container {
|
||||
overflow-y: auto;
|
||||
padding: 1rem;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.tech-layout-container {
|
||||
height: 100vh;
|
||||
}
|
||||
@@ -7,11 +7,12 @@ import messagingReducer from "./messaging/messaging.reducer";
|
||||
import emailReducer from "./email/email.reducer";
|
||||
import modalsReducer from "./modals/modals.reducer";
|
||||
import applicationReducer from "./application/application.reducer";
|
||||
import techReducer from "./tech/tech.reducer";
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage,
|
||||
whitelist: ["messaging"],
|
||||
blacklist: ["user", "email", "modals"],
|
||||
blacklist: ["user", "email", "modals", "tech"],
|
||||
};
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
@@ -20,6 +21,7 @@ const rootReducer = combineReducers({
|
||||
email: emailReducer,
|
||||
modals: modalsReducer,
|
||||
application: applicationReducer,
|
||||
tech: techReducer,
|
||||
});
|
||||
|
||||
export default persistReducer(persistConfig, rootReducer);
|
||||
|
||||
@@ -5,6 +5,8 @@ import { messagingSagas } from "./messaging/messaging.sagas";
|
||||
import { emailSagas } from "./email/email.sagas";
|
||||
import { modalsSagas } from "./modals/modals.sagas";
|
||||
import { applicationSagas } from "./application/application.sagas";
|
||||
import { techSagas } from "./tech/tech.sagas";
|
||||
|
||||
export default function* rootSaga() {
|
||||
yield all([
|
||||
call(userSagas),
|
||||
@@ -12,5 +14,6 @@ export default function* rootSaga() {
|
||||
call(emailSagas),
|
||||
call(modalsSagas),
|
||||
call(applicationSagas),
|
||||
call(techSagas),
|
||||
]);
|
||||
}
|
||||
|
||||
16
client/src/redux/tech/tech.actions.js
Normal file
16
client/src/redux/tech/tech.actions.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import TechActionTypes from "./tech.types";
|
||||
|
||||
export const loginStart = ({ technician, password }) => ({
|
||||
type: TechActionTypes.LOGIN_START,
|
||||
payload: { technician, password },
|
||||
});
|
||||
|
||||
export const loginSuccess = (tech) => ({
|
||||
type: TechActionTypes.LOGIN_SUCCESS,
|
||||
payload: tech,
|
||||
});
|
||||
|
||||
export const loginFailure = (error) => ({
|
||||
type: TechActionTypes.LOGIN_SUCCESS,
|
||||
payload: error,
|
||||
});
|
||||
25
client/src/redux/tech/tech.reducer.js
Normal file
25
client/src/redux/tech/tech.reducer.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import TechActionTypes from "./tech.types";
|
||||
const INITIAL_STATE = {
|
||||
technician: null,
|
||||
loginError: null,
|
||||
};
|
||||
|
||||
const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case TechActionTypes.LOGIN_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
technician: action.payload,
|
||||
};
|
||||
case TechActionTypes.LOGIN_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
loginError: action.payload,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default applicationReducer;
|
||||
19
client/src/redux/tech/tech.sagas.js
Normal file
19
client/src/redux/tech/tech.sagas.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { all, takeLatest, call, put } from "redux-saga/effects";
|
||||
import TechActionTypes from "./tech.types";
|
||||
import { client } from "../../App/App.container";
|
||||
import { loginSuccess, loginFailure } from "./tech.actions";
|
||||
|
||||
export function* onSignInStart() {
|
||||
yield takeLatest(TechActionTypes.LOGIN_START, signInStart);
|
||||
}
|
||||
export function* signInStart({ payload: { technician, password } }) {
|
||||
try {
|
||||
yield put(loginSuccess({ username: "TECHNICIAN" }));
|
||||
} catch (error) {
|
||||
yield put(loginFailure(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* techSagas() {
|
||||
yield all([call(onSignInStart)]);
|
||||
}
|
||||
12
client/src/redux/tech/tech.selectors.js
Normal file
12
client/src/redux/tech/tech.selectors.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { createSelector } from "reselect";
|
||||
|
||||
const selectTechReducer = (state) => state.tech;
|
||||
|
||||
export const selectTechnician = createSelector(
|
||||
[selectTechReducer],
|
||||
(application) => application.technician
|
||||
);
|
||||
export const selectLoginError = createSelector(
|
||||
[selectTechReducer],
|
||||
(application) => application.loginError
|
||||
);
|
||||
6
client/src/redux/tech/tech.types.js
Normal file
6
client/src/redux/tech/tech.types.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const TechActionTypes = {
|
||||
LOGIN_START: "LOGIN_START",
|
||||
LOGIN_SUCCESS: "LOGIN_SUCCESS",
|
||||
LOGIN_FAILURE: "LOGIN_FAILURE",
|
||||
};
|
||||
export default TechActionTypes;
|
||||
@@ -825,6 +825,16 @@
|
||||
"profilesidebar": {
|
||||
"profile": "My Profile",
|
||||
"shops": "My Shops"
|
||||
},
|
||||
"tech": {
|
||||
"clockin": "Clock In",
|
||||
"clockout": "Clock Out",
|
||||
"home": "Home",
|
||||
"joblookup": "Job Lookup",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"productionboard": "Production Board",
|
||||
"productionlist": "Production List"
|
||||
}
|
||||
},
|
||||
"messaging": {
|
||||
@@ -1036,6 +1046,12 @@
|
||||
"removed": "Job removed from scoreboard."
|
||||
}
|
||||
},
|
||||
"tech": {
|
||||
"labels": {
|
||||
"loggedin": "Logged in as {{name}}",
|
||||
"notloggedin": "Not logged in."
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"errors": {
|
||||
"updating": "Error updating template {{error}}."
|
||||
|
||||
@@ -825,6 +825,16 @@
|
||||
"profilesidebar": {
|
||||
"profile": "Mi perfil",
|
||||
"shops": "Mis tiendas"
|
||||
},
|
||||
"tech": {
|
||||
"clockin": "",
|
||||
"clockout": "",
|
||||
"home": "",
|
||||
"joblookup": "",
|
||||
"login": "",
|
||||
"logout": "",
|
||||
"productionboard": "",
|
||||
"productionlist": ""
|
||||
}
|
||||
},
|
||||
"messaging": {
|
||||
@@ -1036,6 +1046,12 @@
|
||||
"removed": ""
|
||||
}
|
||||
},
|
||||
"tech": {
|
||||
"labels": {
|
||||
"loggedin": "",
|
||||
"notloggedin": ""
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"errors": {
|
||||
"updating": ""
|
||||
|
||||
@@ -825,6 +825,16 @@
|
||||
"profilesidebar": {
|
||||
"profile": "Mon profil",
|
||||
"shops": "Mes boutiques"
|
||||
},
|
||||
"tech": {
|
||||
"clockin": "",
|
||||
"clockout": "",
|
||||
"home": "",
|
||||
"joblookup": "",
|
||||
"login": "",
|
||||
"logout": "",
|
||||
"productionboard": "",
|
||||
"productionlist": ""
|
||||
}
|
||||
},
|
||||
"messaging": {
|
||||
@@ -1036,6 +1046,12 @@
|
||||
"removed": ""
|
||||
}
|
||||
},
|
||||
"tech": {
|
||||
"labels": {
|
||||
"loggedin": "",
|
||||
"notloggedin": ""
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"errors": {
|
||||
"updating": ""
|
||||
|
||||
@@ -455,10 +455,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
var name;
|
||||
switch (Number(version[1])) {
|
||||
case 1: {
|
||||
// version one joining all of the names in one string
|
||||
var name = parsedData.DAA.split(",");
|
||||
name = parsedData.DAA.split(",");
|
||||
parsedData.DCS = name[0];
|
||||
parsedData.DAC = name[1];
|
||||
parsedData.DAD = name[2];
|
||||
@@ -475,7 +476,7 @@
|
||||
}
|
||||
case 3: {
|
||||
// version 3 putting middle and first names in the same field
|
||||
var name = parsedData.DCT.split(",");
|
||||
name = parsedData.DCT.split(",");
|
||||
parsedData.DAC = name[0]; // first name
|
||||
parsedData.DAD = name[1]; // middle name
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user