Compare commits

..

2 Commits

Author SHA1 Message Date
Patrick Fic
2be0f3de09 IO-2329 Remove testing statement. 2023-06-07 12:05:55 -07:00
Patrick Fic
b791f9846f IO-2329 Change update alert to be permanent. 2023-06-07 12:03:17 -07:00
15 changed files with 112 additions and 148 deletions

View File

@@ -32,9 +32,9 @@ const mapDispatchToProps = (dispatch) => ({
});
const span = {
lg: { span: 24 },
xl: { span: 12 },
xxl: { span: 8 },
sm: { span: 24 },
md: { span: 12 },
lg: { span: 8 },
};
export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
@@ -137,6 +137,12 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<JobDetailCardsPartsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<JobDetailCardsNotesComponent
loading={loading}
@@ -157,12 +163,6 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col span={24}>
<JobDetailCardsPartsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
</Row>
</Card>
) : null}

View File

@@ -1,119 +1,16 @@
import { Table } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import JobLineNotePopup from "../job-line-note-popup/job-line-note-popup.component";
import PartsStatusPie from "../parts-status-pie/parts-status-pie.component";
import CardTemplate from "./job-detail-cards.template.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort } from "../../utils/sorters";
import JobLineLocationPopup from "../job-line-location-popup/job-line-location-popup.component";
import JobLineStatusPopup from "../job-line-status-popup/job-line-status-popup.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
jobRO: selectJobReadOnly,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobDetailCardsPartsComponent);
export function JobDetailCardsPartsComponent({ loading, data, jobRO }) {
export default function JobDetailCardsPartsComponent({ loading, data }) {
const { t } = useTranslation();
const { joblines_status } = data;
const columns = [
{
title: t("joblines.fields.line_desc"),
dataIndex: "line_desc",
fixed: "left",
key: "line_desc",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
onCell: (record) => ({
className: record.manual_line && "job-line-manual",
style: {
...(record.critical ? { boxShadow: " -.5em 0 0 #FFC107" } : {}),
},
}),
width: "30%",
ellipsis: true,
},
{
title: t("joblines.fields.part_type"),
dataIndex: "part_type",
key: "part_type",
width: "15%",
sorter: (a, b) =>
alphaSort(
t(`joblines.fields.part_types.${a.part_type}`),
t(`joblines.fields.part_types.${b.part_type}`)
),
render: (text, record) =>
record.part_type
? t(`joblines.fields.part_types.${record.part_type}`)
: null,
},
{
title: t("joblines.fields.part_qty"),
dataIndex: "part_qty",
key: "part_qty",
width: "10%",
},
{
title: t("joblines.fields.notes"),
dataIndex: "notes",
key: "notes",
render: (text, record) => (
<JobLineNotePopup disabled={jobRO} jobline={record} />
),
},
{
title: t("joblines.fields.location"),
dataIndex: "location",
key: "location",
sorter: (a, b) => alphaSort(a.location, b.location),
render: (text, record) => (
<JobLineLocationPopup jobline={record} disabled={jobRO} />
),
},
{
title: t("joblines.fields.status"),
dataIndex: "status",
key: "status",
sorter: (a, b) => alphaSort(a.status, b.status),
filters:
(data &&
data.joblines
?.map((l) => l.status)
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Status*",
value: [s],
};
})) ||
[],
onFilter: (value, record) => value.includes(record.status),
render: (text, record) => (
<JobLineStatusPopup jobline={record} disabled={jobRO} />
),
},
];
return (
<div>
<CardTemplate loading={loading} title={t("jobs.labels.cards.parts")}>
<PartsStatusPie joblines_status={joblines_status} />
<Table
key="id"
columns={columns}
dataSource={data ? data.joblines : []}
/>
</CardTemplate>
</div>
);

View File

@@ -88,7 +88,7 @@ export function ProductionListDetail({
/>
}
placement="right"
width={"50%"}
width={"33%"}
onClose={handleClose}
visible={selected}
>

View File

@@ -0,0 +1,72 @@
import { Alert, Button, Space } from "antd";
import i18n from "i18next";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectUpdateAvailable } from "../../redux/application/application.selectors";
import { AlertOutlined } from "@ant-design/icons";
import { useTranslation } from "react-i18next";
import { setUpdateAvailable } from "../../redux/application/application.actions";
import { store } from "../../redux/store";
import * as serviceWorkerRegistration from "../../serviceWorkerRegistration";
let globalRegistration;
const mapStateToProps = createStructuredSelector({
updateAvailable: selectUpdateAvailable,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(UpdateAlert);
export function UpdateAlert({ updateAvailable }) {
const { t } = useTranslation();
if (!updateAvailable) return null;
return (
<Alert
message={t("general.messages.newversiontitle")}
showIcon
icon={<AlertOutlined />}
description={t("general.messages.newversionmessage")}
closable={false}
type="warning"
action={
<Space flex>
<Button
onClick={async () => {
window.open("https://imex-online.noticeable.news/", "_blank");
}}
>
{i18n.t("general.actions.viewreleasenotes")}
</Button>
<Button
type="primary"
onClick={async () => {
if (globalRegistration && globalRegistration.waiting) {
await globalRegistration.unregister();
// Makes Workbox call skipWaiting()
globalRegistration.waiting.postMessage({
type: "SKIP_WAITING",
});
// Once the service worker is unregistered, we can reload the page to let
// the browser download a fresh copy of our app (invalidating the cache)
window.location.reload();
}
}}
>
{i18n.t("general.actions.refresh")}
</Button>
</Space>
}
/>
);
}
const onServiceWorkerUpdate = (registration) => {
console.log("onServiceWorkerUpdate", registration);
globalRegistration = registration;
store.dispatch(setUpdateAvailable(true));
};
serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate });

View File

@@ -868,40 +868,10 @@ export const QUERY_JOB_CARD_DETAILS = gql`
count
status
}
joblines(
where: {
removed: { _eq: false }
part_type: { _is_null: false, _nin: ["PAE", "PAS", "PASL"] }
}
order_by: { line_no: asc }
) {
joblines(where: { removed: { _eq: false } }) {
id
alt_partm
line_no
unq_seq
line_ind
line_desc
line_ref
part_type
part_qty
mod_lbr_ty
db_hrs
mod_lb_hrs
lbr_op
lbr_amt
op_code_desc
status
notes
location
tax_part
db_ref
manual_line
prt_dsmk_p
prt_dsmk_m
ioucreated
convertedtolbr
critical
}
owner {
id

View File

@@ -25,6 +25,7 @@ import {
import * as Sentry from "@sentry/react";
import "./manage.page.styles.scss";
import UpdateAlert from "../../components/update-alert/update-alert.component";
const ManageRootPage = lazy(() =>
import("../manage-root/manage-root.page.container")
@@ -394,6 +395,7 @@ export function Manage({ match, conflict, bodyshop }) {
<>
<ChatAffixContainer />
<Layout className="layout-container">
<UpdateAlert />
<HeaderContainer />
<Content className="content-container">

View File

@@ -6,7 +6,7 @@ import AlertComponent from "../../components/alert/alert.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
import { setBodyshop } from "../../redux/user/user.actions";
import "../../utils/RegisterSw";
//import "../../utils/RegisterSw";
import ManagePage from "./manage.page.component";
const mapDispatchToProps = (dispatch) => ({

View File

@@ -12,6 +12,7 @@ import TechSider from "../../components/tech-sider/tech-sider.component";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import "./tech.page.styles.scss";
import UpdateAlert from "../../components/update-alert/update-alert.component";
const TimeTicketModalContainer = lazy(() =>
import("../../components/time-ticket-modal/time-ticket-modal.container")
);
@@ -56,7 +57,9 @@ export function TechPage({ technician, match }) {
<TechSider />
<Layout>
{technician ? null : <Redirect to={`${match.path}/login`} />}
<UpdateAlert />
<TechHeader />
<Content className="tech-content-container">
<ErrorBoundary>
<Suspense

View File

@@ -9,7 +9,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
import { useTranslation } from "react-i18next";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { createStructuredSelector } from "reselect";
import "../../utils/RegisterSw";
//import "../../utils/RegisterSw";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,

View File

@@ -62,3 +62,8 @@ export const setProblemJobs = (problemJobs) => ({
type: ApplicationActionTypes.SET_PROBLEM_JOBS,
payload: problemJobs,
});
export const setUpdateAvailable = (isUpdateAvailable) => ({
type: ApplicationActionTypes.SET_UPDATE_AVAILABLE,
payload: isUpdateAvailable,
});

View File

@@ -3,6 +3,7 @@ import ApplicationActionTypes from "./application.types";
const INITIAL_STATE = {
loading: false,
online: true,
updateAvailable: false,
breadcrumbs: [],
recentItems: [],
selectedHeader: "home",
@@ -18,6 +19,11 @@ const INITIAL_STATE = {
const applicationReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case ApplicationActionTypes.SET_UPDATE_AVAILABLE:
return {
...state,
updateAvailable: action.payload,
};
case ApplicationActionTypes.SET_SELECTED_HEADER:
return {
...state,

View File

@@ -48,3 +48,7 @@ export const selectProblemJobs = createSelector(
[selectApplication],
(application) => application.problemJobs
);
export const selectUpdateAvailable = createSelector(
[selectApplication],
(application) => application.updateAvailable
);

View File

@@ -12,5 +12,6 @@ const ApplicationActionTypes = {
SET_ONLINE_STATUS: "SET_ONLINE_STATUS",
INSERT_AUDIT_TRAIL: "INSERT_AUDIT_TRAIL",
SET_PROBLEM_JOBS: "SET_PROBLEM_JOBS",
SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE"
};
export default ApplicationActionTypes;

View File

@@ -1118,7 +1118,7 @@
},
"messages": {
"exception": "$t(titles.app) has encountered an error. Please try again. If the problem persists, please submit a support ticket or contact us.",
"newversionmessage": "Click refresh below to update to the latest available version of ImEX Online. Please make sure all other tabs and windows are closed.",
"newversionmessage": "Click refresh to update to the latest available version of ImEX Online. Please make sure all other tabs and windows are closed.",
"newversiontitle": "New version of ImEX Online Available",
"noacctfilepath": "There is no accounting file path set. You will not be able to export any items.",
"nofeatureaccess": "You do not have access to this feature of ImEX Online. Please contact support to request a license for this feature.",

View File

@@ -3,6 +3,7 @@ import { Button, notification, Space } from "antd";
import i18n from "i18next";
import React from "react";
import * as serviceWorkerRegistration from "../serviceWorkerRegistration";
import { store } from "../redux/store";
const onServiceWorkerUpdate = (registration) => {
console.log("onServiceWorkerUpdate", registration);
@@ -33,6 +34,9 @@ const onServiceWorkerUpdate = (registration) => {
</Button>
</Space>
);
store.dispatch()
notification.open({
icon: <AlertOutlined />,
message: i18n.t("general.messages.newversiontitle"),