Jobs list page updates & note adding modal.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useQuery } from "@apollo/react-hooks";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
@@ -17,6 +17,8 @@ import JobDetailCardsTotalsComponent from "./job-detail-cards.totals.component";
|
||||
import JobDetailCardsDocumentsComponent from "./job-detail-cards.documents.component";
|
||||
|
||||
import "./job-detail-cards.styles.scss";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import NoteAddModal from "../note-add-modal/note-add-modal.component";
|
||||
|
||||
export default function JobDetailCards({ selectedJob }) {
|
||||
const { loading, error, data } = useQuery(QUERY_JOB_CARD_DETAILS, {
|
||||
@@ -24,6 +26,7 @@ export default function JobDetailCards({ selectedJob }) {
|
||||
variables: { id: selectedJob },
|
||||
skip: !selectedJob
|
||||
});
|
||||
const [noteModalVisible, setNoteModalVisible] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -31,85 +34,106 @@ export default function JobDetailCards({ selectedJob }) {
|
||||
return <div>{t("jobs.errors.nojobselected")}</div>;
|
||||
}
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
console.log("data", data);
|
||||
return (
|
||||
<PageHeader
|
||||
ghost={false}
|
||||
onBack={() => window.history.back()}
|
||||
tags={<Tag color="blue">{data?.jobs_by_pk.job_status?.name}</Tag>}
|
||||
title={
|
||||
data?.jobs_by_pk.ro_number
|
||||
? `${t("jobs.fields.ro_number")} ${data?.jobs_by_pk.ro_number}`
|
||||
: `${t("jobs.fields.est_number")} ${data?.jobs_by_pk.est_number}`
|
||||
}
|
||||
extra={[
|
||||
<Button key="documents">
|
||||
<Icon type="file-image" />
|
||||
{t("jobs.actions.addDocuments")}
|
||||
</Button>,
|
||||
<Button key="printing">
|
||||
<Icon type="printer" />
|
||||
{t("jobs.actions.printCenter")}
|
||||
</Button>,
|
||||
<Button key="notes">
|
||||
<Icon type="edit" />
|
||||
{t("jobs.actions.addNote")}
|
||||
</Button>,
|
||||
<Button key="postinvoices">
|
||||
<Icon type="shopping-cart" />
|
||||
{t("jobs.actions.postInvoices")}
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
<Descriptions size="small" column={3}>
|
||||
<Descriptions.Item label="Created">Lili Qu</Descriptions.Item>
|
||||
<Descriptions.Item label="Association">421421</Descriptions.Item>
|
||||
<Descriptions.Item label="Creation Time">2017-01-10</Descriptions.Item>
|
||||
<Descriptions.Item label="Effective Time">2017-10-10</Descriptions.Item>
|
||||
<Descriptions.Item label="Remarks">
|
||||
Gonghu Road, Xihu District, Hangzhou, Zhejiang, China
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
|
||||
<section className="job-cards">
|
||||
<JobDetailCardsCustomerComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsVehicleComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsInsuranceComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsDatesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsPartsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsNotesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsDamageComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsDocumentsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsTotalsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</section>
|
||||
</PageHeader>
|
||||
return (
|
||||
<div className='job-cards-container'>
|
||||
<NoteAddModal
|
||||
jobId={data?.jobs_by_pk.id}
|
||||
visible={noteModalVisible}
|
||||
changeVisibility={setNoteModalVisible}
|
||||
/>
|
||||
<PageHeader
|
||||
ghost={false}
|
||||
onBack={() => window.history.back()}
|
||||
tags={<Tag color='blue'>{data?.jobs_by_pk.job_status?.name}</Tag>}
|
||||
title={
|
||||
loading
|
||||
? t("general.labels.loading")
|
||||
: data?.jobs_by_pk.ro_number
|
||||
? `${t("jobs.fields.ro_number")} ${data?.jobs_by_pk.ro_number}`
|
||||
: `${t("jobs.fields.est_number")} ${data?.jobs_by_pk.est_number}`
|
||||
}
|
||||
extra={[
|
||||
<Button key='documents'>
|
||||
<Icon type='file-image' />
|
||||
{t("jobs.actions.addDocuments")}
|
||||
</Button>,
|
||||
<Button key='printing'>
|
||||
<Icon type='printer' />
|
||||
{t("jobs.actions.printCenter")}
|
||||
</Button>,
|
||||
<Button
|
||||
key='notes'
|
||||
actiontype='addNote'
|
||||
onClick={() => {
|
||||
setNoteModalVisible(!noteModalVisible);
|
||||
}}>
|
||||
<Icon type='edit' />
|
||||
{t("jobs.actions.addNote")}
|
||||
</Button>,
|
||||
<Button key='postinvoices'>
|
||||
<Icon type='shopping-cart' />
|
||||
{t("jobs.actions.postInvoices")}
|
||||
</Button>
|
||||
]}>
|
||||
{loading ? (
|
||||
<LoadingSkeleton />
|
||||
) : (
|
||||
<Descriptions size='small' column={3}>
|
||||
<Descriptions.Item label='Created'>Lili Qu</Descriptions.Item>
|
||||
<Descriptions.Item label='Association'>421421</Descriptions.Item>
|
||||
<Descriptions.Item label='Creation Time'>
|
||||
2017-01-10
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Effective Time'>
|
||||
2017-10-10
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Remarks'>
|
||||
Gonghu Road, Xihu District, Hangzhou, Zhejiang, China
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
)}
|
||||
|
||||
<section className='job-cards'>
|
||||
<JobDetailCardsCustomerComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsVehicleComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsInsuranceComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsDatesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsPartsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsNotesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsDamageComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsDocumentsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobDetailCardsTotalsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</section>
|
||||
</PageHeader>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CardTemplate from "./job-detail-cards.template.component";
|
||||
import UnfoldedCar from "../../assets/unfolded_car.svg";
|
||||
|
||||
export default function JobDetailCardsDamageComponent({ loading, data }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -9,7 +10,7 @@ export default function JobDetailCardsDamageComponent({ loading, data }) {
|
||||
<CardTemplate loading={loading} title={t("jobs.labels.cards.damage")}>
|
||||
{data ? (
|
||||
<span>
|
||||
Damage stuff here.
|
||||
<img src={UnfoldedCar} alt='Damaged Area' width={200} height={200} />
|
||||
</span>
|
||||
) : null}
|
||||
</CardTemplate>
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CardTemplate from "./job-detail-cards.template.component";
|
||||
import Moment from "react-moment";
|
||||
import { Timeline } from "antd";
|
||||
|
||||
export default function JobDetailCardsDatesComponent({ loading, data }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -9,11 +10,15 @@ export default function JobDetailCardsDatesComponent({ loading, data }) {
|
||||
return (
|
||||
<CardTemplate loading={loading} title={t("jobs.labels.cards.dates")}>
|
||||
{data ? (
|
||||
<span>
|
||||
Actual In <Moment format="MM/DD/YYYY">{data?.actual_in}</Moment>
|
||||
Scheduled Completion
|
||||
<Moment format="MM/DD/YYYY">{data?.scheduled_completion}</Moment>
|
||||
</span>
|
||||
<Timeline>
|
||||
<Timeline.Item>
|
||||
Actual In <Moment format='MM/DD/YYYY'>{data?.actual_in}</Moment>
|
||||
</Timeline.Item>
|
||||
<Timeline.Item>
|
||||
Scheduled Completion
|
||||
<Moment format='MM/DD/YYYY'>{data?.scheduled_completion}</Moment>
|
||||
</Timeline.Item>
|
||||
</Timeline>
|
||||
) : null}
|
||||
</CardTemplate>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { List, Icon } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CardTemplate from "./job-detail-cards.template.component";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Container = styled.div`
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
export default function JobDetailCardsNotesComponent({ loading, data }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -8,9 +15,24 @@ export default function JobDetailCardsNotesComponent({ loading, data }) {
|
||||
return (
|
||||
<CardTemplate loading={loading} title={t("jobs.labels.cards.notes")}>
|
||||
{data ? (
|
||||
<span>
|
||||
notes stuff here.
|
||||
</span>
|
||||
<Container>
|
||||
<List
|
||||
size='small'
|
||||
bordered
|
||||
dataSource={data?.notes}
|
||||
renderItem={item => (
|
||||
<List.Item>
|
||||
{item.critical ? (
|
||||
<Icon style={{ margin: 4, color: "red" }} type='warning' />
|
||||
) : null}
|
||||
{item.private ? (
|
||||
<Icon style={{ margin: 4 }} type='eye-invisible' />
|
||||
) : null}
|
||||
{item.text}
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Container>
|
||||
) : null}
|
||||
</CardTemplate>
|
||||
);
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
.job-cards-container {
|
||||
height: 45vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.job-cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.job-card {
|
||||
|
||||
margin: .5em;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 40em) {
|
||||
.card {
|
||||
max-width: calc(50% - 1em);
|
||||
}
|
||||
.card {
|
||||
max-width: calc(50% - 1em);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 60em) {
|
||||
.card {
|
||||
max-width: calc(25% - 1em);
|
||||
}
|
||||
.card {
|
||||
max-width: calc(25% - 1em);
|
||||
}
|
||||
}
|
||||
|
||||
.centered {
|
||||
margin: 0 auto;
|
||||
padding: 0 1em;
|
||||
margin: 0 auto;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 52em) {
|
||||
.centered {
|
||||
max-width: 52em;
|
||||
}
|
||||
}
|
||||
.centered {
|
||||
max-width: 52em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function JobDetailCardTemplate({
|
||||
return (
|
||||
<Card
|
||||
size="small"
|
||||
style={{ width: 300 }}
|
||||
style={{ width: 290 }}
|
||||
className="job-card"
|
||||
title={title}
|
||||
loading={loading}
|
||||
|
||||
@@ -91,7 +91,7 @@ function JobTombstone({ job, ...otherProps }) {
|
||||
? (jobContext.owner?.first_name ?? "") +
|
||||
" " +
|
||||
(jobContext.owner?.last_name ?? "")
|
||||
: t("jobs.labels.no_owner")
|
||||
: t("jobs.errors.noowner")
|
||||
}
|
||||
tags={<Tag color='blue'>{jobContext?.job_status?.name}</Tag>}
|
||||
extra={[
|
||||
@@ -102,7 +102,7 @@ function JobTombstone({ job, ...otherProps }) {
|
||||
</Form.Item>
|
||||
]}>
|
||||
<Descriptions size='small' column={5}>
|
||||
<Descriptions.Item label={t("jobs.labels.vehicle_info")}>
|
||||
<Descriptions.Item label={t("jobs.fields.vehicle")}>
|
||||
<Link to={`/manage/vehicles/${jobContext.vehicle?.id}`}>
|
||||
{jobContext.vehicle?.v_model_yr ?? t("general.labels.na")}{" "}
|
||||
{jobContext.vehicle?.v_make_desc ?? t("general.labels.na")}{" "}
|
||||
@@ -185,4 +185,4 @@ function JobTombstone({ job, ...otherProps }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default Form.create({ name: "JobTombstone" })(JobTombstone);
|
||||
export default Form.create({ name: "JobTombstone" })(JobTombstone);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Input, Table, Icon } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Table, Icon, Input, Dropdown, Menu } from "antd";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import "./jobs-list.styles.scss";
|
||||
|
||||
export default function JobsPage({
|
||||
export default function JobsList({
|
||||
loading,
|
||||
jobs,
|
||||
selectedJob,
|
||||
@@ -17,38 +19,9 @@ export default function JobsPage({
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const actionMenu = (
|
||||
<Menu>
|
||||
<Menu.Item key="images">
|
||||
<Icon type="file-image" />
|
||||
{t("jobs.actions.viewJobImages")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="printing">
|
||||
<Icon type="printer" />
|
||||
{t("jobs.actions.printCenter")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="notes">
|
||||
<Icon type="edit" />
|
||||
{t("jobs.actions.notes")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="postinvoices">
|
||||
<Icon type="shopping-cart" />
|
||||
{t("jobs.actions.postInvoices")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="receiveparts">
|
||||
<Icon type="inbox" />
|
||||
{t("jobs.actions.receiveParts")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="partstatus">
|
||||
<Icon type="tool" />
|
||||
{t("jobs.actions.partStatus")}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "RO #",
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
// onFilter: (value, record) => record.ro_number.includes(value),
|
||||
@@ -56,67 +29,144 @@ export default function JobsPage({
|
||||
sorter: (a, b) => alphaSort(a, b),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||
ellipsis: true,
|
||||
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<Link to={`/manage/jobs/${record.id}`}>{record.ro_number}</Link>
|
||||
<Link to={"/manage/jobs/" + record.id}>
|
||||
{record.ro_number ? record.ro_number : t("general.labels.na")}
|
||||
</Link>
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Est. #",
|
||||
dataIndex: "est_number",
|
||||
key: "est_number"
|
||||
title: t("jobs.fields.owner"),
|
||||
dataIndex: "owner",
|
||||
key: "owner",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a.pit_owner_last_name, b.pit_owner_last_name),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.owner ? (
|
||||
<Link to={"/manage/owners/" + record.owner.id}>
|
||||
{record.pit_owner_first_name} {record.pit_owner_last_name}
|
||||
</Link>
|
||||
) : (
|
||||
t("jobs.errors.noowner")
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
title: t("jobs.fields.phone1"),
|
||||
dataIndex: "pit_owner_phone",
|
||||
key: "pit_owner_phone",
|
||||
ellipsis: true,
|
||||
render: (text, record) => {
|
||||
return record.pit_owner_phone ? (
|
||||
<span>
|
||||
<PhoneFormatter>{record.pit_owner_phone}</PhoneFormatter>
|
||||
<Icon
|
||||
style={{ margin: 4 }}
|
||||
type='message'
|
||||
onClick={() => {
|
||||
alert("SMSing will happen here.");
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
t("general.labels.unknown")
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a, b),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
ellipsis: true,
|
||||
render: (text, record) => {
|
||||
return record.job_status?.name ?? "";
|
||||
return record.job_status?.name ?? t("general.labels.na");
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: "Customer",
|
||||
dataIndex: "customer",
|
||||
key: "customer",
|
||||
render: (text, record) => {
|
||||
return record.owner ? (
|
||||
<div>
|
||||
{record.owner.first_name} {record.owner.last_name}
|
||||
</div>
|
||||
) : (
|
||||
"No Customer"
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Vehicle",
|
||||
title: t("jobs.fields.vehicle"),
|
||||
dataIndex: "vehicle",
|
||||
key: "vehicle",
|
||||
ellipsis: true,
|
||||
render: (text, record) => {
|
||||
return record.vehicle ? (
|
||||
<div>
|
||||
<Link to={"manage/vehicles/" + record.vehicle.id}>
|
||||
{record.vehicle.v_model_yr} {record.vehicle.v_make_desc}{" "}
|
||||
{record.vehicle.v_model_desc}
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
"No Vehicle"
|
||||
t("jobs.errors.novehicle")
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Action",
|
||||
key: "action",
|
||||
render: (text, record) => (
|
||||
<Dropdown overlay={actionMenu} trigger={["click"]}>
|
||||
<Icon type="ellipsis" />
|
||||
</Dropdown>
|
||||
)
|
||||
title: t("vehicles.fields.plate_no"),
|
||||
dataIndex: "plate_no",
|
||||
key: "plate_no",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a, b),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.vehicle?.plate_no ? (
|
||||
<span>{record.vehicle.plate_no}</span>
|
||||
) : (
|
||||
t("general.labels.unknown")
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.clm_no"),
|
||||
dataIndex: "clm_no",
|
||||
key: "clm_no",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a, b),
|
||||
sortOrder:
|
||||
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.clm_total"),
|
||||
dataIndex: "clm_total",
|
||||
key: "clm_total",
|
||||
sorter: (a, b) => {
|
||||
return a > b;
|
||||
},
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.clm_total ? (
|
||||
<span>{record.clm_total}</span>
|
||||
) : (
|
||||
t("general.labels.unknown")
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.owner_owing"),
|
||||
dataIndex: "owner_owing",
|
||||
key: "owner_owing",
|
||||
render: (text, record) => {
|
||||
return record.owner_owing ? (
|
||||
<span>{record.owner_owing}</span>
|
||||
) : (
|
||||
t("general.labels.unknown")
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -140,19 +190,22 @@ export default function JobsPage({
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Input.Search
|
||||
placeholder="Search..."
|
||||
onSearch={value => console.log(value)}
|
||||
enterButton
|
||||
/>
|
||||
<br />
|
||||
|
||||
<div className='jobs-list'>
|
||||
<Table
|
||||
loading={loading}
|
||||
title={() => {
|
||||
return (
|
||||
<Input.Search
|
||||
placeholder='Search...'
|
||||
onSearch={value => console.log(value)}
|
||||
enterButton
|
||||
/>
|
||||
);
|
||||
}}
|
||||
size='small'
|
||||
pagination={{ position: "top" }}
|
||||
columns={columns.map(item => ({ ...item }))}
|
||||
rowKey="id"
|
||||
rowKey='id'
|
||||
dataSource={jobs}
|
||||
rowSelection={{ selectedRowKeys: [selectedJob] }}
|
||||
onChange={handleTableChange}
|
||||
|
||||
4
client/src/components/jobs-list/jobs-list.styles.scss
Normal file
4
client/src/components/jobs-list/jobs-list.styles.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
.jobs-list{
|
||||
text-align: center;
|
||||
height: 40vh;
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import React from 'react'
|
||||
import './loading-skeleton.styles.scss'
|
||||
import React from "react";
|
||||
import "./loading-skeleton.styles.scss";
|
||||
|
||||
import { Skeleton } from "antd";
|
||||
|
||||
export default function LoadingSkeleton() {
|
||||
return (
|
||||
<Skeleton className="loading-skeleton" active/>
|
||||
)
|
||||
export default function LoadingSkeleton(props) {
|
||||
return <Skeleton {...props} className='loading-skeleton' active />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Input, Modal, Switch } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation } from "react-apollo";
|
||||
import { INSERT_NEW_NOTE } from "../../graphql/notes.queries";
|
||||
|
||||
export default function NoteAddModal({ jobId, visible, changeVisibility }) {
|
||||
const [newNote, setnewNote] = useState({
|
||||
private: false,
|
||||
critical: false,
|
||||
text: ""
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const [insertNote] = useMutation(INSERT_NEW_NOTE);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title='Basic Modal'
|
||||
visible={visible}
|
||||
okText='Save'
|
||||
onOk={() => {
|
||||
insertNote({
|
||||
variables: {
|
||||
noteInput: [
|
||||
{ ...newNote, jobid: jobId, created_by: "patrick@bodyshop.app" }
|
||||
]
|
||||
}
|
||||
}).then(r => {
|
||||
setnewNote({
|
||||
private: false,
|
||||
critical: false,
|
||||
text: ""
|
||||
});
|
||||
});
|
||||
|
||||
changeVisibility(!visible);
|
||||
}}
|
||||
onCancel={() => {
|
||||
changeVisibility(!visible);
|
||||
setnewNote({
|
||||
private: false,
|
||||
critical: false,
|
||||
text: ""
|
||||
});
|
||||
}}>
|
||||
<div>
|
||||
{t("notes.fields.critical")}
|
||||
<Switch
|
||||
title={t("notes.fields.critical")}
|
||||
onChange={checked => {
|
||||
setnewNote({ ...newNote, critical: checked });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{t("notes.fields.private")}
|
||||
<Switch
|
||||
title={t("notes.fields.private")}
|
||||
onChange={checked => {
|
||||
setnewNote({ ...newNote, private: checked });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Input.TextArea
|
||||
rows={8}
|
||||
defaultValue={newNote.text}
|
||||
placeholder={t("notes.labels.newnoteplaceholder")}
|
||||
onChange={e => {
|
||||
setnewNote({ ...newNote, text: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user