Merged in feature/IO-3020-IO-3036-imex-lite-rome-lite (pull request #2012)
feature/IO-3020-IO-3036-imex-lite-rome-lite Approved-by: Patrick Fic
This commit is contained in:
79
.gitattributes
vendored
79
.gitattributes
vendored
@@ -1 +1,80 @@
|
|||||||
|
# Ensure all text files use LF for line endings
|
||||||
* text eol=lf
|
* text eol=lf
|
||||||
|
|
||||||
|
# Binary files should not be modified by Git
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.webp binary
|
||||||
|
*.svg binary
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
|
*.ttf binary
|
||||||
|
*.otf binary
|
||||||
|
*.eot binary
|
||||||
|
|
||||||
|
# Videos
|
||||||
|
*.mp4 binary
|
||||||
|
*.mov binary
|
||||||
|
*.avi binary
|
||||||
|
*.mkv binary
|
||||||
|
*.webm binary
|
||||||
|
|
||||||
|
# Audio
|
||||||
|
*.mp3 binary
|
||||||
|
*.wav binary
|
||||||
|
*.ogg binary
|
||||||
|
*.flac binary
|
||||||
|
|
||||||
|
# Archives and compressed files
|
||||||
|
*.zip binary
|
||||||
|
*.gz binary
|
||||||
|
*.tar binary
|
||||||
|
*.7z binary
|
||||||
|
*.rar binary
|
||||||
|
|
||||||
|
# PDF and documents
|
||||||
|
*.pdf binary
|
||||||
|
*.doc binary
|
||||||
|
*.docx binary
|
||||||
|
*.xls binary
|
||||||
|
*.xlsx binary
|
||||||
|
*.ppt binary
|
||||||
|
*.pptx binary
|
||||||
|
|
||||||
|
# Exclude JSON and other data files from text processing, if necessary
|
||||||
|
*.json text
|
||||||
|
*.xml text
|
||||||
|
*.csv text
|
||||||
|
|
||||||
|
# Scripts and code files should maintain LF endings
|
||||||
|
*.js text eol=lf
|
||||||
|
*.jsx text eol=lf
|
||||||
|
*.ts text eol=lf
|
||||||
|
*.tsx text eol=lf
|
||||||
|
*.css text eol=lf
|
||||||
|
*.scss text eol=lf
|
||||||
|
*.html text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.py text eol=lf
|
||||||
|
*.rb text eol=lf
|
||||||
|
*.java text eol=lf
|
||||||
|
*.php text eol=lf
|
||||||
|
|
||||||
|
# Git configuration files
|
||||||
|
.gitattributes text eol=lf
|
||||||
|
.gitignore text eol=lf
|
||||||
|
*.gitattributes text eol=lf
|
||||||
|
|
||||||
|
# Exclude some other potential binary files
|
||||||
|
*.db binary
|
||||||
|
*.sqlite binary
|
||||||
|
*.exe binary
|
||||||
|
*.dll binary
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
|
|||||||
md: "100%",
|
md: "100%",
|
||||||
lg: "75%",
|
lg: "75%",
|
||||||
xl: "75%",
|
xl: "75%",
|
||||||
xxl: "60%"
|
xxl: "75%"
|
||||||
};
|
};
|
||||||
const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%";
|
const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%";
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { GenerateThumbUrl } from "../jobs-documents-gallery/job-documents.utility";
|
import { GenerateThumbUrl } from "../jobs-documents-gallery/job-documents.utility";
|
||||||
import CardTemplate from "./job-detail-cards.template.component";
|
import CardTemplate from "./job-detail-cards.template.component";
|
||||||
|
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||||
|
|
||||||
export default function JobDetailCardsDocumentsComponent({ loading, data }) {
|
export default function JobDetailCardsDocumentsComponent({ loading, data }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -20,15 +21,17 @@ export default function JobDetailCardsDocumentsComponent({ loading, data }) {
|
|||||||
title={t("jobs.labels.cards.documents")}
|
title={t("jobs.labels.cards.documents")}
|
||||||
extraLink={`/manage/jobs/${data.id}?tab=documents`}
|
extraLink={`/manage/jobs/${data.id}?tab=documents`}
|
||||||
>
|
>
|
||||||
{data.documents.length > 0 ? (
|
<UpsellComponent disableMask upsell={upsellEnum().media.general}>
|
||||||
<Carousel autoplay>
|
{data.documents.length > 0 ? (
|
||||||
{data.documents.map((item) => (
|
<Carousel autoplay>
|
||||||
<img key={item.id} src={GenerateThumbUrl(item)} alt={item.name} />
|
{data.documents.map((item) => (
|
||||||
))}
|
<img key={item.id} src={GenerateThumbUrl(item)} alt={item.name} />
|
||||||
</Carousel>
|
))}
|
||||||
) : (
|
</Carousel>
|
||||||
<div>{t("documents.errors.nodocuments")}</div>
|
) : (
|
||||||
)}
|
<div>{t("documents.errors.nodocuments")}</div>
|
||||||
|
)}
|
||||||
|
</UpsellComponent>
|
||||||
</CardTemplate>
|
</CardTemplate>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -892,16 +892,16 @@ export function JobsDetailHeaderActions({
|
|||||||
key: "postbills",
|
key: "postbills",
|
||||||
id: "job-actions-postbills",
|
id: "job-actions-postbills",
|
||||||
disabled: !job.converted,
|
disabled: !job.converted,
|
||||||
label: <LockerWrapperComponent featureName="bill">{t("jobs.actions.postbills")}</LockerWrapperComponent>,
|
label: <LockerWrapperComponent featureName="bills">{t("jobs.actions.postbills")}</LockerWrapperComponent>,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
logImEXEvent("job_header_enter_bills");
|
logImEXEvent("job_header_enter_bills");
|
||||||
|
HasFeatureAccess({ featureName: "bills", bodyshop }) &&
|
||||||
setBillEnterContext({
|
setBillEnterContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: {
|
context: {
|
||||||
job: job
|
job: job
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ function JobsDocumentsComponent({
|
|||||||
{!hasMediaAccess && (
|
{!hasMediaAccess && (
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<Card>
|
<Card>
|
||||||
<UpsellComponent upsell={upsellEnum().media.general} />
|
<UpsellComponent disableMask upsell={upsellEnum().media.general} />
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FileExcelFilled, SyncOutlined } from "@ant-design/icons";
|
import { FileExcelFilled, SyncOutlined } from "@ant-design/icons";
|
||||||
import { Alert, Button, Card, Space } from "antd";
|
import { Alert, Button, Card, Col, Row, Space } from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Gallery } from "react-grid-gallery";
|
import { Gallery } from "react-grid-gallery";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -18,6 +18,7 @@ import JobsDocumentsLocalGallerySelectAllComponent from "./jobs-documents-local-
|
|||||||
import Lightbox from "react-image-lightbox";
|
import Lightbox from "react-image-lightbox";
|
||||||
import "react-image-lightbox/style.css";
|
import "react-image-lightbox/style.css";
|
||||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
|
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -88,95 +89,117 @@ export function JobsDocumentsLocalGallery({
|
|||||||
const hasMediaAccess = HasFeatureAccess({ bodyshop, featureName: "media" });
|
const hasMediaAccess = HasFeatureAccess({ bodyshop, featureName: "media" });
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Space wrap>
|
<Row gutter={[16, 16]}>
|
||||||
<Button
|
<Col span={24}>
|
||||||
onClick={() => {
|
<Space wrap>
|
||||||
if (job) {
|
<Button
|
||||||
if (invoice_number) {
|
onClick={() => {
|
||||||
getBillMedia({ jobid: job.id, invoice_number });
|
if (job) {
|
||||||
} else {
|
if (invoice_number) {
|
||||||
getJobMedia(job.id);
|
getBillMedia({ jobid: job.id, invoice_number });
|
||||||
}
|
} else {
|
||||||
}
|
getJobMedia(job.id);
|
||||||
}}
|
}
|
||||||
>
|
}
|
||||||
<SyncOutlined />
|
}}
|
||||||
</Button>
|
>
|
||||||
<a href={CreateExplorerLinkForJob({ jobid: job.id })}>
|
<SyncOutlined />
|
||||||
<Button>{t("documents.labels.openinexplorer")}</Button>
|
</Button>
|
||||||
</a>
|
<a href={CreateExplorerLinkForJob({ jobid: job.id })}>
|
||||||
<JobsDocumentsLocalGalleryReassign jobid={job.id} />
|
<Button>{t("documents.labels.openinexplorer")}</Button>
|
||||||
<JobsDocumentsLocalGallerySelectAllComponent jobid={job.id} />
|
</a>
|
||||||
<JobsLocalGalleryDownloadButton job={job} />
|
<JobsDocumentsLocalGalleryReassign jobid={job.id} />
|
||||||
<JobsDocumentsLocalDeleteButton jobid={job.id} />
|
<JobsDocumentsLocalGallerySelectAllComponent jobid={job.id} />
|
||||||
</Space>
|
<JobsLocalGalleryDownloadButton job={job} />
|
||||||
<Card>
|
<JobsDocumentsLocalDeleteButton jobid={job.id} />
|
||||||
<DocumentsLocalUploadComponent job={job} invoice_number={invoice_number} vendorid={vendorid} allowAllTypes />
|
</Space>
|
||||||
</Card>
|
</Col>
|
||||||
<Card title={t("jobs.labels.documents-images")}>
|
{!hasMediaAccess && (
|
||||||
<Gallery
|
<Col span={24}>
|
||||||
images={jobMedia.images}
|
<Card>
|
||||||
onSelect={(index, image) => {
|
<UpsellComponent disableMask upsell={upsellEnum().media.general} />
|
||||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
</Card>
|
||||||
}}
|
</Col>
|
||||||
{...(optimized && {
|
)}
|
||||||
customControls: [
|
<Col span={24}>
|
||||||
<Alert style={{ margin: "4px" }} message={t("documents.labels.optimizedimage")} type="success" />
|
<Card>
|
||||||
]
|
<DocumentsLocalUploadComponent
|
||||||
})}
|
job={job}
|
||||||
onClick={(index) => {
|
invoice_number={invoice_number}
|
||||||
setModalState({ open: true, index: index });
|
vendorid={vendorid}
|
||||||
// const media = allMedia[job.id].find(
|
allowAllTypes
|
||||||
// (m) => m.optimized === item.src
|
/>
|
||||||
// );
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Card title={t("jobs.labels.documents-images")}>
|
||||||
|
<Gallery
|
||||||
|
images={jobMedia.images}
|
||||||
|
onSelect={(index, image) => {
|
||||||
|
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||||
|
}}
|
||||||
|
{...(optimized && {
|
||||||
|
customControls: [
|
||||||
|
<Alert style={{ margin: "4px" }} message={t("documents.labels.optimizedimage")} type="success" />
|
||||||
|
]
|
||||||
|
})}
|
||||||
|
onClick={(index) => {
|
||||||
|
setModalState({ open: true, index: index });
|
||||||
|
// const media = allMedia[job.id].find(
|
||||||
|
// (m) => m.optimized === item.src
|
||||||
|
// );
|
||||||
|
|
||||||
// window.open(
|
// window.open(
|
||||||
// media ? media.fullsize : item.fullsize,
|
// media ? media.fullsize : item.fullsize,
|
||||||
// "_blank",
|
// "_blank",
|
||||||
// "toolbar=0,location=0,menubar=0"
|
// "toolbar=0,location=0,menubar=0"
|
||||||
// );
|
// );
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
<Card title={t("jobs.labels.documents-other")}>
|
</Col>
|
||||||
<Gallery
|
<Col span={24}>
|
||||||
images={jobMedia.other}
|
<Card title={t("jobs.labels.documents-other")}>
|
||||||
thumbnailStyle={() => {
|
<Gallery
|
||||||
return {
|
images={jobMedia.other}
|
||||||
backgroundImage: <FileExcelFilled />,
|
thumbnailStyle={() => {
|
||||||
height: "100%",
|
return {
|
||||||
width: "100%",
|
backgroundImage: <FileExcelFilled />,
|
||||||
cursor: "pointer"
|
height: "100%",
|
||||||
};
|
width: "100%",
|
||||||
}}
|
cursor: "pointer"
|
||||||
onClick={(index) => {
|
};
|
||||||
window.open(jobMedia.other[index].fullsize, "_blank", "toolbar=0,location=0,menubar=0");
|
}}
|
||||||
}}
|
onClick={(index) => {
|
||||||
onSelect={(index, image) => {
|
window.open(jobMedia.other[index].fullsize, "_blank", "toolbar=0,location=0,menubar=0");
|
||||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
}}
|
||||||
}}
|
onSelect={(index, image) => {
|
||||||
/>
|
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||||
</Card>
|
}}
|
||||||
{modalState.open && (
|
/>
|
||||||
<Lightbox
|
</Card>
|
||||||
mainSrc={jobMedia.images[modalState.index].fullsize}
|
</Col>
|
||||||
nextSrc={jobMedia.images[(modalState.index + 1) % jobMedia.images.length].fullsize}
|
{modalState.open && (
|
||||||
prevSrc={jobMedia.images[(modalState.index + jobMedia.images.length - 1) % jobMedia.images.length].fullsize}
|
<Lightbox
|
||||||
onCloseRequest={() => setModalState({ open: false, index: 0 })}
|
mainSrc={jobMedia.images[modalState.index].fullsize}
|
||||||
onMovePrevRequest={() =>
|
nextSrc={jobMedia.images[(modalState.index + 1) % jobMedia.images.length].fullsize}
|
||||||
setModalState({
|
prevSrc={jobMedia.images[(modalState.index + jobMedia.images.length - 1) % jobMedia.images.length].fullsize}
|
||||||
...modalState,
|
onCloseRequest={() => setModalState({ open: false, index: 0 })}
|
||||||
index: (modalState.index + jobMedia.images.length - 1) % jobMedia.images.length
|
onMovePrevRequest={() =>
|
||||||
})
|
setModalState({
|
||||||
}
|
...modalState,
|
||||||
onMoveNextRequest={() =>
|
index: (modalState.index + jobMedia.images.length - 1) % jobMedia.images.length
|
||||||
setModalState({
|
})
|
||||||
...modalState,
|
}
|
||||||
index: (modalState.index + 1) % jobMedia.images.length
|
onMoveNextRequest={() =>
|
||||||
})
|
setModalState({
|
||||||
}
|
...modalState,
|
||||||
/>
|
index: (modalState.index + 1) % jobMedia.images.length
|
||||||
)}
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Alert, Form, InputNumber, Switch } from "antd";
|
import { Alert, Form, Switch } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
import { Col, Row, Typography } from "antd";
|
import { Card, Col, Row, Typography } from "antd";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -14,6 +14,8 @@ import { QUERY_JOB_CHECKLISTS } from "../../graphql/jobs.queries";
|
|||||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||||
|
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -73,38 +75,47 @@ export function JobsChecklistViewContainer({ bodyshop, setBreadcrumbs, setSelect
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RbacWrapper action="jobs:checklist-view">
|
<FeatureWrapperComponent
|
||||||
<Row gutter={[16, 16]}>
|
featureName="checklist"
|
||||||
<Col span={12}>
|
noauth={
|
||||||
<Typography.Title level={4}>{t("jobs.labels.intakechecklist")}</Typography.Title>
|
<Card>
|
||||||
{data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form && (
|
<UpsellComponent upsell={upsellEnum().checklist.general} />
|
||||||
<>
|
</Card>
|
||||||
<JobChecklistForm
|
}
|
||||||
formItems={data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form}
|
>
|
||||||
type="intake"
|
<RbacWrapper action="jobs:checklist-view">
|
||||||
job={data.jobs_by_pk}
|
<Row gutter={[16, 16]}>
|
||||||
readOnly
|
<Col span={12}>
|
||||||
/>
|
<Typography.Title level={4}>{t("jobs.labels.intakechecklist")}</Typography.Title>
|
||||||
<CompletedBy checklist={data.jobs_by_pk.intakechecklist} />
|
{data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form && (
|
||||||
</>
|
<>
|
||||||
)}
|
<JobChecklistForm
|
||||||
</Col>
|
formItems={data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form}
|
||||||
<Col span={12}>
|
type="intake"
|
||||||
<Typography.Title level={4}>{t("jobs.labels.deliverchecklist")}</Typography.Title>
|
job={data.jobs_by_pk}
|
||||||
{data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form && (
|
readOnly
|
||||||
<>
|
/>
|
||||||
<JobChecklistForm
|
<CompletedBy checklist={data.jobs_by_pk.intakechecklist} />
|
||||||
formItems={data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form}
|
</>
|
||||||
type="deliver"
|
)}
|
||||||
job={data.jobs_by_pk}
|
</Col>
|
||||||
readOnly
|
<Col span={12}>
|
||||||
/>
|
<Typography.Title level={4}>{t("jobs.labels.deliverchecklist")}</Typography.Title>
|
||||||
<CompletedBy checklist={data.jobs_by_pk.deliverchecklist} />
|
{data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form && (
|
||||||
</>
|
<>
|
||||||
)}
|
<JobChecklistForm
|
||||||
</Col>
|
formItems={data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form}
|
||||||
</Row>
|
type="deliver"
|
||||||
</RbacWrapper>
|
job={data.jobs_by_pk}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
<CompletedBy checklist={data.jobs_by_pk.deliverchecklist} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</RbacWrapper>
|
||||||
|
</FeatureWrapperComponent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user