WIP Download Images + Invoice Tables
This commit is contained in:
@@ -1,54 +1,64 @@
|
||||
import { Card } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { Responsive, WidthProvider } from "react-grid-layout";
|
||||
import styled from "styled-components";
|
||||
//Combination of the following:
|
||||
// /node_modules/react-grid-layout/css/styles.css
|
||||
// /node_modules/react-resizable/css/styles.css
|
||||
import "./dashboard-grid.styles.css";
|
||||
|
||||
const Sdiv = styled.div`
|
||||
position: absolute;
|
||||
height: 80%;
|
||||
width: 80%;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
background-color: #ffcc00;
|
||||
`;
|
||||
|
||||
const ResponsiveReactGridLayout = WidthProvider(Responsive);
|
||||
export default function DashboardGridComponent() {
|
||||
const [state, setState] = useState({
|
||||
layout: [
|
||||
{ x: 0, y: 0, w: 2, h: 2 },
|
||||
{ x: 1, y: 0, w: 2, h: 2 },
|
||||
{ x: 4, y: 0, w: 2, h: 2 }
|
||||
{ i: "1", x: 0, y: 0, w: 2, h: 2 },
|
||||
{ i: "2", x: 2, y: 0, w: 2, h: 2 },
|
||||
{ i: "3", x: 4, y: 0, w: 2, h: 2 }
|
||||
]
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
className: "layout",
|
||||
breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
|
||||
cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
|
||||
rowHeight: 100
|
||||
breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }
|
||||
// cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
|
||||
// rowHeight: 100
|
||||
};
|
||||
|
||||
// We're using the cols coming back from this to calculate where to add new items.
|
||||
const onBreakpointChange = (breakpoint, cols) => {
|
||||
console.log("breakpoint, cols", breakpoint, cols);
|
||||
setState({ ...state, breakpoint: breakpoint, cols: cols });
|
||||
// setState({ ...state, breakpoint: breakpoint, cols: cols });
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", height: " 100%" }}>
|
||||
<Sdiv>
|
||||
The Grid.
|
||||
<ResponsiveReactGridLayout
|
||||
{...defaultProps}
|
||||
onBreakpointChange={onBreakpointChange}
|
||||
width="100%"
|
||||
onLayoutChange={layout => {
|
||||
console.log("layout", layout);
|
||||
setState({ ...state, layout });
|
||||
}}
|
||||
>
|
||||
{state.layout.map((item, index) => {
|
||||
console.log("item", item);
|
||||
return (
|
||||
<Card style={{ width: "100px" }} key={index} data-grid={item}>
|
||||
<Card style={{ width: "100px" }} key={item.i} data-grid={item}>
|
||||
A Card {index}
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</ResponsiveReactGridLayout>
|
||||
</div>
|
||||
</Sdiv>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
export default function InvoicesListTableComponent({ loading, invoices }) {
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {}
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: t("invoices.fields.vendorname"),
|
||||
dataIndex: "vendorname",
|
||||
key: "vendorname",
|
||||
// onFilter: (value, record) => record.ro_number.includes(value),
|
||||
// filteredValue: state.filteredInfo.text || null,
|
||||
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
|
||||
//ellipsis: true,
|
||||
render: (text, record) => <span>{record.vendor.name}</span>
|
||||
},
|
||||
{
|
||||
title: t("invoices.fields.invoice_number"),
|
||||
dataIndex: "invoice_number",
|
||||
key: "invoice_number",
|
||||
// onFilter: (value, record) => record.ro_number.includes(value),
|
||||
// filteredValue: state.filteredInfo.text || null,
|
||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "invoice_number" &&
|
||||
state.sortedInfo.order
|
||||
//ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: t("invoices.fields.date"),
|
||||
dataIndex: "date",
|
||||
key: "date",
|
||||
// onFilter: (value, record) => record.ro_number.includes(value),
|
||||
// filteredValue: state.filteredInfo.text || null,
|
||||
sorter: (a, b) => a.date - b.date,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
|
||||
//ellipsis: true,
|
||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>
|
||||
}
|
||||
];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
};
|
||||
|
||||
const rowExpander = record => (
|
||||
<div style={{ margin: 0 }}>Invoice details</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
size="small"
|
||||
expandedRowRender={rowExpander}
|
||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||
columns={columns.map(item => ({ ...item }))}
|
||||
rowKey="id"
|
||||
dataSource={invoices}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +1,15 @@
|
||||
import { Button } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
toggleModalVisible,
|
||||
setModalContext
|
||||
} from "../../redux/modals/modals.actions";
|
||||
import { Button } from "antd";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import InvoicesListTableComponent from "../invoices-list-table/invoices-list-table.component";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
toggleModalVisible: () => dispatch(toggleModalVisible("invoiceEnter")),
|
||||
setInvoiceEnterContext: context =>
|
||||
dispatch(setModalContext({ context: context, modal: "invoiceEnter" }))
|
||||
});
|
||||
@@ -19,9 +17,9 @@ export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(function JobsDetailPliComponent({
|
||||
toggleModalVisible,
|
||||
setInvoiceEnterContext,
|
||||
job
|
||||
job,
|
||||
invoicesQuery
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
@@ -37,6 +35,13 @@ export default connect(
|
||||
>
|
||||
Enter Invoice
|
||||
</Button>
|
||||
{invoicesQuery.error ? (
|
||||
<AlertComponent message={invoicesQuery.error.message} type="error" />
|
||||
) : null}
|
||||
<InvoicesListTableComponent
|
||||
loading={invoicesQuery.loading}
|
||||
invoices={invoicesQuery.data ? invoicesQuery.data.invoices : null}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import React from "react";
|
||||
import { useQuery } from "react-apollo";
|
||||
import JobsDetailPliComponent from "./jobs-detail-pli.component";
|
||||
|
||||
import { QUERY_INVOICES_BY_JOBID } from "../../graphql/invoices.queries";
|
||||
export default function JobsDetailPliContainer({ job }) {
|
||||
console.log("job", job);
|
||||
return <JobsDetailPliComponent job={job} />;
|
||||
const invoicesQuery = useQuery(QUERY_INVOICES_BY_JOBID, {
|
||||
variables: { jobid: job.id },
|
||||
fetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
return <JobsDetailPliComponent job={job} invoicesQuery={invoicesQuery} />;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Modal, notification, Upload } from "antd";
|
||||
import { InboxOutlined } from "@ant-design/icons";
|
||||
import { Modal, notification, Upload } from "antd";
|
||||
import axios from "axios";
|
||||
import React, { useState } from "react";
|
||||
import { useMutation } from "react-apollo";
|
||||
import Gallery from "react-grid-gallery";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Resizer from "react-image-file-resizer";
|
||||
import {
|
||||
INSERT_NEW_DOCUMENT,
|
||||
DELETE_DOCUMENT
|
||||
DELETE_DOCUMENT,
|
||||
INSERT_NEW_DOCUMENT
|
||||
} from "../../graphql/documents.queries";
|
||||
import "./jobs-documents.styles.scss";
|
||||
import { generateCdnThumb } from "../../utils/DocHelpers";
|
||||
import "./jobs-documents.styles.scss";
|
||||
|
||||
function getBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -45,6 +46,19 @@ function JobsDocumentsComponent({ shopId, jobId, loading, data, currentUser }) {
|
||||
}, [])
|
||||
);
|
||||
|
||||
const [galleryImages, setgalleryImages] = useState(
|
||||
data.reduce((acc, value) => {
|
||||
acc.push({
|
||||
src: value.url,
|
||||
thumbnail: value.thumb_url,
|
||||
thumbnailHeight: 150,
|
||||
thumbnailWidth: 150,
|
||||
isSelected: false
|
||||
});
|
||||
return acc;
|
||||
}, [])
|
||||
);
|
||||
|
||||
const uploadToS3 = (
|
||||
fileName,
|
||||
fileType,
|
||||
@@ -246,6 +260,29 @@ function JobsDocumentsComponent({ shopId, jobId, loading, data, currentUser }) {
|
||||
<Modal visible={previewVisible} footer={null} onCancel={handleCancel}>
|
||||
<img alt="example" style={{ width: "100%" }} src={previewImage} />
|
||||
</Modal>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
axios
|
||||
.get("/downloadImages", {
|
||||
images: galleryImages.map(i => i.src)
|
||||
})
|
||||
.then(r => console.log("r", r));
|
||||
}}
|
||||
>
|
||||
Dl
|
||||
</button>
|
||||
<Gallery
|
||||
images={galleryImages}
|
||||
onSelectImage={(index, image) => {
|
||||
console.log("index, image", index, image);
|
||||
setgalleryImages(
|
||||
galleryImages.map((g, idx) =>
|
||||
index === idx ? { ...g, isSelected: !g.isSelected } : g
|
||||
)
|
||||
);
|
||||
}}
|
||||
></Gallery>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,3 +9,25 @@ export const INSERT_NEW_INVOICE = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_INVOICES_BY_JOBID = gql`
|
||||
query QUERY_INVOICES_BY_JOBID($jobid: uuid!) {
|
||||
invoices(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
||||
id
|
||||
vendor {
|
||||
id
|
||||
name
|
||||
}
|
||||
total
|
||||
invoice_number
|
||||
date
|
||||
invoicelines {
|
||||
actual_price
|
||||
actual_cost
|
||||
cost_center
|
||||
id
|
||||
line_desc
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -4,8 +4,8 @@ export const generateCdnThumb = key => {
|
||||
key: key,
|
||||
edits: {
|
||||
resize: {
|
||||
height: 100,
|
||||
width: 100
|
||||
height: 150,
|
||||
width: 150
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user