WIP Styling Changes

This commit is contained in:
Patrick Fic
2021-03-26 12:32:17 -07:00
parent 6688121b21
commit 89d4eb28b6
30 changed files with 486 additions and 498 deletions

View File

@@ -16045,6 +16045,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>ins_co_nm_short</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> <concept_node>
<name>ins_ct_fn</name> <name>ins_ct_fn</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -61,6 +61,7 @@
"analyze": "source-map-explorer 'build/static/js/*.js'", "analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "craco start", "start": "craco start",
"build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build", "build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build",
"buildcra": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` react-scripts build",
"build-deploy": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build && s3cmd sync build/* s3://imex-online-production && echo '🚀 Deployed!'", "build-deploy": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build && s3cmd sync build/* s3://imex-online-production && echo '🚀 Deployed!'",
"test": "craco test", "test": "craco test",
"eject": "react-scripts eject", "eject": "react-scripts eject",

View File

@@ -15,7 +15,7 @@ export default function AppContainer() {
return ( return (
<ApolloProvider client={client}> <ApolloProvider client={client}>
<ConfigProvider <ConfigProvider
componentSize="small" //componentSize="small"
input={{ autoComplete: "new-password" }} input={{ autoComplete: "new-password" }}
locale={enLocale} locale={enLocale}
> >

View File

@@ -1,4 +1,3 @@
import React, { lazy, Suspense, useEffect } from "react"; import React, { lazy, Suspense, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -48,48 +47,46 @@ export function App({ checkUserSession, currentUser }) {
} }
return ( return (
<div> <Switch>
<Switch> <Suspense fallback={<LoadingSpinner message="ImEX Online" />}>
<Suspense fallback={<LoadingSpinner message="App.Js Suspense" />}> <ErrorBoundary>
<ErrorBoundary> <Route exact path="/" component={LandingPage} />
<Route exact path="/" component={LandingPage} /> </ErrorBoundary>
</ErrorBoundary> <ErrorBoundary>
<ErrorBoundary> <Route exact path="/signin" component={SignInPage} />
<Route exact path="/signin" component={SignInPage} /> </ErrorBoundary>
</ErrorBoundary> <ErrorBoundary>
<ErrorBoundary> <Route exact path="/resetpassword" component={ResetPassword} />
<Route exact path="/resetpassword" component={ResetPassword} /> </ErrorBoundary>
</ErrorBoundary> <ErrorBoundary>
<ErrorBoundary> <Route exact path="/csi/:surveyId" component={CsiPage} />
<Route exact path="/csi/:surveyId" component={CsiPage} /> </ErrorBoundary>
</ErrorBoundary> <ErrorBoundary>
<ErrorBoundary> <Route exact path="/about" component={AboutPage} />
<Route exact path="/about" component={AboutPage} /> </ErrorBoundary>
</ErrorBoundary> <ErrorBoundary>
<ErrorBoundary> <Route
<Route exact
exact path="/mp/:paymentIs"
path="/mp/:paymentIs" component={MobilePaymentContainer}
component={MobilePaymentContainer} />
/> </ErrorBoundary>
</ErrorBoundary> <ErrorBoundary>
<ErrorBoundary> <PrivateRoute
<PrivateRoute isAuthorized={currentUser.authorized}
isAuthorized={currentUser.authorized} path="/manage"
path="/manage" component={ManagePage}
component={ManagePage} />
/> </ErrorBoundary>
</ErrorBoundary> <ErrorBoundary>
<ErrorBoundary> <PrivateRoute
<PrivateRoute isAuthorized={currentUser.authorized}
isAuthorized={currentUser.authorized} path="/tech"
path="/tech" component={TechPageContainer}
component={TechPageContainer} />
/> </ErrorBoundary>
</ErrorBoundary> </Suspense>
</Suspense> </Switch>
</Switch>
</div>
); );
} }

View File

@@ -77,7 +77,7 @@
.ant-picker-input, .ant-picker-input,
.ant-picker, .ant-picker,
.ant-select { .ant-select {
width: 100%; width: 100% !important;
} }
.production-alert { .production-alert {

View File

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

View File

@@ -1,10 +1,10 @@
import { MessageFilled } from "@ant-design/icons";
import { notification } from "antd"; import { notification } from "antd";
import parsePhoneNumber from "libphonenumber-js"; import parsePhoneNumber from "libphonenumber-js";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { openChatByPhone } from "../../redux/messaging/messaging.actions"; import { openChatByPhone } from "../../redux/messaging/messaging.actions";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)), openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
@@ -12,16 +12,13 @@ const mapDispatchToProps = (dispatch) => ({
export function ChatOpenButton({ phone, jobid, openChatByPhone }) { export function ChatOpenButton({ phone, jobid, openChatByPhone }) {
const { t } = useTranslation(); const { t } = useTranslation();
if (!phone) return <></>;
return ( return (
<MessageFilled <a
style={{ margin: 4 }} href="# "
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
const p = parsePhoneNumber(phone, "CA"); const p = parsePhoneNumber(phone, "CA");
console.log(
"🚀 ~ file: chat-open-button.component.jsx ~ line 21 ~ p",
p
);
if (p && p.isValid()) { if (p && p.isValid()) {
openChatByPhone({ phone_num: p.formatInternational(), jobid: jobid }); openChatByPhone({ phone_num: p.formatInternational(), jobid: jobid });
@@ -29,7 +26,9 @@ export function ChatOpenButton({ phone, jobid, openChatByPhone }) {
notification["error"]({ message: t("messaging.error.invalidphone") }); notification["error"]({ message: t("messaging.error.invalidphone") });
} }
}} }}
/> >
<PhoneNumberFormatter>{phone}</PhoneNumberFormatter>
</a>
); );
} }
export default connect(null, mapDispatchToProps)(ChatOpenButton); export default connect(null, mapDispatchToProps)(ChatOpenButton);

View File

@@ -1,3 +1,4 @@
import { Typography } from "antd";
import React from "react"; import React from "react";
export default function DataLabel({ export default function DataLabel({
@@ -11,14 +12,28 @@ export default function DataLabel({
if (!visible || (hideIfNull && !!!children)) return null; if (!visible || (hideIfNull && !!!children)) return null;
return ( return (
<div {...props}> <div {...props} style={{ display: "flex" }}>
<div <div
style={{ style={{
display: vertical ? "block" : "inline-block", flex: 2,
marginRight: ".2rem", marginRight: ".2rem",
}}>{`${label}: `}</div> }}
<div style={{ display: vertical ? "block" : "inline-block" }}> >
{children} <Typography.Text type="secondary">{`${label}:`}</Typography.Text>
</div>
<div
style={{
flex: 4,
marginLeft: ".3rem",
fontWeight: "bolder",
wordWrap: "break-word",
}}
>
{typeof children === "string" ? (
<Typography.Text>{children}</Typography.Text>
) : (
children
)}
</div> </div>
</div> </div>
); );

View File

@@ -13,10 +13,7 @@ export default function FormsFieldChanged({ form }) {
const loc = useLocation(); const loc = useLocation();
return ( return (
<Form.Item <Form.Item shouldUpdate style={{ margin: 0, padding: 0 }}>
shouldUpdate
//style={{ margin: 0, padding: 0 }}
>
{() => { {() => {
if (form.isFieldsTouched()) if (form.isFieldsTouched())
return ( return (

View File

@@ -14,7 +14,7 @@ import Icon, {
UnorderedListOutlined, UnorderedListOutlined,
UserOutlined, UserOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Avatar, Menu } from "antd"; import { Menu } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { BsKanban } from "react-icons/bs"; import { BsKanban } from "react-icons/bs";
@@ -67,10 +67,10 @@ function Header({
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<div style={{ display: "flex", alignItems: "center" }}> <div style={{ display: "flex", alignContent: "center" }}>
<Menu <Menu
mode="horizontal" mode="horizontal"
theme="dark" theme="light"
style={{ flex: 5 }} style={{ flex: 5 }}
selectedKeys={[selectedHeader]} selectedKeys={[selectedHeader]}
onClick={handleMenuClick} onClick={handleMenuClick}
@@ -297,38 +297,15 @@ function Header({
<Link to="/manage/shop/csi">{t("menus.header.shop_csi")}</Link> <Link to="/manage/shop/csi">{t("menus.header.shop_csi")}</Link>
</Menu.Item> </Menu.Item>
</Menu.SubMenu> </Menu.SubMenu>
</Menu>
<GlobalSearch /> <Menu.Item>
<Menu <GlobalSearch />
mode="horizontal" </Menu.Item>
theme="dark"
selectedKeys={[selectedHeader]}
onClick={handleMenuClick}
>
<Menu.SubMenu <Menu.SubMenu
title={ title={
<div> currentUser.displayName ||
{currentUser.photoURL ? ( currentUser.email ||
<Avatar t("general.labels.unknown")
src={currentUser.photoURL}
style={{
margin: "10px",
}}
/>
) : (
<Avatar
style={{
backgroundColor: "#87d068",
margin: "10px",
}}
icon={<UserOutlined />}
/>
)}
{currentUser.displayName ||
currentUser.email ||
t("general.labels.unknown")}
</div>
} }
> >
<Menu.Item danger onClick={() => signOutStart()}> <Menu.Item danger onClick={() => signOutStart()}>

View File

@@ -8,17 +8,8 @@ export default function JiraSupportComponent() {
const useScript = () => { const useScript = () => {
useEffect(() => { useEffect(() => {
console.log("Creating JIRA widget.");
const script = document.createElement("script"); const script = document.createElement("script");
script.src = "https://jsd-widget.atlassian.com/assets/embed.js"; script.src = "https://jsd-widget.atlassian.com/assets/embed.js";
// script["data-jsd-embedded"] = true;
// script["data-key"] = "d69bb65c-1dd3-483f-b109-66a970d03f44";
// script["data-base-url"] = "https://jsd-widget.atlassian.com";
// script.attributes.setNamedItem("data-jsd-embedded");
// script.attributes.setNamedItem("data-key");
// script.attributes.setNamedItem("data-base-url");
script.setAttribute("data-jsd-embedded", true); script.setAttribute("data-jsd-embedded", true);
script.setAttribute("data-key", "d69bb65c-1dd3-483f-b109-66a970d03f44"); script.setAttribute("data-key", "d69bb65c-1dd3-483f-b109-66a970d03f44");
script.setAttribute("data-base-url", "https://jsd-widget.atlassian.com"); script.setAttribute("data-base-url", "https://jsd-widget.atlassian.com");

View File

@@ -136,7 +136,7 @@ export function JobCostingModalComponent({ bodyshop, job }) {
let gppercentFormatted; let gppercentFormatted;
if (isNaN(gppercent)) gppercentFormatted = "0%"; if (isNaN(gppercent)) gppercentFormatted = "0%";
else if (!isFinite(gppercent)) gppercentFormatted = "-∞"; else if (!isFinite(gppercent)) gppercentFormatted = "- ∞";
else { else {
gppercentFormatted = `${gppercent}%`; gppercentFormatted = `${gppercent}%`;
} }

View File

@@ -1,6 +1,6 @@
import { PrinterFilled } from "@ant-design/icons"; import { PrinterFilled } from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Button, Col, Drawer, Grid, PageHeader, Row, Space, Tag } from "antd"; import { Button, Card, Drawer, Grid, PageHeader, Space, Tag } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -25,15 +25,6 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(setModalContext({ context: context, modal: "printCenter" })), dispatch(setModalContext({ context: context, modal: "printCenter" })),
}); });
const colBreakPoints = {
xs: {
span: 24,
},
sm: {
span: 12,
},
};
export function JobDetailCards({ setPrintCenterContext }) { export function JobDetailCards({ setPrintCenterContext }) {
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1]) .filter((screen) => !!screen[1])
@@ -69,20 +60,23 @@ export function JobDetailCards({ setPrintCenterContext }) {
}), }),
}); });
}; };
const gridStyle = {
width: "25%",
textAlign: "center",
};
return ( return (
<Drawer <Drawer
visible={!!selected} visible={!!selected}
destroyOnClose destroyOnClose
width={drawerPercentage} height={drawerPercentage}
placement="right" placement="top"
onClose={handleDrawerClose} onClose={handleDrawerClose}
> >
{loading ? <LoadingSpinner /> : null} {loading ? <LoadingSpinner /> : null}
{error ? <AlertComponent message={error.message} type="error" /> : null} {error ? <AlertComponent message={error.message} type="error" /> : null}
{data ? ( {data ? (
<PageHeader <PageHeader
ghost={true} // ghost={true}
tags={[ tags={[
<OwnerTagPopoverComponent key="owner" job={data.jobs_by_pk} />, <OwnerTagPopoverComponent key="owner" job={data.jobs_by_pk} />,
<VehicleTagPopoverComponent key="vehicle" job={data.jobs_by_pk} />, <VehicleTagPopoverComponent key="vehicle" job={data.jobs_by_pk} />,
@@ -99,79 +93,80 @@ export function JobDetailCards({ setPrintCenterContext }) {
{t("jobs.labels.inproduction")} {t("jobs.labels.inproduction")}
</Tag>, </Tag>,
]} ]}
title={
<Link to={`/manage/jobs/${data.jobs_by_pk.id}`}>
{data.jobs_by_pk.ro_number || t("general.labels.na")}
</Link>
}
subTitle={data.jobs_by_pk.status} subTitle={data.jobs_by_pk.status}
extra={
<Space>
<Button
onClick={() => {
setPrintCenterContext({
actions: { refetch: refetch },
context: {
id: data.jobs_by_pk.id,
job: data.jobs_by_pk,
type: "job",
},
});
}}
>
<PrinterFilled />
{t("jobs.actions.printCenter")}
</Button>
<Link to={`/manage/jobs/${data.jobs_by_pk.id}?tab=repairdata`}>
<Button>{t("parts.actions.order")}</Button>
</Link>
</Space>
}
> >
<Row gutter={[16, 16]}> <Card
<Col {...colBreakPoints}> title={
<Link to={`/manage/jobs/${data.jobs_by_pk.id}`}>
{data.jobs_by_pk.ro_number || t("general.labels.na")}
</Link>
}
extra={
<Space>
<Button
onClick={() => {
setPrintCenterContext({
actions: { refetch: refetch },
context: {
id: data.jobs_by_pk.id,
job: data.jobs_by_pk,
type: "job",
},
});
}}
>
<PrinterFilled />
{t("jobs.actions.printCenter")}
</Button>
<Link to={`/manage/jobs/${data.jobs_by_pk.id}?tab=repairdata`}>
<Button>{t("parts.actions.order")}</Button>
</Link>
</Space>
}
>
<Card.Grid style={gridStyle}>
<JobDetailCardsInsuranceComponent <JobDetailCardsInsuranceComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
</Col> </Card.Grid>
<Col {...colBreakPoints}> <Card.Grid style={gridStyle}>
<JobDetailCardsTotalsComponent <JobDetailCardsTotalsComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
</Col> </Card.Grid>
<Col {...colBreakPoints}> <Card.Grid style={gridStyle}>
<JobDetailCardsDatesComponent <JobDetailCardsDatesComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
</Col> </Card.Grid>
<Col {...colBreakPoints}> <Card.Grid style={gridStyle}>
<JobDetailCardsPartsComponent <JobDetailCardsPartsComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
</Col> </Card.Grid>
<Col {...colBreakPoints}> <Card.Grid style={gridStyle}>
<JobDetailCardsNotesComponent <JobDetailCardsNotesComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
</Col> </Card.Grid>
<Col {...colBreakPoints}> <Card.Grid style={gridStyle}>
<JobDetailCardsDocumentsComponent <JobDetailCardsDocumentsComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
</Col> </Card.Grid>
<Col {...colBreakPoints}> <Card.Grid style={gridStyle}>
<JobDetailCardsDamageComponent <JobDetailCardsDamageComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
</Col> </Card.Grid>
</Row> </Card>
</PageHeader> </PageHeader>
) : null} ) : null}
</Drawer> </Drawer>

View File

@@ -246,10 +246,6 @@ export function JobsAvailableContainer({ bodyshop, currentUser }) {
const newTotals = await Axios.post("/job/totalsssu", { const newTotals = await Axios.post("/job/totalsssu", {
id: selectedJob, id: selectedJob,
}); });
console.log(
"🚀 ~ file: jobs-available-table.container.jsx ~ line 247 ~ newTotals",
newTotals
);
if (newTotals.status !== 200) { if (newTotals.status !== 200) {
notification["error"]({ notification["error"]({

View File

@@ -1,7 +1,7 @@
import { DownCircleFilled } from "@ant-design/icons"; import { DownCircleFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { Button, Dropdown, Menu, notification } from "antd"; import { Button, Dropdown, Menu, notification } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useMutation } from "@apollo/client";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -90,14 +90,15 @@ export function JobsChangeStatus({ job, bodyshop, jobRO }) {
return ( return (
<Dropdown <Dropdown
className="imex-flex-row__margin"
overlay={statusmenu} overlay={statusmenu}
trigger={["click"]} trigger={["click"]}
key="changestatus" key="changestatus"
disabled={jobRO || !job.converted} disabled={jobRO || !job.converted}
> >
<Button> <Button shape="round">
{t("jobs.actions.changestatus")} <DownCircleFilled /> <span>{job.status}</span>
<DownCircleFilled />
</Button> </Button>
</Dropdown> </Dropdown>
); );

View File

@@ -110,13 +110,14 @@ export function JobsConvertButton({ bodyshop, job, refetch, jobRO }) {
</div> </div>
); );
if (job.converted) return <></>;
return ( return (
<Popover visible={visible} content={popMenu}> <Popover visible={visible} content={popMenu}>
<Button <Button
key="convert" key="convert"
className="imex-flex-row__margin"
type="danger" type="danger"
style={{ display: job.converted ? "none" : "" }} // style={{ display: job.converted ? "none" : "" }}
disabled={job.converted || jobRO} disabled={job.converted || jobRO}
onClick={() => setVisible(true)} onClick={() => setVisible(true)}
> >

View File

@@ -390,14 +390,11 @@ export function JobsDetailHeaderActions({
</Menu> </Menu>
); );
return ( return (
<Dropdown <Dropdown overlay={statusmenu} trigger={["click"]} key="changestatus">
className="imex-flex-row__margin"
overlay={statusmenu}
trigger={["click"]}
key="changestatus"
>
<Button> <Button>
{t("general.labels.actions")} <DownCircleFilled /> <span>{t("general.labels.actions")}</span>
<DownCircleFilled />
</Button> </Button>
</Dropdown> </Dropdown>
); );

View File

@@ -1,21 +1,15 @@
import { PrinterFilled } from "@ant-design/icons"; import { Card, Col, Row, Tag } from "antd";
import { Button, Divider, PageHeader, Tag } from "antd";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import JobSyncButton from "../job-sync-button/job-sync-button.component"; import DataLabel from "../data-label/data-label.component";
import JobsChangeStatus from "../jobs-change-status/jobs-change-status.component";
import JobsConvertButton from "../jobs-convert-button/jobs-convert-button.component";
import JobsDetailHeaderActions from "../jobs-detail-header-actions/jobs-detail-header-actions.component";
import OwnerTagPopoverComponent from "../owner-tag-popover/owner-tag-popover.component";
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
import VehicleTagPopoverComponent from "../vehicle-tag-popover/vehicle-tag-popover.component";
import "./jobs-detail-header.styles.scss"; import "./jobs-detail-header.styles.scss";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -45,80 +39,127 @@ export function JobsDetailHeader({
); );
}, [job.status, bodyshop.md_ro_statuses.post_production_statuses]); }, [job.status, bodyshop.md_ro_statuses.post_production_statuses]);
const menuExtra = ( const gridStyle = {
<div className="imex-flex-row"> flex: 1,
<JobsChangeStatus job={job} /> //textAlign: "center",
<JobSyncButton job={job} /> };
<Button
className="imex-flex-row__margin"
onClick={() => {
setPrintCenterContext({
actions: { refetch: refetch },
context: {
id: job.id,
job: job,
type: "job",
},
});
}}
key="printing"
>
<PrinterFilled />
{t("jobs.actions.printCenter")}
</Button>
<JobsConvertButton job={job} refetch={refetch} />
<JobsDetailHeaderActions key="actions" job={job} refetch={refetch} />
<Button
type="primary"
loading={loading}
disabled={jobRO}
className="imex-flex-row__margin"
onClick={() => form.submit()}
>
{t("general.actions.save")}
</Button>
</div>
);
return ( return (
<PageHeader <Row gutter={16} style={{ alignItems: "stretch" }}>
title={job.ro_number || t("general.labels.na")} <Col span={8}>
subTitle={job.status} <Card title="Job Status" style={{ height: "100%" }}>
tags={[ <div>
<OwnerTagPopoverComponent key="owner" job={job} />, <DataLabel label={t("jobs.fields.status")}>
<VehicleTagPopoverComponent key="vehicle" job={job} />, {job.status}
<Tag {job.inproduction && (
color="#f50" <span style={{ marginLeft: ".5rem" }}>
key="production" <Tag color="#f50" key="production">
style={{ display: job.inproduction ? "" : "none" }} {t("jobs.labels.inproduction")}
> </Tag>
{t("jobs.labels.inproduction")} </span>
</Tag>, )}
<Tag title={t("jobs.fields.repairtotal")} key="total" color="green"> </DataLabel>
<CurrencyFormatter>{job.clm_total}</CurrencyFormatter> <DataLabel label={t("jobs.fields.ins_co_nm_short")}>
<span style={{ margin: "0rem .5rem" }}>/</span> {job.ins_co_nm}
<CurrencyFormatter>{job.owner_owing}</CurrencyFormatter> </DataLabel>
</Tag>, <DataLabel label={t("jobs.fields.clm_no")}>{job.clm_no}</DataLabel>
]} <DataLabel label={t("jobs.fields.repairtotal")}>
extra={menuExtra} <CurrencyFormatter>{job.clm_total}</CurrencyFormatter>
> <span style={{ margin: "0rem .5rem" }}>/</span>
<div style={{ display: "flex", justifyContent: "flex-end" }}> <CurrencyFormatter>{job.owner_owing}</CurrencyFormatter>
{(job.inproduction || jobInPostProduction) && ( </DataLabel>
<> </div>
<div style={{ display: "flex", flex: 1 }}> </Card>
<div style={{ marginRight: "2rem" }}> </Col>
{t("jobs.fields.production_vars.note")} <Col span={8}>
</div> <Link to={`/manage/owners/${job.owner.id}`}>
<ProductionListColumnProductionNote record={job} /> <Card
className="ant-card-grid-hoverable"
style={{ height: "100%" }}
title={`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
job.ownr_co_nm || ""
}`}
>
<div>
<DataLabel key="2" label={t("jobs.fields.ownr_ph1")}>
<ChatOpenButton>{job.ownr_ph1 || ""}</ChatOpenButton>
</DataLabel>
<DataLabel key="3" label={t("owners.fields.address")}>
{`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${
job.ownr_city || ""
} ${job.ownr_st || ""} ${job.ownr_zip || ""}`}
</DataLabel>
<DataLabel key="4" label={t("owners.fields.ownr_ea")}>
{job.ownr_ea || ""}
</DataLabel>
</div> </div>
<Divider type="vertical" /> </Card>
</> </Link>
)} </Col>
<Col span={8}>
<JobEmployeeAssignments job={job} /> <Link to={`/manage/vehicles/${job.vehicle.id}`}>
</div> <Card
</PageHeader> className="ant-card-grid-hoverable"
style={{ height: "100%" }}
title={`${job.v_model_yr || ""} ${job.v_color || ""}
${job.v_make_desc || ""}
${job.v_model_desc || ""}`}
>
<div>
<DataLabel key="2" label={t("vehicles.fields.plate_no")}>
{`${job.plate_no || t("general.labels.na")} (${`${
job.plate_st || t("general.labels.na")
}`})`}
</DataLabel>
<DataLabel key="4" label={t("vehicles.fields.v_vin")}>
{`${job.v_vin || t("general.labels.na")}`}
</DataLabel>
</div>
</Card>
</Link>
</Col>
</Row>
); );
// return (
// <PageHeader
// title={job.ro_number || t("general.labels.na")}
// subTitle={job.status}
// tags={[
// <OwnerTagPopoverComponent key="owner" job={job} />,
// <VehicleTagPopoverComponent key="vehicle" job={job} />,
// <Tag
// color="#f50"
// key="production"
// style={{ display: job.inproduction ? "" : "none" }}
// >
// {t("jobs.labels.inproduction")}
// </Tag>,
// <Tag title={t("jobs.fields.repairtotal")} key="total" color="green">
// <CurrencyFormatter>{job.clm_total}</CurrencyFormatter>
// <span style={{ margin: "0rem .5rem" }}>/</span>
// <CurrencyFormatter>{job.owner_owing}</CurrencyFormatter>
// </Tag>,
// ]}
// extra={menuExtra}
// >
// <div style={{ display: "flex", justifyContent: "flex-end" }}>
// {(job.inproduction || jobInPostProduction) && (
// <>
// <div style={{ display: "flex", flex: 1 }}>
// <div style={{ marginRight: "2rem" }}>
// {t("jobs.fields.production_vars.note")}
// </div>
// <ProductionListColumnProductionNote record={job} />
// </div>
// <Divider type="vertical" />
// </>
// )}
// <JobEmployeeAssignments job={job} />
// </div>
// </PageHeader>
// );
} }
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailHeader); export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailHeader);

View File

@@ -1,6 +1,6 @@
import { SyncOutlined } from "@ant-design/icons"; import { SyncOutlined } from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Button, Input, Table } from "antd"; import { Button, Card, Input, Space, Table } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -11,7 +11,6 @@ import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import { onlyUnique } from "../../utils/arrayHelper"; import { onlyUnique } from "../../utils/arrayHelper";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import StartChatButton from "../chat-open-button/chat-open-button.component"; import StartChatButton from "../chat-open-button/chat-open-button.component";
@@ -130,14 +129,10 @@ export function JobsList({ bodyshop }) {
dataIndex: "ownr_ph1", dataIndex: "ownr_ph1",
key: "ownr_ph1", key: "ownr_ph1",
ellipsis: true, ellipsis: true,
render: (text, record) => { responsive: ["md"],
return record.ownr_ph1 ? ( render: (text, record) => (
<span> <StartChatButton phone={record.ownr_ph1} jobid={record.id} />
<PhoneFormatter>{record.ownr_ph1}</PhoneFormatter> ),
<StartChatButton phone={record.ownr_ph1} jobid={record.id} />
</span>
) : null;
},
}, },
{ {
@@ -160,9 +155,6 @@ export function JobsList({ bodyshop }) {
})) || })) ||
[], [],
onFilter: (value, record) => value.includes(record.status), onFilter: (value, record) => value.includes(record.status),
render: (text, record) => {
return record.status || t("general.labels.na");
},
}, },
{ {
@@ -188,28 +180,20 @@ export function JobsList({ bodyshop }) {
title: t("vehicles.fields.plate_no"), title: t("vehicles.fields.plate_no"),
dataIndex: "plate_no", dataIndex: "plate_no",
key: "plate_no", key: "plate_no",
responsive: ["md"],
sorter: (a, b) => alphaSort(a.plate_no, b.plate_no), sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order, state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
render: (text, record) => {
return record.plate_no ? record.plate_no : "";
},
}, },
{ {
title: t("jobs.fields.clm_no"), title: t("jobs.fields.clm_no"),
dataIndex: "clm_no", dataIndex: "clm_no",
key: "clm_no", key: "clm_no",
ellipsis: true, ellipsis: true,
responsive: ["md"],
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no), sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order, state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
render: (text, record) => {
return record.clm_no ? (
<span>{record.clm_no}</span>
) : (
t("general.labels.unknown")
);
},
}, },
{ {
title: t("jobs.fields.ins_co_nm"), title: t("jobs.fields.ins_co_nm"),
@@ -224,68 +208,65 @@ export function JobsList({ bodyshop }) {
sorter: (a, b) => a.clm_total - b.clm_total, sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder: sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
render: (text, record) => {
return record.clm_total ? (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
) : (
t("general.labels.unknown")
);
},
},
{
title: t("jobs.fields.owner_owing"),
dataIndex: "owner_owing",
key: "owner_owing",
render: (text, record) => ( render: (text, record) => (
<CurrencyFormatter>{record.owner_owing}</CurrencyFormatter> <CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
), ),
}, },
// {
// title: t("jobs.fields.owner_owing"),
// dataIndex: "owner_owing",
// key: "owner_owing",
// responsive: ["md"],
// render: (text, record) => (
// <CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
// ),
// },
]; ];
return ( return (
<Table <Card
loading={loading} title={t("titles.bc.jobs-active")}
size="small" extra={
pagination={false} <Space wrap>
columns={columns} <Button onClick={() => refetch()}>
rowKey="id" <SyncOutlined />
dataSource={jobs} </Button>
style={{ height: "100%" }} <Input.Search
scroll={{ x: true }} placeholder={t("general.labels.search")}
title={() => { onChange={(e) => {
return ( setSearchText(e.target.value);
<div className="imex-table-header"> }}
<Button onClick={() => refetch()}> value={searchText}
<SyncOutlined /> enterButton
</Button> />
<Input.Search </Space>
className="imex-table-header__search" }
placeholder={t("general.labels.search")} >
onChange={(e) => { <Table
setSearchText(e.target.value); loading={loading}
}} size="small"
value={searchText} pagination={false}
enterButton columns={columns}
/> rowKey="id"
</div> dataSource={jobs}
); // scroll={{ x: true }}
}} rowSelection={{
rowSelection={{ onSelect: (record) => {
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selected],
type: "radio",
}}
onChange={handleTableChange}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record); handleOnRowClick(record);
}, },
}; selectedRowKeys: [selected],
}} type: "radio",
/> }}
onChange={handleTableChange}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
},
};
}}
/>
</Card>
); );
} }

View File

@@ -35,7 +35,8 @@ function RbacWrapper({
authLevel || authLevel ||
(!bodyshop.md_rbac && rbacDefaults[action] <= authLevel) (!bodyshop.md_rbac && rbacDefaults[action] <= authLevel)
) )
return <div>{React.cloneElement(children, restProps)}</div>; return children;
//return <div>{React.cloneElement(children, restProps)}</div>;
return ( return (
noauth || ( noauth || (

View File

@@ -42,7 +42,7 @@ ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<BrowserRouter> <BrowserRouter>
<PersistGate <PersistGate
loading={<LoadingSpinner message="PersistGate Loading." />} loading={<LoadingSpinner message="Restoring your settings..." />}
persistor={persistor} persistor={persistor}
> >
<AppContainer /> <AppContainer />
@@ -54,7 +54,6 @@ ReactDOM.render(
const onServiceWorkerUpdate = (registration) => { const onServiceWorkerUpdate = (registration) => {
console.log("onServiceWorkerUpdate", registration); console.log("onServiceWorkerUpdate", registration);
const key = `open${Date.now()}`; const key = `open${Date.now()}`;
const btn = ( const btn = (
<Button <Button

View File

@@ -3,140 +3,134 @@ import Icon, {
CalendarFilled, CalendarFilled,
DollarCircleOutlined, DollarCircleOutlined,
FileImageFilled, FileImageFilled,
PrinterFilled,
ToolFilled, ToolFilled,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Form, notification, Tabs } from "antd"; import { Button, Form, notification, PageHeader, Space, Tabs } from "antd";
import Axios from "axios"; import Axios from "axios";
import Dinero from "dinero.js";
import moment from "moment"; import moment from "moment";
import queryString from "query-string"; import queryString from "query-string";
import React, { lazy, Suspense, useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FaHardHat, FaRegStickyNote, FaShieldAlt } from "react-icons/fa"; import { FaHardHat, FaRegStickyNote, FaShieldAlt } from "react-icons/fa";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component"; import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
//import JobsDetailChecklists from "../../components/jobs-detail-checklists/jobs-detail-checklists.component"; import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container";
import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container";
import JobSyncButton from "../../components/job-sync-button/job-sync-button.component";
import JobsChangeStatus from "../../components/jobs-change-status/jobs-change-status.component";
import JobsConvertButton from "../../components/jobs-convert-button/jobs-convert-button.component";
import JobsDetailDatesComponent from "../../components/jobs-detail-dates/jobs-detail-dates.component";
import JobsDetailGeneral from "../../components/jobs-detail-general/jobs-detail-general.component";
import JobsDetailHeaderActions from "../../components/jobs-detail-header-actions/jobs-detail-header-actions.component";
import JobsDetailHeader from "../../components/jobs-detail-header/jobs-detail-header.component";
import JobsDetailLaborContainer from "../../components/jobs-detail-labor/jobs-detail-labor.container";
import JobsDetailPliContainer from "../../components/jobs-detail-pli/jobs-detail-pli.container";
import JobsDetailRates from "../../components/jobs-detail-rates/jobs-detail-rates.component";
import JobsDetailTotals from "../../components/jobs-detail-totals/jobs-detail-totals.component";
import JobsDocumentsGalleryContainer from "../../components/jobs-documents-gallery/jobs-documents-gallery.container";
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container";
import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
const JobsLinesContainer = lazy(() =>
import("../../components/job-detail-lines/job-lines.container")
);
const JobsDetailDatesComponent = lazy(() =>
import("../../components/jobs-detail-dates/jobs-detail-dates.component")
);
const JobsDetailTotals = lazy(() =>
import("../../components/jobs-detail-totals/jobs-detail-totals.component")
);
const JobsDetailRates = lazy(() =>
import("../../components/jobs-detail-rates/jobs-detail-rates.component")
);
const JobsDetailHeader = lazy(() =>
import("../../components/jobs-detail-header/jobs-detail-header.component")
);
const JobsDetailGeneral = lazy(() =>
import("../../components/jobs-detail-general/jobs-detail-general.component")
);
const JobsDocumentsGalleryContainer = lazy(() =>
import(
"../../components/jobs-documents-gallery/jobs-documents-gallery.container"
)
);
const JobNotesContainer = lazy(() =>
import("../../components/jobs-notes/jobs-notes.container")
);
const ScheduleJobModalContainer = lazy(() =>
import("../../components/schedule-job-modal/schedule-job-modal.container")
);
const JobLineUpsertModalContainer = lazy(() =>
import(
"../../components/job-lines-upsert-modal/job-lines-upsert-modal.container"
)
);
const JobsDetailPliContainer = lazy(() =>
import("../../components/jobs-detail-pli/jobs-detail-pli.container")
);
// const JobsDetailAuditContainer = lazy(() =>
// import("../../components/audit-trail-list/audit-trail-list.container")
// );
const JobsDetailLaborContainer = lazy(() =>
import("../../components/jobs-detail-labor/jobs-detail-labor.container")
);
const JobReconciliationModal = lazy(() =>
import(
"../../components/job-reconciliation-modal/job-reconciliation.modal.container"
)
);
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
jobRO: selectJobReadOnly, jobRO: selectJobReadOnly,
}); });
const mapDispatchToProps = (dispatch) => ({
setPrintCenterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "printCenter" })),
});
export function JobsDetailPage({ export function JobsDetailPage({
setPrintCenterContext,
jobRO,
job, job,
mutationUpdateJob, mutationUpdateJob,
handleSubmit, handleSubmit,
refetch, refetch,
jobRO,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
const history = useHistory(); const history = useHistory();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const search = queryString.parse(useLocation().search); const search = queryString.parse(useLocation().search);
const formItemLayout = { const formItemLayout = {
layout: "vertical", layout: "vertical",
// size: "small",
}; };
useEffect(() => { useEffect(() => {
form.resetFields(); //form.setFieldsValue(transormJobToForm(job));
form.resetFields(); form.resetFields();
}, [form, job]); }, [form, job]);
const handleFinish = async (values) => { const handleFinish = async (values) => {
setLoading(true); setLoading(true);
//const newTotals = CalculateJob({ ...job, ...values }, bodyshop.shoprates);
const newTotals = (
await Axios.post("/job/totals", {
job: { ...job, ...values },
})
).data;
const result = await mutationUpdateJob({ const result = await mutationUpdateJob({
variables: { variables: {
jobId: job.id, jobId: job.id,
job: { job: values,
...values,
clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat(
"0.00"
),
job_totals: newTotals, //JSON.stringify(newTotals),
},
}, },
}); });
const newTotals = await Axios.post("/job/totalsssu", {
id: job.id,
});
if (!!!result.errors) { if (newTotals.status !== 200 || result.errors) {
notification["error"]({
message: t("jobs.errors.totalscalc"),
});
} else {
notification["success"]({ notification["success"]({
message: t("jobs.successes.savetitle"), message: t("jobs.successes.savetitle"),
}); });
await refetch(); await refetch();
form.resetFields(); form.setFieldsValue(transormJobToForm(job));
form.resetFields(); form.resetFields();
} }
setLoading(false); setLoading(false);
}; };
const menuExtra = (
<Space wrap>
<JobsChangeStatus job={job} />
<JobSyncButton job={job} />
<Button
onClick={() => {
setPrintCenterContext({
actions: { refetch: refetch },
context: {
id: job.id,
job: job,
type: "job",
},
});
}}
key="printing"
>
<PrinterFilled />
{t("jobs.actions.printCenter")}
</Button>
<JobsConvertButton job={job} refetch={refetch} />
<JobsDetailHeaderActions key="actions" job={job} refetch={refetch} />
<Button
type="primary"
loading={loading}
disabled={jobRO}
onClick={() => form.submit()}
>
{t("general.actions.save")}
</Button>
</Space>
);
return ( return (
<Suspense <div>
fallback={<LoadingSpinner message={t("general.labels.loadingapp")} />}
>
<ScheduleJobModalContainer /> <ScheduleJobModalContainer />
<JobReconciliationModal /> <JobReconciliationModal />
<JobLineUpsertModalContainer /> <JobLineUpsertModalContainer />
@@ -146,23 +140,16 @@ export function JobsDetailPage({
onFinish={handleFinish} onFinish={handleFinish}
{...formItemLayout} {...formItemLayout}
autoComplete={"off"} autoComplete={"off"}
initialValues={{ initialValues={transormJobToForm(job)}
...job,
loss_date: job.loss_date ? moment(job.loss_date) : null,
date_estimated: job.date_estimated
? moment(job.date_estimated)
: null,
}}
> >
<FormFieldsChanged form={form} /> <PageHeader
onBack={() => window.history.back()}
<JobsDetailHeader title={job.ro_number || t("general.labels.na")}
form={form} extra={menuExtra}
job={job}
refetch={refetch}
handleSubmit={handleSubmit}
loading={loading}
/> />
<JobsDetailHeader job={job} />
<FormFieldsChanged form={form} />
<Tabs <Tabs
defaultActiveKey={search.tab} defaultActiveKey={search.tab}
onChange={(key) => history.push({ search: `?tab=${key}` })} onChange={(key) => history.push({ search: `?tab=${key}` })}
@@ -271,33 +258,17 @@ export function JobsDetailPage({
> >
<JobNotesContainer jobId={job.id} /> <JobNotesContainer jobId={job.id} />
</Tabs.TabPane> </Tabs.TabPane>
{
// <Tabs.TabPane
// tab={
// <span>
// <Icon component={FaHistory} />
// {t("jobs.labels.audit")}
// </span>
// }
// key="audit"
// >
// <JobsDetailAuditContainer recordId={job.id} />
// </Tabs.TabPane>
// <Tabs.TabPane
// tab={
// <span>
// <CheckSquareFilled />
// {t("jobs.labels.checklists")}
// </span>
// }
// key="checklists"
// >
// <JobsDetailChecklists job={job} />
// </Tabs.TabPane>
}
</Tabs> </Tabs>
</Form> </Form>
</Suspense> </div>
); );
} }
export default connect(mapStateToProps, null)(JobsDetailPage); export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailPage);
const transormJobToForm = (job) => {
return {
...job,
loss_date: job.loss_date ? moment(job.loss_date) : null,
date_estimated: job.date_estimated ? moment(job.date_estimated) : null,
};
};

View File

@@ -3,11 +3,11 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component"; import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component";
import JobsList from "../../components/jobs-list/jobs-list.component"; import JobsList from "../../components/jobs-list/jobs-list.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { import {
setBreadcrumbs, setBreadcrumbs,
setSelectedHeader, setSelectedHeader,
} from "../../redux/application/application.actions"; } from "../../redux/application/application.actions";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -27,10 +27,8 @@ export function JobsPage({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<RbacWrapper action="jobs:list-active"> <RbacWrapper action="jobs:list-active">
<div className="jobs-list-container"> <JobsList />
<JobsList /> <JobDetailCards />
<JobDetailCards />
</div>
</RbacWrapper> </RbacWrapper>
); );
} }

View File

@@ -12,15 +12,14 @@ import ChatAffixContainer from "../../components/chat-affix/chat-affix.container
import ConflictComponent from "../../components/conflict/conflict.component"; import ConflictComponent from "../../components/conflict/conflict.component";
import ErrorBoundary from "../../components/error-boundary/error-boundary.component"; import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
import FcmNotification from "../../components/fcm-notification/fcm-notification.component"; import FcmNotification from "../../components/fcm-notification/fcm-notification.component";
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
//import FooterComponent from "../../components/footer/footer.component"; //import FooterComponent from "../../components/footer/footer.component";
//Component Imports //Component Imports
import HeaderContainer from "../../components/header/header.container"; import HeaderContainer from "../../components/header/header.container";
import JiraSupportComponent from "../../components/jira-support-widget/jira-support-widget.component"; import JiraSupportComponent from "../../components/jira-support-widget/jira-support-widget.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import PartnerPingComponent from "../../components/partner-ping/partner-ping.component"; import PartnerPingComponent from "../../components/partner-ping/partner-ping.component";
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container"; import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
import TestComponent from "../../components/_test/test.component"; import TestComponent from "../../components/_test/test.component";
import { QUERY_STRIPE_ID } from "../../graphql/bodyshop.queries"; import { QUERY_STRIPE_ID } from "../../graphql/bodyshop.queries";
import { import {
@@ -34,6 +33,7 @@ const ManageRootPage = lazy(() =>
import("../manage-root/manage-root.page.container") import("../manage-root/manage-root.page.container")
); );
const JobsPage = lazy(() => import("../jobs/jobs.page")); const JobsPage = lazy(() => import("../jobs/jobs.page"));
const JobsDetailPage = lazy(() => const JobsDetailPage = lazy(() =>
import("../jobs-detail/jobs-detail.page.container") import("../jobs-detail/jobs-detail.page.container")
); );
@@ -154,7 +154,7 @@ const EmailTest = lazy(() =>
import("../../components/email-test/email-test-component") import("../../components/email-test/email-test-component")
); );
const { Content, Header } = Layout; const { Content, Footer } = Layout;
const stripePromise = new Promise((resolve, reject) => { const stripePromise = new Promise((resolve, reject) => {
client.query({ query: QUERY_STRIPE_ID }).then((resp) => { client.query({ query: QUERY_STRIPE_ID }).then((resp) => {
@@ -197,7 +197,6 @@ export function Manage({ match, conflict, bodyshop }) {
<PrintCenterModalContainer /> <PrintCenterModalContainer />
<Route exact path={`${match.path}/_test`} component={TestComponent} /> <Route exact path={`${match.path}/_test`} component={TestComponent} />
<Route exact path={`${match.path}`} component={ManageRootPage} /> <Route exact path={`${match.path}`} component={ManageRootPage} />
<Route exact path={`${match.path}/jobs`} component={JobsPage} /> <Route exact path={`${match.path}/jobs`} component={JobsPage} />
<Switch> <Switch>
<Route <Route
@@ -365,27 +364,27 @@ export function Manage({ match, conflict, bodyshop }) {
return ( return (
<Layout className="layout-container"> <Layout className="layout-container">
<Header> <HeaderContainer />
<HeaderContainer />
</Header>
<Content className="content-container"> <Content className="content-container">
<FcmNotification /> <FcmNotification />
<PartnerPingComponent /> <PartnerPingComponent />
<ErrorBoundary>{PageContent}</ErrorBoundary> <ErrorBoundary>{PageContent}</ErrorBoundary>
<ChatAffixContainer /> <ChatAffixContainer />
<BackTop /> <BackTop />
<div style={{ textAlign: "center", margin: "1rem 0rem" }}> <Footer>
<div> <div style={{ textAlign: "center", margin: "1rem 0rem" }}>
{`ImEX Online V.${process.env.NODE_ENV} - ${ <div>
process.env.REACT_APP_GIT_SHA {`ImEX Online V.${process.env.NODE_ENV} - ${
} - ${preval`module.exports = new Date().toLocaleString();`}`} process.env.REACT_APP_GIT_SHA
} - ${preval`module.exports = new Date().toLocaleString();`}`}
</div>
<Link to="/about" target="_blank" style={{ color: "#ccc" }}>
Disclaimer
</Link>
<JiraSupportComponent />
</div> </div>
<Link to="/about" target="_blank" style={{ color: "#ccc" }}> </Footer>
Disclaimer
</Link>
<JiraSupportComponent />
</div>
</Content> </Content>
</Layout> </Layout>
); );

View File

@@ -2,21 +2,17 @@ import { useQuery } from "@apollo/client";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries"; import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
import { setBodyshop } from "../../redux/user/user.actions"; import { setBodyshop } from "../../redux/user/user.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import ManagePage from "./manage.page.component"; import ManagePage from "./manage.page.component";
const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBodyshop: (bs) => dispatch(setBodyshop(bs)), setBodyshop: (bs) => dispatch(setBodyshop(bs)),
}); });
function ManagePageContainer({ match, setBodyshop, bodyshop }) { function ManagePageContainer({ match, setBodyshop }) {
const { loading, error, data } = useQuery(QUERY_BODYSHOP, { const { loading, error, data } = useQuery(QUERY_BODYSHOP, {
fetchPolicy: "network-only", fetchPolicy: "network-only",
}); });
@@ -34,7 +30,4 @@ function ManagePageContainer({ match, setBodyshop, bodyshop }) {
return <ManagePage match={match} />; return <ManagePage match={match} />;
} }
export default connect( export default connect(null, mapDispatchToProps)(ManagePageContainer);
mapStateToProps,
mapDispatchToProps
)(ManagePageContainer);

View File

@@ -1,12 +1,8 @@
.content-container { .content-container {
overflow-y: auto; padding: 1rem;
margin: 1rem 1rem 0rem 1rem;
padding: 0.25rem 2.5rem 1rem 2.5rem;
border-radius: 4px;
background: #fff;
padding-bottom: 3rem;
} }
.layout-container { .layout-container {
height: 100vh; height: 100vh;
overflow-y: auto;
} }

View File

@@ -1001,6 +1001,7 @@
"ins_city": "Insurance City", "ins_city": "Insurance City",
"ins_co_id": "Insurance Co. ID", "ins_co_id": "Insurance Co. ID",
"ins_co_nm": "Insurance Company Name", "ins_co_nm": "Insurance Company Name",
"ins_co_nm_short": "Ins. Co.",
"ins_ct_fn": "File Handler First Name", "ins_ct_fn": "File Handler First Name",
"ins_ct_ln": "File Handler Last Name", "ins_ct_ln": "File Handler Last Name",
"ins_ea": "File Handler Email", "ins_ea": "File Handler Email",

View File

@@ -1001,6 +1001,7 @@
"ins_city": "Ciudad de seguros", "ins_city": "Ciudad de seguros",
"ins_co_id": "ID de la compañía de seguros", "ins_co_id": "ID de la compañía de seguros",
"ins_co_nm": "Nombre de la compañía de seguros", "ins_co_nm": "Nombre de la compañía de seguros",
"ins_co_nm_short": "",
"ins_ct_fn": "Nombre del controlador de archivos", "ins_ct_fn": "Nombre del controlador de archivos",
"ins_ct_ln": "Apellido del manejador de archivos", "ins_ct_ln": "Apellido del manejador de archivos",
"ins_ea": "Correo electrónico del controlador de archivos", "ins_ea": "Correo electrónico del controlador de archivos",

View File

@@ -1001,6 +1001,7 @@
"ins_city": "Insurance City", "ins_city": "Insurance City",
"ins_co_id": "ID de la compagnie d'assurance", "ins_co_id": "ID de la compagnie d'assurance",
"ins_co_nm": "Nom de la compagnie d'assurance", "ins_co_nm": "Nom de la compagnie d'assurance",
"ins_co_nm_short": "",
"ins_ct_fn": "Prénom du gestionnaire de fichiers", "ins_ct_fn": "Prénom du gestionnaire de fichiers",
"ins_ct_ln": "Nom du gestionnaire de fichiers", "ins_ct_ln": "Nom du gestionnaire de fichiers",
"ins_ea": "Courriel du gestionnaire de fichiers", "ins_ea": "Courriel du gestionnaire de fichiers",

View File

@@ -0,0 +1,18 @@
import React, { useEffect, useRef } from "react";
function useTraceUpdate(props) {
const prev = useRef(props);
useEffect(() => {
const changedProps = Object.entries(props).reduce((ps, [k, v]) => {
if (prev.current[k] !== v) {
ps[k] = [prev.current[k], v];
}
return ps;
}, {});
if (Object.keys(changedProps).length > 0) {
console.log("Changed props:", changedProps);
}
prev.current = props;
});
}
export default useTraceUpdate;