Further UI Updates

This commit is contained in:
Patrick Fic
2021-03-29 17:08:52 -07:00
parent 17264ff7d6
commit 6c34b8839c
78 changed files with 1250 additions and 1024 deletions

View File

@@ -9207,6 +9207,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>status</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>usage</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>vehicle</name>
<definition_loaded>false</definition_loaded>
@@ -24132,6 +24174,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>relatedjobs</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>updateowner</name>
<definition_loaded>false</definition_loaded>
@@ -29159,6 +29222,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>timetickets</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -31765,6 +31849,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>relatedjobs</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>updatevehicle</name>
<definition_loaded>false</definition_loaded>

View File

@@ -168,7 +168,6 @@ export default function AccountingPayablesTableComponent({ loading, bills }) {
);
}}
dataSource={dataSource}
size="small"
pagination={{ position: "top", pageSize: 50 }}
columns={columns}
rowKey="id"

View File

@@ -175,7 +175,6 @@ export default function AccountingPayablesTableComponent({
);
}}
dataSource={dataSource}
size="small"
pagination={{ position: "top", pageSize: 50 }}
columns={columns}
rowKey="id"

View File

@@ -189,7 +189,6 @@ export default function AccountingReceivablesTableComponent({ loading, jobs }) {
);
}}
dataSource={dataSource}
size="small"
pagination={{ position: "top" }}
columns={columns}
rowKey="id"

View File

@@ -8,7 +8,7 @@ import AuditTrailValuesComponent from "../audit-trail-values/audit-trail-values.
export default function AuditTrailListComponent({ loading, data }) {
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {}
filteredInfo: {},
});
const { t } = useTranslation();
const columns = [
@@ -22,7 +22,7 @@ export default function AuditTrailListComponent({ loading, data }) {
),
sorter: (a, b) => a.created - b.created,
sortOrder:
state.sortedInfo.columnKey === "created" && state.sortedInfo.order
state.sortedInfo.columnKey === "created" && state.sortedInfo.order,
},
{
title: t("audit.fields.operation"),
@@ -31,7 +31,7 @@ export default function AuditTrailListComponent({ loading, data }) {
width: "10%",
sorter: (a, b) => alphaSort(a.operation, b.operation),
sortOrder:
state.sortedInfo.columnKey === "operation" && state.sortedInfo.order
state.sortedInfo.columnKey === "operation" && state.sortedInfo.order,
},
{
title: t("audit.fields.values"),
@@ -43,7 +43,7 @@ export default function AuditTrailListComponent({ loading, data }) {
oldV={record.old_val}
newV={record.new_val}
/>
)
),
},
{
title: t("audit.fields.useremail"),
@@ -52,19 +52,19 @@ export default function AuditTrailListComponent({ loading, data }) {
width: "10%",
sorter: (a, b) => alphaSort(a.useremail, b.useremail),
sortOrder:
state.sortedInfo.columnKey === "useremail" && state.sortedInfo.order
}
state.sortedInfo.columnKey === "useremail" && state.sortedInfo.order,
},
];
const formItemLayout = {
labelCol: {
xs: { span: 12 },
sm: { span: 5 }
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 }
}
sm: { span: 12 },
},
};
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
@@ -74,9 +74,8 @@ export default function AuditTrailListComponent({ loading, data }) {
<Table
{...formItemLayout}
loading={loading}
size="small"
pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns.map(item => ({ ...item }))}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={data}
onChange={handleTableChange}

View File

@@ -1,12 +1,15 @@
import { SyncOutlined } from "@ant-design/icons";
import { EyeFilled, SyncOutlined } from "@ant-design/icons";
import {
Button,
Card,
Checkbox,
Descriptions,
Drawer,
Grid,
Input,
PageHeader,
Space,
Table,
Typography,
} from "antd";
import queryString from "query-string";
import React, { useState } from "react";
@@ -45,7 +48,21 @@ export function BillsListTableComponent({
}) {
const { t } = useTranslation();
const [selectedBillLinesByBill, setSelectedBillLinesByBill] = useState({});
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
const bpoints = {
xs: "100%",
sm: "100%",
md: "100%",
lg: "75%",
xl: "75%",
xxl: "65%",
};
const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]]
: "100%";
const [state, setState] = useState({
sortedInfo: {},
});
@@ -54,6 +71,34 @@ export function BillsListTableComponent({
const Templates = TemplateList("bill");
const bills = billsQuery.data ? billsQuery.data.bills : [];
const { refetch } = billsQuery;
const recordActions = (record, showView = false) => (
<Space wrap>
{showView && (
<Button onClick={() => handleOnRowClick(record)}>
<EyeFilled />
</Button>
)}
{record.exported ? (
<Button disabled>{t("bills.actions.edit")}</Button>
) : (
<Link
to={`/manage/bills?billid=${record.id}&vendorid=${record.vendorid}`}
>
<Button>{t("bills.actions.edit")}</Button>
</Link>
)}
<BillDeleteButton bill={record} />
{record.isinhouse && (
<PrintWrapperComponent
templateObject={{
name: Templates.inhouse_invoice.key,
variables: { id: record.id },
}}
messageObject={{ subject: Templates.inhouse_invoice.subject }}
/>
)}
</Space>
);
const columns = [
{
title: t("bills.fields.vendorname"),
@@ -116,31 +161,10 @@ export function BillsListTableComponent({
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Space wrap>
{record.exported ? (
<Button disabled>{t("bills.actions.edit")}</Button>
) : (
<Link
to={`/manage/bills?billid=${record.id}&vendorid=${record.vendorid}`}
>
<Button>{t("bills.actions.edit")}</Button>
</Link>
)}
<BillDeleteButton bill={record} />
{record.isinhouse && (
<PrintWrapperComponent
templateObject={{
name: Templates.inhouse_invoice.key,
variables: { id: record.id },
}}
messageObject={{ subject: Templates.inhouse_invoice.subject }}
/>
)}
</Space>
),
render: (text, record) => recordActions(record, true),
},
];
const selectedBillRecord = bills.find((r) => r.id === selectedBill);
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
@@ -240,7 +264,6 @@ export function BillsListTableComponent({
),
},
];
const handleOnBillrowclick = (selectedRows) => {
setSelectedBillLinesByBill({
...selectedBillLinesByBill,
@@ -249,10 +272,14 @@ export function BillsListTableComponent({
};
return (
<div>
<Typography.Title level={3}>{`${t("bills.fields.invoice_number")} ${
record.invoice_number
}`}</Typography.Title>
<>
<PageHeader
title={
record &&
`${t("bills.fields.invoice_number")} ${record.invoice_number}`
}
extra={recordActions(record)}
/>
<Descriptions>
<Descriptions.Item label={t("bills.fields.federal_tax_rate")}>
{`${record.federal_tax_rate}%` || ""}
@@ -301,9 +328,7 @@ export function BillsListTableComponent({
{t("bills.actions.return")}
</Button>
<Table
size="small"
scroll={{ x: "50%", y: "40rem" }}
pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns}
rowKey="id"
dataSource={record.billlines}
@@ -318,94 +343,77 @@ export function BillsListTableComponent({
type: "checkbox",
}}
/>
</div>
</>
);
};
return (
<div>
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<Card
title={t("bills.labels.bills")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
{job ? (
<>
<Button
onClick={() => {
setBillEnterContext({
actions: { refetch: billsQuery.refetch },
context: {
job,
},
});
}}
>
{t("jobs.actions.postbills")}
</Button>
<Button
onClick={() => {
setReconciliationContext({
actions: { refetch: billsQuery.refetch },
context: {
job,
bills: (billsQuery.data && billsQuery.data.bills) || [],
},
});
}}
>
{t("jobs.actions.reconcile")}
</Button>
</>
) : null}
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
e.preventDefault();
}}
/>
</Space>
}
>
<Drawer
placement="right"
onClose={() => handleOnRowClick(null)}
visible={selectedBill}
//getContainer={false}
style={{ position: "absolute" }}
closable
width={drawerPercentage}
>
{selectedBillRecord && rowExpander(selectedBillRecord)}
</Drawer>
<Table
loading={billsQuery.loading}
size="small"
title={() => (
<div className="imex-table-header">
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
{job ? (
<div>
<Button
onClick={() => {
setBillEnterContext({
actions: { refetch: billsQuery.refetch },
context: {
job,
},
});
}}
>
{t("jobs.actions.postbills")}
</Button>
<Button
onClick={() => {
setReconciliationContext({
actions: { refetch: billsQuery.refetch },
context: {
job,
bills: (billsQuery.data && billsQuery.data.bills) || [],
},
});
}}
>
{t("jobs.actions.reconcile")}
</Button>
</div>
) : null}
<div className="imex-table-header__search">
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
e.preventDefault();
}}
/>
</div>
</div>
)}
scroll={{ x: "50%", y: "40rem" }}
expandedRowRender={rowExpander}
pagination={{ position: "top", defaultPageSize: 25 }}
scroll={{ x: true, y: "50rem" }}
columns={columns}
rowKey="id"
dataSource={bills}
onChange={handleTableChange}
expandable={{
expandedRowKeys: [selectedBill],
onExpand: (expanded, record) => {
handleOnRowClick(expanded ? record : null);
},
}}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selectedBill],
type: "radio",
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
}, // click row
onDoubleClick: (event) => {}, // double click row
onContextMenu: (event) => {}, // right button click row
onMouseEnter: (event) => {}, // mouse enter row
onMouseLeave: (event) => {}, // mouse leave row
};
}}
/>
</div>
</Card>
);
}
export default connect(

View File

@@ -95,7 +95,6 @@ export default function BillsVendorsList() {
);
}}
dataSource={dataSource}
size="small"
pagination={{ position: "top" }}
columns={columns}
rowKey="id"

View File

@@ -29,7 +29,6 @@ export function ChatConversationListComponent({
<div className="chat-list-container">
<List
bordered
size="small"
dataSource={conversationList}
renderItem={(item) => (
<List.Item

View File

@@ -77,10 +77,7 @@ export function ChatMediaSelector({
visible={visible}
onVisibleChange={handleVisibleChange}
>
<Badge
size="small"
count={selectedMedia.filter((s) => s.isSelected).length}
>
<Badge count={selectedMedia.filter((s) => s.isSelected).length}>
<PictureFilled style={{ margin: "0 .5rem" }} />
</Badge>
</Popover>

View File

@@ -106,7 +106,6 @@ export default function ContractsCarsComponent({
onChange={(e) => setState({ ...state, search: e.target.value })}
/>
)}
size="small"
pagination={{ position: "top" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"

View File

@@ -7,7 +7,7 @@ export default function ContractCourtesyCarBlock({ courtesyCar }) {
return (
<Link to={`/manage/courtesycars/${courtesyCar && courtesyCar.id}`}>
<Card title={t("courtesycars.labels.courtesycar")}>
<Descriptions size="small" column={1}>
<Descriptions column={1}>
<Descriptions.Item label={t("courtesycars.fields.fleetnumber")}>
{(courtesyCar && courtesyCar.fleetnumber) || ""}
</Descriptions.Item>
@@ -15,9 +15,9 @@ export default function ContractCourtesyCarBlock({ courtesyCar }) {
{(courtesyCar && courtesyCar.plate) || ""}
</Descriptions.Item>
<Descriptions.Item label={t("courtesycars.labels.vehicle")}>
{`${(courtesyCar && courtesyCar.year) || ""} ${(courtesyCar &&
courtesyCar.make) ||
""} ${(courtesyCar && courtesyCar.model) || ""}`}
{`${(courtesyCar && courtesyCar.year) || ""} ${
(courtesyCar && courtesyCar.make) || ""
} ${(courtesyCar && courtesyCar.model) || ""}`}
</Descriptions.Item>
</Descriptions>
</Card>

View File

@@ -8,17 +8,19 @@ export default function ContractJobBlock({ job }) {
return (
<Link to={`/manage/jobs/${job && job.id}`}>
<Card title={t("jobs.labels.job")}>
<Descriptions size="small" column={1}>
<Descriptions column={1}>
<Descriptions.Item label={t("jobs.fields.ro_number")}>
{(job && job.ro_number) || ""}
</Descriptions.Item>
<Descriptions.Item label={t("jobs.fields.vehicle")}>
{`${(job && job.v_model_yr) || ""} ${(job && job.v_make_desc) ||
""} ${(job && job.v_model_desc) || ""}`}
{`${(job && job.v_model_yr) || ""} ${
(job && job.v_make_desc) || ""
} ${(job && job.v_model_desc) || ""}`}
</Descriptions.Item>
<Descriptions.Item label={t("jobs.fields.owner")}>
{`${(job && job.ownr_fn) || ""} ${(job && job.ownr_ln) ||
""} ${(job && job.ownr_co_nm) || ""}`}
{`${(job && job.ownr_fn) || ""} ${(job && job.ownr_ln) || ""} ${
(job && job.ownr_co_nm) || ""
}`}
</Descriptions.Item>
</Descriptions>
</Card>

View File

@@ -179,7 +179,6 @@ export default function ContractsJobsComponent({
onChange={(e) => setState({ ...state, search: e.target.value })}
/>
)}
size="small"
pagination={{
position: "top",
defaultPageSize: 3,

View File

@@ -144,7 +144,6 @@ export default function ContractsList({ loading, contracts, refetch, total }) {
</div>
</div>
)}
size="small"
scroll={{ x: "50%", y: "40rem" }}
pagination={{
position: "top",

View File

@@ -1,4 +1,4 @@
import { Table } from "antd";
import { Card, Table } from "antd";
import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -84,19 +84,20 @@ export default function CourtesyCarContractListComponent({
};
return (
<Table
size="small"
scroll={{ x: true }}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: totalContracts,
}}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={contracts}
onChange={handleTableChange}
/>
<Card title={t("menus.header.courtesycars-contracts")}>
<Table
scroll={{ x: true }}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: totalContracts,
}}
columns={columns}
rowKey="id"
dataSource={contracts}
onChange={handleTableChange}
/>
</Card>
);
}

View File

@@ -1,4 +1,4 @@
import { Button, Form, Input, InputNumber } from "antd";
import { Button, Form, Input, InputNumber, PageHeader } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
@@ -13,15 +13,21 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
const { t } = useTranslation();
return (
<div>
<Button
type="primary"
loading={saveLoading}
onClick={() => form.submit()}
>
{t("general.actions.save")}
</Button>
<PageHeader
title={t("menus.header.courtesycars")}
extra={
<Button
type="primary"
loading={saveLoading}
onClick={() => form.submit()}
>
{t("general.actions.save")}
</Button>
}
/>
<FormFieldsChanged form={form} />
<LayoutFormRow>
<LayoutFormRow header={t("courtesycars.labels.vehicle")}>
<Form.Item
label={t("courtesycars.fields.make")}
name="make"
@@ -95,7 +101,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
<Input />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow>
<LayoutFormRow header={t("courtesycars.labels.usage")}>
<Form.Item
label={t("courtesycars.fields.mileage")}
name="mileage"
@@ -139,19 +145,21 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
<FormDatePicker />
</Form.Item>
</LayoutFormRow>
<Form.Item
label={t("courtesycars.fields.fuel")}
name="fuel"
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<CourtesyCarFuelSlider />
</Form.Item>
<LayoutFormRow>
<LayoutFormRow header={t("courtesycars.labels.status")}>
<Form.Item
span={24}
label={t("courtesycars.fields.fuel")}
name="fuel"
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<CourtesyCarFuelSlider />
</Form.Item>
<Form.Item
label={t("courtesycars.fields.status")}
name="status"

View File

@@ -1,4 +1,4 @@
import { Table, Button, Input } from "antd";
import { Table, Button, Input, Card, Space } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
@@ -118,10 +118,10 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
)
: courtesycars;
return (
<Table
loading={loading}
title={() => (
<div className="imex-table-header">
<Card
title={t("menus.header.courtesycars")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
@@ -137,14 +137,17 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
value={searchText}
enterButton
/>
</div>
)}
size="small"
pagination={{ position: "top" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={tableData}
onChange={handleTableChange}
/>
</Space>
}
>
<Table
loading={loading}
pagination={{ position: "top" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={tableData}
onChange={handleTableChange}
/>
</Card>
);
}

View File

@@ -118,7 +118,6 @@ export default function CsiResponseListPaginated({
</div>
);
}}
size="small"
pagination={{
position: "top",
pageSize: 25,

View File

@@ -14,7 +14,7 @@ import Icon, {
UnorderedListOutlined,
UserOutlined,
} from "@ant-design/icons";
import { Menu } from "antd";
import { Layout, Menu } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { BsKanban } from "react-icons/bs";
@@ -67,10 +67,11 @@ function Header({
const { t } = useTranslation();
return (
<div style={{ display: "flex", alignContent: "center" }}>
<Layout.Header>
<Menu
mode="horizontal"
theme="light"
//theme="light"
theme={"dark"}
style={{ flex: 5 }}
selectedKeys={[selectedHeader]}
onClick={handleMenuClick}
@@ -351,7 +352,7 @@ function Header({
))}
</Menu.SubMenu>
</Menu>
</div>
</Layout.Header>
);
}

View File

@@ -1,4 +1,4 @@
import { Statistic } from "antd";
import { Card, Space, Statistic } from "antd";
import Dinero from "dinero.js";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -56,44 +56,46 @@ export default function JobBillsTotalComponent({ loading, bills, jobTotals }) {
const discrepWithCms = discrepWithLbrAdj.subtract(billCms);
return (
<div className="job-bills-totals-container">
<Statistic
title={t("jobs.labels.rosaletotal")}
value={totalPartsSublet.toFormat()}
/>
<Statistic
title={t("bills.labels.retailtotal")}
value={billTotals.toFormat()}
/>
<Statistic
title={t("bills.labels.discrepancy")}
valueStyle={{
color: discrepancy.getAmount === 0 ? "green" : "red",
}}
value={discrepancy.toFormat()}
/>
<Statistic
title={t("bills.labels.dedfromlbr")}
value={lbrAdjustments.toFormat()}
/>
<Statistic
title={t("bills.labels.discrepwithlbradj")}
valueStyle={{
color: discrepWithLbrAdj.getAmount === 0 ? "green" : "red",
}}
value={discrepWithLbrAdj.toFormat()}
/>
<Statistic
title={t("bills.labels.billcmtotal")}
value={billCms.toFormat()}
/>
<Statistic
title={t("bills.labels.discrepwithcms")}
valueStyle={{
color: discrepWithCms.getAmount === 0 ? "green" : "red",
}}
value={discrepWithCms.toFormat()}
/>
</div>
<Card title={t("jobs.labels.jobtotals")}>
<Space wrap size="large">
<Statistic
title={t("jobs.labels.rosaletotal")}
value={totalPartsSublet.toFormat()}
/>
<Statistic
title={t("bills.labels.retailtotal")}
value={billTotals.toFormat()}
/>
<Statistic
title={t("bills.labels.discrepancy")}
valueStyle={{
color: discrepancy.getAmount === 0 ? "green" : "red",
}}
value={discrepancy.toFormat()}
/>
<Statistic
title={t("bills.labels.dedfromlbr")}
value={lbrAdjustments.toFormat()}
/>
<Statistic
title={t("bills.labels.discrepwithlbradj")}
valueStyle={{
color: discrepWithLbrAdj.getAmount === 0 ? "green" : "red",
}}
value={discrepWithLbrAdj.toFormat()}
/>
<Statistic
title={t("bills.labels.billcmtotal")}
value={billCms.toFormat()}
/>
<Statistic
title={t("bills.labels.discrepwithcms")}
valueStyle={{
color: discrepWithCms.getAmount === 0 ? "green" : "red",
}}
value={discrepWithCms.toFormat()}
/>
</Space>
</Card>
);
}

View File

@@ -73,7 +73,6 @@ export default function JobCostingPartsTable({ job, data, summaryData }) {
return (
<div>
<Table
size="small"
title={() => {
return (
<div className="imex-table-header">

View File

@@ -26,7 +26,6 @@ export default function JobDetailCardsNotesComponent({ loading, data }) {
{data ? (
<Container>
<List
size="small"
bordered
dataSource={data.notes}
renderItem={(item) => (

View File

@@ -62,16 +62,6 @@ export function JobLinesComponent({
sortOrder:
state.sortedInfo.columnKey === "line_no" && state.sortedInfo.order,
},
{
title: t("joblines.fields.line_ind"),
dataIndex: "line_ind",
key: "line_ind",
fixed: "left",
sorter: (a, b) => alphaSort(a.line_ind, b.line_ind),
sortOrder:
state.sortedInfo.columnKey === "line_ind" && state.sortedInfo.order,
responsive: ["md"],
},
{
title: t("joblines.fields.line_desc"),
dataIndex: "line_desc",
@@ -192,6 +182,15 @@ export function JobLinesComponent({
sortOrder:
state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
},
{
title: t("joblines.fields.line_ind"),
dataIndex: "line_ind",
key: "line_ind",
sorter: (a, b) => alphaSort(a.line_ind, b.line_ind),
sortOrder:
state.sortedInfo.columnKey === "line_ind" && state.sortedInfo.order,
responsive: ["md"],
},
{
title: t("joblines.fields.notes"),
dataIndex: "notes",

View File

@@ -88,7 +88,6 @@ export default function JobReconciliationBillsTable({
return (
<div>
<Table
size="small"
pagination={false}
scroll={{ y: "40vh", x: true }}
columns={columns}

View File

@@ -104,7 +104,6 @@ export default function JobReconcilitionPartsTable({
return (
<div>
<Table
size="small"
pagination={false}
columns={columns}
scroll={{ y: "40vh", x: true }}

View File

@@ -87,7 +87,6 @@ export default function JobTotalsTableLabor({ job }) {
];
const handleTableChange = (pagination, filters, sorter) => {
console.log("sorter :>> ", sorter);
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
return (

View File

@@ -1,5 +1,5 @@
import { DownloadOutlined, SyncOutlined } from "@ant-design/icons";
import { Button, Input, notification, Space, Table } from "antd";
import { Button, Card, Input, notification, Space, Table } from "antd";
import axios from "axios";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
@@ -37,9 +37,11 @@ export function JobsAvailableScan({ partnerVersion, refetch }) {
});
if (response.data.success) {
//Came through
if(refetch) refetch()
if (refetch) refetch();
} else {
notification["error"]({ message: t("jobs.errors.scanimport", {message: response.data.error}) });
notification["error"]({
message: t("jobs.errors.scanimport", { message: response.data.error }),
});
}
setLoading(false);
};
@@ -120,40 +122,37 @@ export function JobsAvailableScan({ partnerVersion, refetch }) {
: [];
return (
<Table
loading={loading}
title={() => {
return (
<div className="imex-table-header">
<Space>
<strong>{t("jobs.labels.diskscan")}</strong>
<Button
loading={loading}
disabled={!partnerVersion}
onClick={() => {
scanEstimates();
}}
>
<SyncOutlined />
</Button>
</Space>
<div className="imex-table-header__search">
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.currentTarget.value);
}}
/>
</div>
</div>
);
}}
size="small"
pagination={{ position: "top" }}
columns={columns}
rowKey="id"
dataSource={data}
onChange={handleTableChange}
/>
<Card
title={t("jobs.labels.diskscan")}
extra={
<Space wrap>
<Button
loading={loading}
disabled={!partnerVersion}
onClick={() => {
scanEstimates();
}}
>
<SyncOutlined />
</Button>
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.currentTarget.value);
}}
/>
</Space>
}
>
<Table
loading={loading}
pagination={{ position: "top" }}
columns={columns}
rowKey="id"
dataSource={data}
onChange={handleTableChange}
/>
</Card>
);
}

View File

@@ -5,7 +5,7 @@ import {
SyncOutlined,
} from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { Button, Input, notification, Space, Table } from "antd";
import { Button, Card, Input, notification, Space, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
@@ -176,58 +176,54 @@ export default function JobsAvailableComponent({
: [];
return (
<Table
loading={loading}
title={() => {
return (
<div className="imex-table-header">
<Space>
<strong>{t("jobs.labels.availablejobs")}</strong>
<Button
onClick={() => {
<Card
title={t("jobs.labels.availablejobs")}
extra={
<Space wrap>
<Button
onClick={() => {
refetch();
}}
>
<SyncOutlined />
</Button>
<Button
onClick={() => {
deleteAllAvailableJobs()
.then((r) => {
notification["success"]({
message: t("jobs.successes.all_deleted", {
count: r.data.delete_available_jobs.affected_rows,
}),
});
refetch();
}}
>
<SyncOutlined />
</Button>
<Button
onClick={() => {
deleteAllAvailableJobs()
.then((r) => {
notification["success"]({
message: t("jobs.successes.all_deleted", {
count: r.data.delete_available_jobs.affected_rows,
}),
});
refetch();
})
.catch((r) => {
notification["error"]({
message: t("jobs.errors.deleted") + " " + r.message,
});
});
}}
>
{t("general.actions.deleteall")}
</Button>
</Space>
<div className="imex-table-header__search">
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.currentTarget.value);
}}
/>
</div>
</div>
);
}}
size="small"
pagination={{ position: "top" }}
columns={columns}
rowKey="id"
dataSource={availableJobs}
onChange={handleTableChange}
/>
})
.catch((r) => {
notification["error"]({
message: t("jobs.errors.deleted") + " " + r.message,
});
});
}}
>
{t("general.actions.deleteall")}
</Button>
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.currentTarget.value);
}}
/>
</Space>
}
>
<Table
loading={loading}
columns={columns}
rowKey="id"
dataSource={availableJobs}
onChange={handleTableChange}
/>
</Card>
);
}

View File

@@ -5,7 +5,7 @@ import {
useMutation,
useQuery,
} from "@apollo/client";
import { notification } from "antd";
import { Col, notification, Row } from "antd";
import Axios from "axios";
import Dinero from "dinero.js";
import _ from "lodash";
@@ -354,14 +354,20 @@ export function JobsAvailableContainer({ bodyshop, currentUser }) {
onCancel={onJobModalCancel}
modalSearchState={modalSearchState}
/>
<JobsAvailableTableComponent
loading={loading}
data={data}
refetch={refetch}
addJobAsNew={addJobAsNew}
addJobAsSupp={addJobAsSupp}
/>
<JobsAvailableScan refetch={refetch} />
<Row gutter={[16, 16]}>
<Col span={24}>
<JobsAvailableTableComponent
loading={loading}
data={data}
refetch={refetch}
addJobAsNew={addJobAsNew}
addJobAsSupp={addJobAsSupp}
/>
</Col>
<Col span={24}>
<JobsAvailableScan refetch={refetch} />
</Col>
</Row>
</LoadingSpinner>
);
}

View File

@@ -110,7 +110,6 @@ export default function JobsCreateOwnerInfoSearchComponent({
</div>
);
}}
size="small"
scroll={{ x: true }}
pagination={{ position: "top" }}
columns={columns}

View File

@@ -74,7 +74,6 @@ export default function JobsCreateVehicleInfoSearchComponent({
</div>
);
}}
size="small"
scroll={{ x: true }}
pagination={{ position: "top" }}
columns={columns}

View File

@@ -1,10 +1,9 @@
import { Col, Row } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import LaborAllocationsTableComponent from "../labor-allocations-table/labor-allocations-table.component";
import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component";
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
const mapStateToProps = createStructuredSelector({
@@ -13,6 +12,41 @@ const mapStateToProps = createStructuredSelector({
export default connect(mapStateToProps, null)(JobsDetailLaborContainer);
const ticketSpan = {
xs: {
span: 24,
},
sm: {
span: 24,
},
md: {
span: 24,
},
lg: {
span: 24,
},
xl: {
span: 16,
},
};
const adjSpan = {
xs: {
span: 24,
},
sm: {
span: 24,
},
md: {
span: 24,
},
lg: {
span: 24,
},
xl: {
span: 8,
},
};
export function JobsDetailLaborContainer({
jobRO,
jobId,
@@ -23,27 +57,26 @@ export function JobsDetailLaborContainer({
techConsole,
adjustments,
}) {
const { t } = useTranslation();
return (
<div>
{techConsole ? null : (
<TimeTicketEnterButton actions={{ refetch }} context={{ jobId: jobId }}>
{t("timetickets.actions.enter")}
</TimeTicketEnterButton>
)}
<LaborAllocationsTableComponent
jobId={jobId}
joblines={joblines}
timetickets={timetickets}
adjustments={adjustments}
/>
<TimeTicketList
loading={loading}
timetickets={timetickets}
refetch={refetch}
techConsole={techConsole}
disabled={jobRO}
/>
</div>
<Row gutter={[16, 16]}>
<Col {...ticketSpan}>
<TimeTicketList
loading={loading}
timetickets={timetickets}
refetch={refetch}
techConsole={techConsole}
disabled={jobRO}
jobId={jobId}
/>
</Col>
<Col {...adjSpan}>
<LaborAllocationsTableComponent
jobId={jobId}
joblines={joblines}
timetickets={timetickets}
adjustments={adjustments}
/>
</Col>
</Row>
);
}

View File

@@ -3,25 +3,8 @@ import React from "react";
import AlertComponent from "../alert/alert.component";
import BillsListTable from "../bills-list-table/bills-list-table.component";
import JobBillsTotal from "../job-bills-total/job-bills-total.component";
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
import PartsOrderListTableComponent from "../parts-order-list-table/parts-order-list-table.component";
const tableCol = {
xs: {
span: 24,
},
md: {
span: 20,
},
};
const totalsCol = {
xs: {
span: 24,
},
md: {
span: 4,
},
};
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
export default function JobsDetailPliComponent({
job,
@@ -35,26 +18,29 @@ export default function JobsDetailPliComponent({
{billsQuery.error ? (
<AlertComponent message={billsQuery.error.message} type="error" />
) : null}
<Row>
<Col {...tableCol}>
<PartsOrderListTableComponent
job={job}
handleOnRowClick={handlePartsOrderOnRowClick}
billsQuery={billsQuery}
/>
<BillsListTable
job={job}
handleOnRowClick={handleBillOnRowClick}
billsQuery={billsQuery}
/>
</Col>
<Col {...totalsCol}>
<Row gutter={[16, 16]}>
<Col span={24}>
<JobBillsTotal
bills={billsQuery.data ? billsQuery.data.bills : []}
loading={billsQuery.loading}
jobTotals={job.job_totals}
/>
</Col>
<Col span={24}>
<PartsOrderListTableComponent
job={job}
handleOnRowClick={handlePartsOrderOnRowClick}
billsQuery={billsQuery}
/>
</Col>
<Col span={24}>
<BillsListTable
job={job}
handleOnRowClick={handleBillOnRowClick}
billsQuery={billsQuery}
/>
</Col>
</Row>
</div>
);

View File

@@ -1,5 +1,5 @@
import { FileExcelFilled } from "@ant-design/icons";
import { Card } from "antd";
import { Card, Col, Row, Space } from "antd";
import React, { useEffect, useState } from "react";
import Gallery from "react-grid-gallery";
import { useTranslation } from "react-i18next";
@@ -104,78 +104,87 @@ function JobsDocumentsComponent({
}, [data, setgalleryImages, t]);
return (
<div className="clearfix">
<div className="imex-flex-row">
<JobsDocumentsGallerySelectAllComponent
galleryImages={galleryImages}
setGalleryImages={setgalleryImages}
/>
<JobsDocumentsDownloadButton galleryImages={galleryImages} />
<JobsDocumentsDeleteButton
galleryImages={galleryImages}
deletionCallback={billsCallback || refetch}
/>
<JobsDocumentsGalleryReassign galleryImages={galleryImages} />
</div>
<DocumentsUploadComponent
jobId={jobId}
billId={billId}
callbackAfterUpload={billsCallback || refetch}
tagsArray={["test"]}
></DocumentsUploadComponent>
<div style={{ marginTop: "2rem" }}>
<Card title={t("jobs.labels.documents-images")}>
<Gallery
images={galleryImages.images}
backdropClosesModal={true}
onClickImage={(props) => {
window.open(
props.target.src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index, image) => {
setgalleryImages({
...galleryImages,
images: galleryImages.images.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
),
});
}}
/>
</Card>
<div className="clea rfix">
<Row gutter={[16, 16]}>
<Col span={24}>
<Space wrap>
<JobsDocumentsGallerySelectAllComponent
galleryImages={galleryImages}
setGalleryImages={setgalleryImages}
/>
<JobsDocumentsDownloadButton galleryImages={galleryImages} />
<JobsDocumentsDeleteButton
galleryImages={galleryImages}
deletionCallback={billsCallback || refetch}
/>
<JobsDocumentsGalleryReassign galleryImages={galleryImages} />
</Space>
</Col>
<Col span={24}>
<Card>
<DocumentsUploadComponent
jobId={jobId}
billId={billId}
callbackAfterUpload={billsCallback || refetch}
/>
</Card>
</Col>
<Card title={t("jobs.labels.documents-other")}>
<Gallery
images={galleryImages.other}
backdropClosesModal={true}
enableLightbox={false}
thumbnailStyle={() => {
return {
backgroundImage: <FileExcelFilled />,
height: "100%",
width: "100%",
};
}}
onClickThumbnail={(index) => {
window.open(
galleryImages.other[index].src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index) => {
setgalleryImages({
...galleryImages,
other: galleryImages.other.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
),
});
}}
/>
</Card>
</div>
<Col span={24}>
<Card title={t("jobs.labels.documents-images")}>
<Gallery
images={galleryImages.images}
backdropClosesModal={true}
onClickImage={(props) => {
window.open(
props.target.src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index, image) => {
setgalleryImages({
...galleryImages,
images: galleryImages.images.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
),
});
}}
/>
</Card>
</Col>
<Col span={24}>
<Card title={t("jobs.labels.documents-other")}>
<Gallery
images={galleryImages.other}
backdropClosesModal={true}
enableLightbox={false}
thumbnailStyle={() => {
return {
backgroundImage: <FileExcelFilled />,
height: "100%",
width: "100%",
};
}}
onClickThumbnail={(index) => {
window.open(
galleryImages.other[index].src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index) => {
setgalleryImages({
...galleryImages,
other: galleryImages.other.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
),
});
}}
/>
</Card>
</Col>
</Row>
</div>
);
}

View File

@@ -1,4 +1,4 @@
import { Button } from "antd";
import { Button, Space } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -49,7 +49,7 @@ export default function JobsDocumentsGallerySelectAllComponent({
};
return (
<>
<Space wrap>
<Button onClick={handleSelectAll}>
{t("general.actions.selectall")}
</Button>
@@ -62,6 +62,6 @@ export default function JobsDocumentsGallerySelectAllComponent({
<Button onClick={handleDeselectAll}>
{t("general.actions.deselectall")}
</Button>
</>
</Space>
);
}

View File

@@ -155,7 +155,6 @@ export default function JobsFindModalComponent({
/>
</div>
)}
size="small"
pagination={{ position: "bottom" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"

View File

@@ -194,7 +194,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
<div>
<Table
loading={loading}
size="small"
scroll={{ x: true }}
pagination={{
position: "top",

View File

@@ -244,7 +244,6 @@ export function JobsList({ bodyshop }) {
>
<Table
loading={loading}
size="small"
pagination={false}
columns={columns}
rowKey="id"

View File

@@ -5,7 +5,7 @@ import {
EyeInvisibleFilled,
WarningFilled,
} from "@ant-design/icons";
import { Button, Table } from "antd";
import { Button, Card, Table } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -110,28 +110,32 @@ export function JobNotesComponent({
];
return (
<div>
<Card
title={t("jobs.labels.notes")}
extra={
<Button
onClick={() => {
setNoteUpsertContext({
actions: { refetch: refetch },
context: {
jobId: jobId,
},
});
}}
>
{t("notes.actions.new")}
</Button>
}
>
<NoteUpsertModal />
<Button
onClick={() => {
setNoteUpsertContext({
actions: { refetch: refetch },
context: {
jobId: jobId,
},
});
}}
>
{t("notes.actions.new")}
</Button>
<Table
loading={loading}
pagination={{ position: "bottom" }}
columns={columns}
rowKey="id"
dataSource={data}
/>
</div>
</Card>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(JobNotesComponent);

View File

@@ -1,10 +1,11 @@
import { EditFilled } from "@ant-design/icons";
import { Typography } from "antd";
import { Card, Space, Table } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { alphaSort } from "../../utils/sorters";
import LaborAllocationsAdjustmentEdit from "../labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component";
import "./labor-allocations-table.styles.scss";
import { CalculateAllocationsTotals } from "./labor-allocations-table.utility";
@@ -22,6 +23,15 @@ export function LaborAllocationsTable({
}) {
const { t } = useTranslation();
const [totals, setTotals] = useState([]);
const [state, setState] = useState({
sortedInfo: {
columnKey: "cost_center",
field: "cost_center",
order: "ascend",
},
filteredInfo: {},
});
useEffect(() => {
if (!!joblines && !!timetickets && !!bodyshop);
setTotals(
@@ -35,65 +45,92 @@ export function LaborAllocationsTable({
if (!jobId) setTotals([]);
}, [joblines, timetickets, bodyshop, adjustments, jobId]);
const columns = [
{
title: t("timetickets.fields.cost_center"),
dataIndex: "cost_center",
key: "cost_center",
defaultSortOrder: "cost_center",
sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
sortOrder:
state.sortedInfo.columnKey === "cost_center" && state.sortedInfo.order,
},
{
title: t("jobs.labels.hrs_total"),
dataIndex: "total",
key: "total",
sorter: (a, b) => a.total - b.total,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
render: (text, record) => record.total.toFixed(1),
},
{
title: t("jobs.labels.hrs_claimed"),
dataIndex: "hrs_claimed",
key: "hrs_claimed",
sorter: (a, b) => a.claimed - b.claimed,
sortOrder:
state.sortedInfo.columnKey === "claimed" && state.sortedInfo.order,
render: (text, record) => record.claimed && record.claimed.toFixed(1),
},
{
title: t("jobs.labels.adjustments"),
dataIndex: "adjustments",
key: "adjustments",
sorter: (a, b) => a.adjustments - b.adjustments,
sortOrder:
state.sortedInfo.columnKey === "adjustments" && state.sortedInfo.order,
render: (text, record) => (
<Space wrap>
{record.adjustments.toFixed(1)}
<LaborAllocationsAdjustmentEdit
jobId={jobId}
adjustments={adjustments}
mod_lbr_ty={record.opcode}
>
<EditFilled />
</LaborAllocationsAdjustmentEdit>
</Space>
),
},
{
title: t("jobs.labels.difference"),
dataIndex: "difference",
key: "difference",
sorter: (a, b) => a.difference - b.difference,
sortOrder:
state.sortedInfo.columnKey === "difference" && state.sortedInfo.order,
render: (text, record) => (
<strong
style={{
color: record.difference > 0 ? "green" : "red",
}}
>
{record.difference}
</strong>
),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
console.log("totals :>> ", totals);
return (
<div>
<div className="imex-flex-row" style={{ margin: ".5rem" }}>
<Typography.Title level={3}>
{t("jobs.labels.laborallocations")}
</Typography.Title>
<div className="labor-allocations-table">
<table>
<thead>
<tr>
<th>
<strong>{t("timetickets.fields.cost_center")}</strong>
</th>
<th>
<strong>{t("jobs.labels.hrs_total")}</strong>
</th>
<th>
<strong>{t("jobs.labels.hrs_claimed")}</strong>
</th>
<th>
<strong>{t("jobs.labels.adjustments")}</strong>
</th>
<th>
<strong>{t("jobs.labels.difference")}</strong>
</th>
</tr>
</thead>
<tbody>
{totals.map((t, idx) => (
<tr key={idx}>
<td>{t.cost_center}</td>
<td>{t.total.toFixed(1)}</td>
<td>{t.claimed.toFixed(1)}</td>
<td>
{t.adjustments.toFixed(1)}
<LaborAllocationsAdjustmentEdit
jobId={jobId}
adjustments={adjustments}
mod_lbr_ty={t.opcode}
>
<EditFilled style={{ marginLeft: ".2rem" }} />
</LaborAllocationsAdjustmentEdit>
</td>
<td>
<strong
style={{
color: t.difference > 0 ? "green" : "red",
}}
>
{t.difference}
</strong>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
<Card title={t("jobs.labels.laborallocations")}>
<Table
columns={columns}
rowKey="cost_center"
pagination={false}
onChange={handleTableChange}
dataSource={totals}
scroll={{
x: true,
}}
/>
</Card>
);
}
export default connect(mapStateToProps, null)(LaborAllocationsTable);

View File

@@ -1,4 +1,4 @@
import { Button, Form, Input, Switch } from "antd";
import { Form, Input, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
@@ -13,20 +13,7 @@ export default function OwnerDetailFormComponent({ form, loading }) {
const { getFieldValue } = form;
return (
<div>
<div className="imex-flex-row imex-flex-row__flex-space-around">
<Button
className="imex-flex-row__margin-large"
type="primary"
key="submit"
loading={loading}
htmlType="submit"
>
{t("general.actions.save")}
</Button>
<div className="imex-flex-row__grow imex-flex-row__margin-large">
<FormFieldsChanged form={form} />
</div>
</div>
<FormFieldsChanged form={form} />
<LayoutFormRow header={t("owners.forms.name")}>
<Form.Item label={t("owners.fields.ownr_title")} name="ownr_title">

View File

@@ -1,4 +1,4 @@
import { Form, notification } from "antd";
import { Button, Form, notification, PageHeader } from "antd";
import React, { useState } from "react";
import { useMutation } from "@apollo/client";
import { useTranslation } from "react-i18next";
@@ -37,15 +37,29 @@ function OwnerDetailFormContainer({ owner, refetch }) {
};
return (
<Form
form={form}
onFinish={handleFinish}
autoComplete="off"
layout="vertical"
initialValues={owner}
>
<OwnerDetailFormComponent loading={loading} form={form} />
</Form>
<>
<PageHeader
title={t("menus.header.owners")}
extra={
<Button
type="primary"
loading={loading}
onClick={() => form.submit()}
>
{t("general.actions.save")}
</Button>
}
/>
<Form
form={form}
onFinish={handleFinish}
autoComplete="off"
layout="vertical"
initialValues={owner}
>
<OwnerDetailFormComponent loading={loading} form={form} />
</Form>
</>
);
}
export default OwnerDetailFormContainer;

View File

@@ -1,4 +1,4 @@
import { Table } from "antd";
import { Card, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -59,44 +59,47 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
];
return (
<Table
title={() => (
<div>
<OwnerDetailUpdateJobsComponent
selectedJobs={selectedJobs}
owner={owner}
disabled={selectedJobs.length === 0}
/>
</div>
)}
pagination={{ position: "bottom" }}
columns={columns}
scroll={{ x: true }}
rowKey="id"
dataSource={owner.jobs}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
},
onSelectAll: (selected, selectedRows, changeRows) => {
setSelectedJobs(
selectedRows
? selectedRows
.filter((i) =>
bodyshop.md_ro_statuses.active_statuses.includes(i.status)
)
.map((i) => i.id)
: []
);
},
selectedRowKeys: selectedJobs,
getCheckboxProps: (record) => ({
disabled: bodyshop.md_ro_statuses.active_statuses
? !bodyshop.md_ro_statuses.active_statuses.includes(record.status)
: true,
}),
}}
/>
<Card
title={t("owners.labels.relatedjobs")}
extra={
<OwnerDetailUpdateJobsComponent
selectedJobs={selectedJobs}
owner={owner}
disabled={selectedJobs.length === 0}
/>
}
>
<Table
pagination={{ position: "bottom" }}
columns={columns}
scroll={{ x: true }}
rowKey="id"
dataSource={owner.jobs}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
},
onSelectAll: (selected, selectedRows, changeRows) => {
setSelectedJobs(
selectedRows
? selectedRows
.filter((i) =>
bodyshop.md_ro_statuses.active_statuses.includes(i.status)
)
.map((i) => i.id)
: []
);
},
selectedRowKeys: selectedJobs,
getCheckboxProps: (record) => ({
disabled: bodyshop.md_ro_statuses.active_statuses
? !bodyshop.md_ro_statuses.active_statuses.includes(record.status)
: true,
}),
}}
/>
</Card>
);
}
export default connect(mapStateToProps, null)(OwnerDetailJobsComponent);

View File

@@ -67,7 +67,6 @@ export default function OwnerFindModalComponent({
<div>
<Table
title={() => t("owners.labels.existing_owners")}
size="small"
pagination={{ position: "bottom" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"

View File

@@ -9,11 +9,7 @@ export default function OwnerTagPopoverComponent({ job }) {
<div style={{ width: "400px" }}>
<Row>
<Col span={12}>
<Descriptions
title={t("owners.labels.fromclaim")}
size="small"
column={1}
>
<Descriptions title={t("owners.labels.fromclaim")} column={1}>
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>{`${
job.ownr_fn || ""
} ${job.ownr_ln || ""} ${job.ownr_co_nm || ""}`}</Descriptions.Item>
@@ -31,11 +27,7 @@ export default function OwnerTagPopoverComponent({ job }) {
</Descriptions>
</Col>
<Col span={12}>
<Descriptions
title={t("owners.labels.fromowner")}
size="small"
column={1}
>
<Descriptions title={t("owners.labels.fromowner")} column={1}>
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>{`${
job.owner.ownr_fn || ""
} ${job.owner.ownr_ln || ""} ${

View File

@@ -1,5 +1,5 @@
import { SyncOutlined } from "@ant-design/icons";
import { Button, Input, Table } from "antd";
import { Button, Card, Input, Space, Table } from "antd";
import queryString from "query-string";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
@@ -74,38 +74,38 @@ export default function OwnersListComponent({
history.push({ search: queryString.stringify(search) });
};
return (
<Table
loading={loading}
title={() => {
return (
<div className="imex-table-header">
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
className="imex-table-header__search"
placeholder={t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
}}
enterButton
/>
</div>
);
}}
size="small"
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey="id"
scroll={{ x: true }}
dataSource={owners}
onChange={handleTableChange}
/>
<Card
title={t("menus.header.owners")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
}}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey="id"
scroll={{ x: true }}
dataSource={owners}
onChange={handleTableChange}
/>
</Card>
);
}

View File

@@ -83,7 +83,7 @@ export function PartsOrderBackorderEta({
{isAlreadyBackordered && (
<CalendarFilled style={{ cursor: "pointer" }} onClick={handlePopover} />
)}
{loading && <Spin size="small" />}
{loading && <Spin />}
</Popover>
);
}

View File

@@ -1,5 +1,15 @@
import { SyncOutlined } from "@ant-design/icons";
import { Button, Checkbox, Input, Space, Table, Typography } from "antd";
import { EyeFilled, SyncOutlined } from "@ant-design/icons";
import {
Button,
Card,
Checkbox,
Drawer,
Grid,
Input,
PageHeader,
Space,
Table,
} from "antd";
import queryString from "query-string";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
@@ -40,6 +50,21 @@ export function PartsOrderListTableComponent({
handleOnRowClick,
setPartsReceiveContext,
}) {
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
const bpoints = {
xs: "100%",
sm: "100%",
md: "100%",
lg: "75%",
xl: "75%",
xxl: "65%",
};
const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]]
: "100%";
const responsibilityCenters = bodyshop.md_responsibility_centers;
const Templates = TemplateList("partsorder");
const { t } = useTranslation();
@@ -51,6 +76,86 @@ export function PartsOrderListTableComponent({
const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : [];
const { refetch } = billsQuery;
const recordActions = (record, showView = false) => (
<Space wrap>
{showView && (
<Button onClick={() => handleOnRowClick(record)}>
<EyeFilled />
</Button>
)}
<Button
disabled={jobRO || record.return}
onClick={() => {
logImEXEvent("parts_order_receive_bill");
setPartsReceiveContext({
actions: { refetch: refetch },
context: {
jobId: job.id,
job: job,
partsorderlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id,
line_desc: pol.line_desc,
quantity: pol.quantity,
};
}),
},
});
}}
>
{t("parts_orders.actions.receive")}
</Button>
<Button
disabled={jobRO}
onClick={() => {
logImEXEvent("parts_order_receive_bill");
setBillEnterContext({
actions: { refetch: refetch },
context: {
job: job,
bill: {
vendorid: record.vendor.id,
is_credit_memo: record.return,
billlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id,
line_desc: pol.line_desc,
quantity: pol.quantity,
actual_price: pol.act_price,
cost_center: pol.jobline.part_type
? responsibilityCenters.defaults.costs[
pol.jobline.part_type
] || null
: null,
};
}),
},
},
});
}}
>
{t("parts_orders.actions.receivebill")}
</Button>
<PrintWrapper
templateObject={{
name: record.return
? Templates.parts_return_slip.key
: Templates.parts_order.key,
variables: { id: record.id },
}}
messageObject={{
subject: record.return
? Templates.parts_return_slip.subject
: Templates.parts_order.subject,
}}
/>
</Space>
);
const columns = [
{
title: t("vendors.fields.name"),
@@ -105,79 +210,7 @@ export function PartsOrderListTableComponent({
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Space wrap>
<Button
disabled={jobRO || record.return}
onClick={() => {
logImEXEvent("parts_order_receive_bill");
setPartsReceiveContext({
actions: { refetch: refetch },
context: {
jobId: job.id,
job: job,
partsorderlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id,
line_desc: pol.line_desc,
quantity: pol.quantity,
};
}),
},
});
}}
>
{t("parts_orders.actions.receive")}
</Button>
<Button
disabled={jobRO}
onClick={() => {
logImEXEvent("parts_order_receive_bill");
setBillEnterContext({
actions: { refetch: refetch },
context: {
job: job,
bill: {
vendorid: record.vendor.id,
is_credit_memo: record.return,
billlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id,
line_desc: pol.line_desc,
quantity: pol.quantity,
actual_price: pol.act_price,
cost_center: pol.jobline.part_type
? responsibilityCenters.defaults.costs[
pol.jobline.part_type
] || null
: null,
};
}),
},
},
});
}}
>
{t("parts_orders.actions.receivebill")}
</Button>
<PrintWrapper
templateObject={{
name: record.return
? Templates.parts_return_slip.key
: Templates.parts_order.key,
variables: { id: record.id },
}}
messageObject={{
subject: record.return
? Templates.parts_return_slip.subject
: Templates.parts_order.subject,
}}
/>
</Space>
),
render: (text, record) => recordActions(record, true),
},
];
@@ -280,89 +313,70 @@ export function PartsOrderListTableComponent({
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<div>
<PartsOrderLineBackorderButton
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
jobLineId={record.job_line_id}
/>
</div>
<PartsOrderLineBackorderButton
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
jobLineId={record.job_line_id}
/>
),
},
];
return (
<div style={{ margin: ".5rem" }}>
<>
<PageHeader
title={record && `${record.vendor.name} - ${record.order_number}`}
extra={recordActions(record)}
/>
<Table
size="small"
scroll={{ x: "50%", y: "40rem" }}
scroll={{ x: true, y: "50rem" }}
columns={columns}
rowKey="id"
dataSource={record.parts_order_lines}
/>
</div>
</>
);
};
return (
<div>
<Typography.Title level={4}>
{t("parts_orders.labels.parts_orders")}
</Typography.Title>
<Card
title={t("parts_orders.labels.parts_orders")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
e.preventDefault();
}}
/>
</Space>
}
>
<PartsReceiveModalContainer />
<Drawer
placement="right"
onClose={() => handleOnRowClick(null)}
visible={selectedpartsorder}
//getContainer={false}
style={{ position: "absolute" }}
closable
width={drawerPercentage}
>
{selectedPartsOrderRecord && rowExpander(selectedPartsOrderRecord)}
</Drawer>
<Table
loading={billsQuery.loading}
size="small"
title={() => (
<div className="imex-table-header">
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<div className="imex-table-header__search">
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
e.preventDefault();
}}
/>
</div>
</div>
)}
scroll={{ x: "50%", y: "40rem" }}
expandedRowRender={rowExpander}
pagination={{ position: "top", defaultPageSize: 25 }}
scroll={{ x: true, y: "50rem" }}
columns={columns}
rowKey="id"
dataSource={parts_orders}
onChange={handleTableChange}
expandable={{
expandedRowKeys: [selectedpartsorder],
onExpand: (expanded, record) => {
handleOnRowClick(expanded ? record : null);
},
}}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selectedpartsorder],
type: "radio",
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
}, // click row
onDoubleClick: (event) => {}, // double click row
onContextMenu: (event) => {}, // right button click row
onMouseEnter: (event) => {}, // mouse enter row
onMouseLeave: (event) => {}, // mouse leave row
};
}}
/>
</div>
</Card>
);
}
export default connect(

View File

@@ -178,7 +178,6 @@ export function PaymentsListPaginated({
<div>
<Table
loading={loading}
size="small"
scroll={{ x: true }}
pagination={{
position: "top",

View File

@@ -55,7 +55,7 @@ export function PrintCenterItemComponent({
);
}}
/>
{loading && <Spin size="small" />}
{loading && <Spin />}
</li>
);
}

View File

@@ -20,7 +20,7 @@ export default function PrintWrapperComponent({
{children || null}
<PrinterFilled onClick={() => handlePrint("p")} />
<MailFilled onClick={() => handlePrint("e")} />
{loading && <Spin size="small" />}
{loading && <Spin />}
</Space>
);
}

View File

@@ -25,7 +25,6 @@ export default function ProductionBoardCard(technician, card) {
<Card
className="react-kanban-card imex-kanban-card tight-antd-rows"
style={{ margin: ".2rem 0rem" }}
size="small"
title={`${card.ro_number || t("general.labels.na")} - ${
card.v_model_yr
} ${card.v_make_desc || ""} ${card.v_model_desc || ""}`}

View File

@@ -47,7 +47,7 @@ export function ProductionListColumnStatus({ record, bodyshop }) {
>
<div style={{ width: "100%", height: "19px", cursor: "pointer" }}>
{record.status}
{loading && <Spin size="small" />}
{loading && <Spin />}
</div>
</Dropdown>
);

View File

@@ -53,7 +53,7 @@ export default function ProductionListDetail({ jobs }) {
{!loading && data && (
<div>
<JobEmployeeAssignments job={data.jobs_by_pk} refetch={refetch} />
<Descriptions bordered size="small" column={1}>
<Descriptions bordered column={1}>
<Descriptions.Item label={t("jobs.fields.ro_number")}>
{theJob.ro_number || ""}
</Descriptions.Item>

View File

@@ -146,7 +146,6 @@ export function ProductionListTable({
handleSelector=".prod-header-dropdown"
>
<Table
size="small"
pagination={false}
components={{
header: {

View File

@@ -48,7 +48,6 @@ export default function ProductionSubletsManageComponent({ subletJobLines }) {
const popContent = (
<div style={{ minWidth: "20rem" }}>
<List
size="small"
onClick={(e) => e.stopPropagation()}
dataSource={subletJobLines}
renderItem={(s) => (

View File

@@ -48,7 +48,6 @@ export default function ProfileShopsComponent({
</Typography.Title>
)}
loading={loading}
size="small"
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={data}

View File

@@ -53,7 +53,6 @@ export default function ScoreboardJobsList({ scoreBoardlist }) {
const overlay = (
<div style={{ width: "50vw", padding: "1rem" }}>
<Table
size="small"
pagination={false}
columns={columns}
rowKey="id"

View File

@@ -70,7 +70,6 @@ export default function ShopEmployeesListComponent({
);
}}
loading={loading}
size="small"
pagination={{ position: "top" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"

View File

@@ -48,7 +48,6 @@ export default function ShopInfoUsersComponent() {
<div>
<Table
loading={loading}
size="small"
pagination={{ position: "top" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"

View File

@@ -82,7 +82,7 @@ export function TechClockedInList({ technician }) {
<DateTimeFormatter>{ticket.clockon}</DateTimeFormatter>
</DataLabel>
<DataLabel label={t("timetickets.fields.cost_center")}>
{ticket.cost_center}{" "}
{ticket.cost_center}
</DataLabel>
</Card>
</List.Item>

View File

@@ -179,7 +179,6 @@ export function TechLookupJobsList({ bodyshop }) {
return (
<Table
loading={loading}
size="small"
pagination={false}
columns={columns}
rowKey="id"

View File

@@ -1,4 +1,4 @@
import { Table } from "antd";
import { Card, Space, Table } from "antd";
import moment from "moment";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -15,6 +15,7 @@ export default function TimeTicketList({
timetickets,
refetch,
techConsole,
jobId,
}) {
const [state, setState] = useState({
sortedInfo: {},
@@ -157,8 +158,8 @@ export default function TimeTicketList({
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<div>
{!!techConsole && (
<Space wrap>
{techConsole && (
<TimeTicketEnterButton
actions={{ refetch }}
context={{ id: record.id, timeticket: record }}
@@ -186,7 +187,7 @@ export default function TimeTicketList({
</TimeTicketEnterButton>
</RbacWrapper>
)}
</div>
</Space>
),
},
];
@@ -196,37 +197,54 @@ export default function TimeTicketList({
};
return (
<Table
loading={loading}
size="small"
pagination={{ position: "top" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={timetickets}
onChange={handleTableChange}
summary={() => {
return (
<Table.Summary.Row>
<Table.Summary.Cell>
{t("general.labels.totals")}
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell />
<Table.Summary.Cell>{totals.productivehrs}</Table.Summary.Cell>
<Table.Summary.Cell>{totals.actualhrs}</Table.Summary.Cell>
<Table.Summary.Cell>
{totals.actualhrs === 0 || !totals.actualhrs
? "∞"
: `${((totals.productivehrs / totals.actualhrs) * 100).toFixed(
2
)}% ${t("timetickets.labels.efficiency")}`}
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell />
<Table.Summary.Cell />
</Table.Summary.Row>
);
}}
/>
<Card
title={t("timetickets.labels.timetickets")}
extra={
jobId &&
(techConsole ? null : (
<TimeTicketEnterButton
actions={{ refetch }}
context={{ jobId: jobId }}
>
{t("timetickets.actions.enter")}
</TimeTicketEnterButton>
))
}
>
<Table
loading={loading}
columns={columns}
rowKey="id"
scroll={{
x: true,
}}
dataSource={timetickets}
onChange={handleTableChange}
summary={() => {
return (
<Table.Summary.Row>
<Table.Summary.Cell>
{t("general.labels.totals")}
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell />
<Table.Summary.Cell>{totals.productivehrs}</Table.Summary.Cell>
<Table.Summary.Cell>{totals.actualhrs}</Table.Summary.Cell>
<Table.Summary.Cell>
{totals.actualhrs === 0 || !totals.actualhrs
? "∞"
: `${(
(totals.productivehrs / totals.actualhrs) *
100
).toFixed(2)}% ${t("timetickets.labels.efficiency")}`}
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell />
<Table.Summary.Cell />
</Table.Summary.Row>
);
}}
/>
</Card>
);
}

View File

@@ -1,4 +1,4 @@
import { Button, Form, Input } from "antd";
import { Form, Input } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
@@ -10,20 +10,7 @@ export default function VehicleDetailFormComponent({ form, loading }) {
return (
<div>
<div className="imex-flex-row imex-flex-row__flex-space-around">
<Button
className="imex-flex-row__margin-large"
type="primary"
key="submit"
htmlType="submit"
loading={loading}
>
{t("general.actions.save")}
</Button>
<div className="imex-flex-row__grow imex-flex-row__margin-large">
<FormFieldsChanged form={form} />
</div>
</div>
<FormFieldsChanged form={form} />
<LayoutFormRow header={t("vehicles.forms.detail")}>
<Form.Item
@@ -136,7 +123,6 @@ export default function VehicleDetailFormComponent({ form, loading }) {
<FormDatePicker />
</Form.Item>
{
//Removed as a part of IO-446.
//No values have been captured in this field as of yet.
// <Form.Item

View File

@@ -1,5 +1,5 @@
import React, { useState } from "react";
import { Form, notification } from "antd";
import { Button, Form, notification, PageHeader } from "antd";
import { useMutation } from "@apollo/client";
import VehicleDetailFormComponent from "./vehicle-detail-form.component";
import { useTranslation } from "react-i18next";
@@ -37,18 +37,32 @@ function VehicleDetailFormContainer({ vehicle, refetch }) {
};
return (
<Form
onFinish={handleFinish}
form={form}
autoComplete="off"
layout="vertical"
initialValues={{
...vehicle,
v_prod_dt: vehicle.v_prod_dt ? moment(vehicle.v_prod_dt) : null,
}}
>
<VehicleDetailFormComponent form={form} loading={loading} />
</Form>
<>
<PageHeader
title={t("menus.header.owners")}
extra={
<Button
type="primary"
loading={loading}
onClick={() => form.submit()}
>
{t("general.actions.save")}
</Button>
}
/>
<Form
onFinish={handleFinish}
form={form}
autoComplete="off"
layout="vertical"
initialValues={{
...vehicle,
v_prod_dt: vehicle.v_prod_dt ? moment(vehicle.v_prod_dt) : null,
}}
>
<VehicleDetailFormComponent form={form} loading={loading} />
</Form>
</>
);
}

View File

@@ -1,4 +1,4 @@
import { Table } from "antd";
import { Card, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -62,44 +62,45 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
];
return (
<Table
title={() => (
<div>
<VehicleDetailUpdateJobsComponent
selectedJobs={selectedJobs}
vehicle={vehicle}
disabled={selectedJobs.length === 0}
/>
</div>
)}
pagination={{ position: "bottom" }}
columns={columns}
rowKey="id"
scroll={{ x: true }}
dataSource={vehicle.jobs}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
},
onSelectAll: (selected, selectedRows, changeRows) => {
setSelectedJobs(
selectedRows
? selectedRows
.filter((i) =>
bodyshop.md_ro_statuses.active_statuses.includes(i.status)
)
.map((i) => i.id)
: []
);
},
selectedRowKeys: selectedJobs,
getCheckboxProps: (record) => ({
disabled: bodyshop.md_ro_statuses.active_statuses
? !bodyshop.md_ro_statuses.active_statuses.includes(record.status)
: true,
}),
}}
/>
<Card
title={t("vehicles.labels.relatedjobs")}
extra={
<VehicleDetailUpdateJobsComponent
selectedJobs={selectedJobs}
vehicle={vehicle}
disabled={selectedJobs.length === 0}
/>
}
>
<Table
columns={columns}
rowKey="id"
scroll={{ x: true }}
dataSource={vehicle.jobs}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
},
onSelectAll: (selected, selectedRows, changeRows) => {
setSelectedJobs(
selectedRows
? selectedRows
.filter((i) =>
bodyshop.md_ro_statuses.active_statuses.includes(i.status)
)
.map((i) => i.id)
: []
);
},
selectedRowKeys: selectedJobs,
getCheckboxProps: (record) => ({
disabled: bodyshop.md_ro_statuses.active_statuses
? !bodyshop.md_ro_statuses.active_statuses.includes(record.status)
: true,
}),
}}
/>
</Card>
);
}

View File

@@ -11,11 +11,7 @@ export default function VehicleTagPopoverComponent({ job }) {
<div style={{ width: "400px" }}>
<Row>
<Col span={12}>
<Descriptions
title={t("owners.labels.fromclaim")}
size="small"
column={1}
>
<Descriptions title={t("owners.labels.fromclaim")} column={1}>
<Descriptions.Item key="1" label={t("jobs.fields.vehicle")}>
{`${job.v_model_yr || t("general.labels.na")} ${
job.v_color || ""
@@ -36,11 +32,7 @@ export default function VehicleTagPopoverComponent({ job }) {
</Descriptions>
</Col>
<Col span={12}>
<Descriptions
title={t("vehicles.labels.fromvehicle")}
size="small"
column={1}
>
<Descriptions title={t("vehicles.labels.fromvehicle")} column={1}>
<Descriptions.Item key="1" label={t("jobs.fields.vehicle")}>
{`${job.vehicle.v_model_yr || t("general.labels.na")}
${job.vehicle.v_make_desc || t("general.labels.na")}

View File

@@ -1,5 +1,5 @@
import { SyncOutlined } from "@ant-design/icons";
import { Button, Input, Table } from "antd";
import { Button, Card, Input, Space, Table } from "antd";
import queryString from "query-string";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
@@ -62,38 +62,38 @@ export default function VehiclesListComponent({
};
return (
<Table
loading={loading}
title={() => {
return (
<div className="imex-table-header">
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
className="imex-table-header__search"
placeholder={t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
}}
enterButton
/>
</div>
);
}}
size="small"
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey="id"
scroll={{ x: true }}
dataSource={vehicles}
onChange={handleTableChange}
/>
<Card
title={t("menus.header.vehicles")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
}}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey="id"
scroll={{ x: true }}
dataSource={vehicles}
onChange={handleTableChange}
/>
</Card>
);
}

View File

@@ -99,7 +99,6 @@ export default function VendorsListComponent({
</div>
);
}}
size="small"
pagination={{ position: "top" }}
columns={columns}
rowKey="id"

View File

@@ -206,7 +206,6 @@ export function BillsListPage({
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<Table
loading={loading}
size="small"
title={() => (
<div className="imex-table-header">
<Button onClick={() => refetch()}>

View File

@@ -1,6 +1,7 @@
import React from "react";
import CourtesyCarCreateFormComponent from "../../components/courtesy-car-form/courtesy-car-form.component";
import CourtesyCarContractListComponent from "../../components/courtesy-car-contract-list/courtesy-car-contract-list.component";
import { Col, Divider, Row } from "antd";
export default function CourtesyCarDetailPageComponent({
contracts,
@@ -9,12 +10,17 @@ export default function CourtesyCarDetailPageComponent({
totalContracts,
}) {
return (
<div>
<CourtesyCarCreateFormComponent form={form} saveLoading={saveLoading} />
<CourtesyCarContractListComponent
contracts={contracts}
totalContracts={totalContracts}
/>
</div>
<Row gutter={[16, 16]}>
<Col span={24}>
<CourtesyCarCreateFormComponent form={form} saveLoading={saveLoading} />
</Col>
<Divider type="horizontal" />
<Col span={24}>
<CourtesyCarContractListComponent
contracts={contracts}
totalContracts={totalContracts}
/>
</Col>
</Row>
);
}

View File

@@ -1,4 +1,4 @@
import { Button } from "antd";
import { Button, PageHeader } from "antd";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -7,7 +7,7 @@ import JobsAvailableTableContainer from "../../components/jobs-available-table/j
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import {
setBreadcrumbs,
setSelectedHeader
setSelectedHeader,
} from "../../redux/application/application.actions";
const mapDispatchToProps = (dispatch) => ({
@@ -32,9 +32,14 @@ export function JobsAvailablePageContainer({
return (
<RbacWrapper action="jobs:available-list">
<div>
<Link to="/manage/jobs/new">
<Button>{t("jobs.actions.manualnew")}</Button>
</Link>
<PageHeader
title={t("titles.bc.availablejobs")}
extra={
<Link to="/manage/jobs/new">
<Button>{t("jobs.actions.manualnew")}</Button>
</Link>
}
/>
<JobsAvailableTableContainer />
</div>
</RbacWrapper>

View File

@@ -1,11 +1,18 @@
import { Col, Divider, Row } from "antd";
import React from "react";
import OwnerDetailForm from "../../components/owner-detail-form/owner-detail-form.container";
import OwnerDetailJobsComponent from "../../components/owner-detail-jobs/owner-detail-jobs.component";
export default function OwnersDetailComponent({ owner, refetch }) {
return (
<div>
<OwnerDetailForm owner={owner} refetch={refetch} />
<OwnerDetailJobsComponent owner={owner} />
</div>
<Row gutter={[16, 16]}>
<Col span={24}>
<OwnerDetailForm owner={owner} refetch={refetch} />
</Col>
<Divider type="horizontal" />
<Col span={24}>
<OwnerDetailJobsComponent owner={owner} />
</Col>
</Row>
);
}

View File

@@ -1,6 +1,6 @@
import { SyncOutlined } from "@ant-design/icons";
import { useQuery } from "@apollo/client";
import { Button, Input, Table } from "antd";
import { Button, Card, Input, Space, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -212,35 +212,35 @@ export function PartsQueuePageComponent({ bodyshop }) {
];
return (
<Table
loading={loading}
size="small"
pagination={false}
columns={columns}
rowKey="id"
dataSource={jobs}
style={{ height: "100%" }}
scroll={{ x: true }}
title={() => {
return (
<div className="imex-table-header">
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
className="imex-table-header__search"
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.target.value);
}}
value={searchText}
enterButton
/>
</div>
);
}}
onChange={handleTableChange}
/>
<Card
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
className="imex-table-header__search"
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.target.value);
}}
value={searchText}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={false}
columns={columns}
rowKey="id"
dataSource={jobs}
style={{ height: "100%" }}
scroll={{ x: true }}
onChange={handleTableChange}
/>
</Card>
);
}

View File

@@ -1,3 +1,4 @@
import { Col, Divider, Row } from "antd";
import React from "react";
import VehicleDetailFormContainer from "../../components/vehicle-detail-form/vehicle-detail-form.container";
import VehicleDetailJobsComponent from "../../components/vehicle-detail-jobs/vehicle-detail-jobs.component";
@@ -5,8 +6,15 @@ import VehicleDetailJobsComponent from "../../components/vehicle-detail-jobs/veh
export default function VehicleDetailComponent({ vehicle, refetch }) {
return (
<div>
<VehicleDetailFormContainer vehicle={vehicle} refetch={refetch} />
<VehicleDetailJobsComponent vehicle={vehicle} />
<Row gutter={[16, 16]}>
<Col span={24}>
<VehicleDetailFormContainer vehicle={vehicle} refetch={refetch} />
</Col>
<Divider type="horizontal" />
<Col span={24}>
<VehicleDetailJobsComponent vehicle={vehicle} />
</Col>
</Row>
</div>
);
}

View File

@@ -582,6 +582,8 @@
},
"outwith": "Out With",
"return": "Return Courtesy Car",
"status": "Status",
"usage": "Usage",
"vehicle": "Vehicle Description"
},
"status": {
@@ -1446,6 +1448,7 @@
"existing_owners": "Existing Owners",
"fromclaim": "Current Claim",
"fromowner": "Historical Owner Record",
"relatedjobs": "Related Jobs",
"updateowner": "Update Owner"
},
"successes": {
@@ -1776,7 +1779,8 @@
"pmshift": "PM Shift",
"shift": "Shift",
"shiftalreadyclockedon": "Active Shift Time Tickets",
"straight_time": "Straight Time"
"straight_time": "Straight Time",
"timetickets": "Time Tickets"
},
"successes": {
"clockedin": "Clocked in successfully.",
@@ -1924,6 +1928,7 @@
},
"labels": {
"fromvehicle": "Historical Vehicle Record",
"relatedjobs": "Related Jobs",
"updatevehicle": "Update Vehicle Information"
},
"successes": {

View File

@@ -582,6 +582,8 @@
},
"outwith": "",
"return": "",
"status": "",
"usage": "",
"vehicle": ""
},
"status": {
@@ -1446,6 +1448,7 @@
"existing_owners": "Propietarios existentes",
"fromclaim": "",
"fromowner": "",
"relatedjobs": "",
"updateowner": ""
},
"successes": {
@@ -1776,7 +1779,8 @@
"pmshift": "",
"shift": "",
"shiftalreadyclockedon": "",
"straight_time": ""
"straight_time": "",
"timetickets": ""
},
"successes": {
"clockedin": "",
@@ -1924,6 +1928,7 @@
},
"labels": {
"fromvehicle": "",
"relatedjobs": "",
"updatevehicle": ""
},
"successes": {

View File

@@ -582,6 +582,8 @@
},
"outwith": "",
"return": "",
"status": "",
"usage": "",
"vehicle": ""
},
"status": {
@@ -1446,6 +1448,7 @@
"existing_owners": "Propriétaires existants",
"fromclaim": "",
"fromowner": "",
"relatedjobs": "",
"updateowner": ""
},
"successes": {
@@ -1776,7 +1779,8 @@
"pmshift": "",
"shift": "",
"shiftalreadyclockedon": "",
"straight_time": ""
"straight_time": "",
"timetickets": ""
},
"successes": {
"clockedin": "",
@@ -1924,6 +1928,7 @@
},
"labels": {
"fromvehicle": "",
"relatedjobs": "",
"updatevehicle": ""
},
"successes": {