Breaking Changes as a part of BOD-63 on invoice enter. WIP for all invoices screen editing + lookup.

This commit is contained in:
Patrick Fic
2020-05-04 18:07:56 -07:00
parent b7d438a0f0
commit 9d694e6403
12 changed files with 542 additions and 289 deletions

View File

@@ -56,10 +56,11 @@
}
.messages ul li p {
display: inline-block;
padding: 10px 15px;
margin: 0px;
padding: 0px 10px;
border-radius: 20px;
max-width: 205px;
line-height: 130%;
//line-height: 130%;
}
@media screen and (min-width: 735px) {
.messages ul li p {

View File

@@ -0,0 +1,106 @@
import { DatePicker, Form, Input, Switch } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import JobSearchSelect from "../job-search-select/job-search-select.component";
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
import InvoiceEnterModalLinesComponent from "../invoice-enter-modal/invoice-enter-modal.lines.component";
import DocumentsUploadContainer from "../documents-upload/documents-upload.container";
export default function InvoiceDetailEditComponent({
form,
roAutoCompleteOptions,
loadLines,
lineData,
responsibilityCenters,
}) {
const { t } = useTranslation();
return (
<div>
<div style={{ display: "flex" }}>
<Form.Item
name="jobid"
label={t("invoices.fields.ro_number")}
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<JobSearchSelect
options={roAutoCompleteOptions}
onBlur={() => {
if (form.getFieldValue("jobid") !== null) {
//loadLines({ variables: { id: form.getFieldValue("jobid") } });
}
}}
/>
</Form.Item>
</div>
<div style={{ display: "flex" }}>
<Form.Item
label={t("invoices.fields.invoice_number")}
name="invoice_number"
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("invoices.fields.date")}
name="date"
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<DatePicker />
</Form.Item>
<Form.Item
label={t("invoices.fields.is_credit_memo")}
name="is_credit_memo"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("invoices.fields.total")}
name="total"
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
</div>
<InvoiceEnterModalLinesComponent
lineData={lineData}
discount={0.1}
form={form}
responsibilityCenters={responsibilityCenters}
/>
<Form.Item name="upload" label="Upload">
<DocumentsUploadContainer jobId={form.getFieldValue("jobid")} />
</Form.Item>
<button
onClick={() => {
console.log(form.getFieldsValue());
}}
>
a
</button>
</div>
);
}

View File

@@ -0,0 +1,93 @@
import React, { useState, useEffect } from "react";
import {
QUERY_INVOICES_BY_VENDOR,
QUERY_INVOICE_BY_PK,
} from "../../graphql/invoices.queries";
import { useQuery, useLazyQuery } from "@apollo/react-hooks";
import queryString from "query-string";
import { useHistory, useLocation } from "react-router-dom";
import { Table, Input, Form } from "antd";
import { useTranslation } from "react-i18next";
import { alphaSort } from "../../utils/sorters";
import AlertComponent from "../alert/alert.component";
import { DateFormatter } from "../../utils/DateFormatter";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import InvoiceDetailEditComponent from "./invoice-detail-edit.component";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import moment from "moment";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { createStructuredSelector } from "reselect";
import { connect } from "react-redux";
import { GET_JOB_LINES_TO_ENTER_INVOICE } from "../../graphql/jobs-lines.queries";
import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
export function InvoiceDetailEditContainer({ bodyshop }) {
const search = queryString.parse(useLocation().search);
const { t } = useTranslation();
const [form] = Form.useForm();
const { loading, error, data } = useQuery(QUERY_INVOICE_BY_PK, {
variables: { invoiceid: search.invoiceid },
skip: !!!search.invoiceid,
});
const { data: RoAutoCompleteData } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
fetchPolicy: "network-only",
variables: { statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"] },
});
const {
loading: linesLoading,
data: lineData,
refetch: loadLines,
} = useQuery(GET_JOB_LINES_TO_ENTER_INVOICE, {
variables: { id: data && data.invoices_by_pk.jobid },
fetchPolicy: "network-only",
skip: !!!(data && data.invoices_by_pk.id),
});
const handleFinish = (values) => {
console.log("values", values);
};
useEffect(() => {
// if (data) {
// loadLines();
// if (lineData) //form.resetFields();
// }
}, [data, lineData]);
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<LoadingSkeleton loading={loading || linesLoading}>
<Form
form={form}
onFinish={handleFinish}
initialValues={
data
? {
...data.invoices_by_pk,
// invoicelines: [],
date: data.invoices_by_pk
? moment(data.invoices_by_pk.date)
: null,
}
: { invoicelines: [] }
}
>
<InvoiceDetailEditComponent
form={form}
roAutoCompleteOptions={RoAutoCompleteData && RoAutoCompleteData.jobs}
loadLines={loadLines}
lineData={lineData ? lineData.joblines : null}
responsibilityCenters={bodyshop.md_responsibility_centers || null}
/>
</Form>
</LoadingSkeleton>
);
}
export default connect(mapStateToProps, null)(InvoiceDetailEditContainer);

View File

@@ -9,7 +9,7 @@ export default function InvoiceEnterModalLinesComponent({
lineData,
discount,
form,
responsibilityCenters
responsibilityCenters,
}) {
const { t } = useTranslation();
const { setFieldsValue, getFieldsValue } = form;
@@ -25,14 +25,15 @@ export default function InvoiceEnterModalLinesComponent({
acc + (value && value.actual_cost ? value.actual_cost : 0),
0
)
: 0
: 0,
});
};
return (
<div>
<Form.List name="invoicelines" >
<Form.List name="invoicelines">
{(fields, { add, remove }) => {
console.log("fields", fields);
return (
<div>
{fields.map((field, index) => (
@@ -44,8 +45,8 @@ export default function InvoiceEnterModalLinesComponent({
rules={[
{
required: true,
message: t("general.validation.required")
}
message: t("general.validation.required"),
},
]}
>
<Select
@@ -55,7 +56,7 @@ export default function InvoiceEnterModalLinesComponent({
onSelect={(value, opt) => {
setFieldsValue({
invoicelines: getFieldsValue([
"invoicelines"
"invoicelines",
]).invoicelines.map((item, idx) => {
if (idx === index) {
return {
@@ -71,11 +72,11 @@ export default function InvoiceEnterModalLinesComponent({
? responsibilityCenters.defaults[
opt.part_type
] || null
: null
: null,
};
}
return item;
})
}),
});
}}
showSearch
@@ -88,7 +89,7 @@ export default function InvoiceEnterModalLinesComponent({
{t("invoicelines.labels.other")}
</Select.Option>
{lineData
? lineData.map(item => (
? lineData.map((item) => (
<Select.Option
key={item.id}
value={item.line_desc}
@@ -103,7 +104,7 @@ export default function InvoiceEnterModalLinesComponent({
<Col span={4}>
<Tag color="green">
<CurrencyFormatter>
{item.act_price}
{item.act_price || 0}
</CurrencyFormatter>
</Tag>
</Col>
@@ -113,26 +114,29 @@ export default function InvoiceEnterModalLinesComponent({
: null}
</Select>
</Form.Item>
{getFieldsValue("invoicelines").invoicelines[index] &&
getFieldsValue("invoicelines").invoicelines[index]
.joblinename &&
!getFieldsValue("invoicelines").invoicelines[index]
.joblineid ? (
<Form.Item
label={t("invoicelines.fields.line_desc")}
key={`${index}line_desc`}
name={[field.name, "line_desc"]}
rules={[
{
required: !getFieldsValue("invoicelines")
.invoicelines[index].joblineid,
message: t("general.validation.required")
}
]}
>
<Input />
</Form.Item>
) : null}
{
//TODO Will need to refactor this to use proper form components in the search select above.
getFieldsValue("invoicelines")[index] &&
// getFieldsValue("invoicelines")[index].joblinename &&
!getFieldsValue("invoicelines").invoicelines[index]
.joblineid ? (
<Form.Item
label={t("invoicelines.fields.line_desc")}
key={`${index}line_desc`}
name={[field.name, "line_desc"]}
rules={[
{
required: !getFieldsValue("invoicelines")[index]
.joblineid,
message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
) : null
}
<Form.Item
label={t("invoicelines.fields.actual")}
@@ -141,12 +145,12 @@ export default function InvoiceEnterModalLinesComponent({
rules={[
{
required: true,
message: t("general.validation.required")
}
message: t("general.validation.required"),
},
]}
>
<CurrencyInput
onBlur={e => {
onBlur={(e) => {
setFieldsValue({
invoicelines: getFieldsValue(
"invoicelines"
@@ -157,11 +161,11 @@ export default function InvoiceEnterModalLinesComponent({
actual_cost: !!item.actual_cost
? item.actual_cost
: parseFloat(e.target.value) *
(1 - discount)
(1 - discount),
};
}
return item;
})
}),
});
}}
/>
@@ -173,8 +177,8 @@ export default function InvoiceEnterModalLinesComponent({
rules={[
{
required: true,
message: t("general.validation.required")
}
message: t("general.validation.required"),
},
]}
>
<CurrencyInput onBlur={() => calculateTotals()} />
@@ -186,12 +190,12 @@ export default function InvoiceEnterModalLinesComponent({
rules={[
{
required: true,
message: t("general.validation.required")
}
message: t("general.validation.required"),
},
]}
>
<Select style={{ width: "150px" }}>
{responsibilityCenters.costs.map(item => (
{responsibilityCenters.costs.map((item) => (
<Select.Option key={item}>{item}</Select.Option>
))}
</Select>

View File

@@ -0,0 +1,132 @@
import React, { useState } from "react";
import { QUERY_INVOICES_BY_VENDOR } from "../../graphql/invoices.queries";
import { useQuery } from "@apollo/react-hooks";
import queryString from "query-string";
import { useHistory, useLocation } from "react-router-dom";
import { Table, Input } from "antd";
import { useTranslation } from "react-i18next";
import { alphaSort } from "../../utils/sorters";
import AlertComponent from "../alert/alert.component";
import { DateFormatter } from "../../utils/DateFormatter";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
export default function InvoicesByVendorList() {
const search = queryString.parse(useLocation().search);
const history = useHistory();
const { loading, error, data } = useQuery(QUERY_INVOICES_BY_VENDOR, {
variables: { vendorId: search.vendorid },
skip: !!!search.vendorid,
});
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
search: "",
});
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const handleOnRowClick = (record) => {
if (record) {
if (record.id) {
search.invoiceid = record.id;
history.push({ search: queryString.stringify(search) });
}
} else {
delete search.invoiceid;
history.push({ search: queryString.stringify(search) });
}
};
const columns = [
{
title: t("invoices.fields.invoice_number"),
dataIndex: "invoice_number",
key: "invoice_number",
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
sortOrder:
state.sortedInfo.columnKey === "invoice_number" &&
state.sortedInfo.order,
},
{
title: t("invoices.fields.date"),
dataIndex: "date",
key: "date",
sorter: (a, b) => a.date - b.date,
sortOrder:
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
},
{
title: t("invoices.fields.total"),
dataIndex: "total",
key: "total",
sorter: (a, b) => a.total - b.total,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.total}</CurrencyFormatter>
),
},
];
const handleSearch = (e) => {
setState({ ...state, search: e.target.value });
};
const dataSource = state.search
? data.invoices.filter(
(i) =>
(i.invoice_number || "")
.toLowerCase()
.includes(state.search.toLowerCase()) ||
(i.amount || "").toString().includes(state.search)
)
: (data && data.invoices) || [];
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<Table
loading={loading}
title={() => {
return (
<div>
<Input
value={state.search}
onChange={handleSearch}
placeholder={t("general.labels.search")}
allowClear
/>
</div>
);
}}
dataSource={dataSource}
size="small"
pagination={{ position: "top" }}
columns={columns}
rowKey="id"
onChange={handleTableChange}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [search.invoiceid],
type: "radio",
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
}, // click row
};
}}
/>
);
}

View File

@@ -0,0 +1,119 @@
import React, { useState } from "react";
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
import { useQuery } from "@apollo/react-hooks";
import queryString from "query-string";
import { useHistory, useLocation } from "react-router-dom";
import { Table, Input } from "antd";
import { useTranslation } from "react-i18next";
import { alphaSort } from "../../utils/sorters";
import AlertComponent from "../alert/alert.component";
export default function InvoicesVendorsList() {
const search = queryString.parse(useLocation().search);
const history = useHistory();
const { loading, error, data } = useQuery(QUERY_ALL_VENDORS);
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
search: "",
});
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const columns = [
{
title: t("vendors.fields.name"),
dataIndex: "name",
key: "name",
sorter: (a, b) => alphaSort(a.name, b.name),
sortOrder:
state.sortedInfo.columnKey === "name" && state.sortedInfo.order,
},
{
title: t("vendors.fields.cost_center"),
dataIndex: "cost_center",
key: "cost_center",
sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
sortOrder:
state.sortedInfo.columnKey === "cost_center" && state.sortedInfo.order,
},
{
title: t("vendors.fields.city"),
dataIndex: "city",
key: "city",
},
];
const handleOnRowClick = (record) => {
if (record) {
delete search.invoiceid;
if (record.id) {
search.vendorid = record.id;
history.push({ search: queryString.stringify(search) });
}
} else {
delete search.vendorid;
history.push({ search: queryString.stringify(search) });
}
};
const handleSearch = (e) => {
setState({ ...state, search: e.target.value });
};
if (error) return <AlertComponent message={error.message} type="error" />;
const dataSource = state.search
? data.vendors.filter(
(v) =>
(v.name || "").toLowerCase().includes(state.search.toLowerCase()) ||
(v.cost_center || "")
.toLowerCase()
.includes(state.search.toLowerCase()) ||
(v.city || "").toLowerCase().includes(state.search.toLowerCase())
)
: (data && data.vendors) || [];
return (
<Table
loading={loading}
title={() => {
return (
<div>
<Input
value={state.search}
onChange={handleSearch}
placeholder={t("general.labels.search")}
allowClear
/>
</div>
);
}}
dataSource={dataSource}
size="small"
pagination={{ position: "top" }}
columns={columns}
rowKey="id"
onChange={handleTableChange}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [search.vendorid],
type: "radio",
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
}, // click row
};
}}
/>
);
}

View File

@@ -18,15 +18,15 @@ const VendorSearchSelect = ({ value, onChange, options, onSelect }) => {
showSearch
value={option}
style={{
width: 300
width: 300,
}}
onChange={setOption}
optionFilterProp="children"
optionFilterProp="name"
onSelect={onSelect}
>
{options
? options.map(o => (
<Option key={o.id} value={o.id} discount={o.discount}>
? options.map((o) => (
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
<div style={{ display: "flex" }}>
{o.name}
<Tag color="green">{`${o.discount * 100}%`}</Tag>

View File

@@ -58,6 +58,24 @@ export const QUERY_INVOICES_BY_JOBID = gql`
}
`;
export const QUERY_INVOICES_BY_VENDOR = gql`
query QUERY_INVOICES_BY_VENDOR($vendorId: uuid!) {
invoices(
where: { vendorid: { _eq: $vendorId } }
order_by: { date: desc }
) {
id
job {
id
ro_number
}
total
invoice_number
date
}
}
`;
export const QUERY_INVOICE_BY_PK = gql`
query QUERY_INVOICE_BY_PK($invoiceid: uuid!) {
invoices_by_pk(id: $invoiceid) {
@@ -72,6 +90,7 @@ export const QUERY_INVOICE_BY_PK = gql`
total
updated_at
vendor {
id
name
discount
}

View File

@@ -36,7 +36,7 @@ export const UPDATE_VENDOR = gql`
export const QUERY_ALL_VENDORS = gql`
query QUERY_ALL_VENDORS {
vendors {
vendors(order_by: { name: asc }) {
name
id
street1

View File

@@ -1,188 +0,0 @@
import { Button, Descriptions, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters";
export default function InvoicesPageComponent({
loading,
invoices,
selectedInvoice,
handleFetchMore,
handleOnRowClick,
}) {
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
});
const columns = [
{
title: t("invoices.fields.vendorname"),
dataIndex: "vendorname",
key: "vendorname",
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
sortOrder:
state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
render: (text, record) => <span>{record.vendor.name}</span>,
},
{
title: t("invoices.fields.invoice_number"),
dataIndex: "invoice_number",
key: "invoice_number",
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
sortOrder:
state.sortedInfo.columnKey === "invoice_number" &&
state.sortedInfo.order,
},
{
title: t("invoices.fields.date"),
dataIndex: "date",
key: "date",
sorter: (a, b) => a.date - b.date,
sortOrder:
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
},
{
title: t("invoices.fields.total"),
dataIndex: "total",
key: "total",
sorter: (a, b) => a.total - b.total,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.total}</CurrencyFormatter>
),
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Link to={`/manage/invoices/${record.id}`}>
<Button>{t("invoices.actions.edit")}</Button>
</Link>
),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const rowExpander = (record) => {
const columns = [
{
title: t("invoicelines.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
sortOrder:
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
},
{
title: t("invoicelines.fields.retail"),
dataIndex: "actual_price",
key: "actual_price",
sorter: (a, b) => a.actual_price - b.actual_price,
sortOrder:
state.sortedInfo.columnKey === "actual_price" &&
state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.actual_price}</CurrencyFormatter>
),
},
{
title: t("invoicelines.fields.actual_cost"),
dataIndex: "actual_cost",
key: "actual_cost",
sorter: (a, b) => a.actual_cost - b.actual_cost,
sortOrder:
state.sortedInfo.columnKey === "actual_cost" &&
state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.actual_cost}</CurrencyFormatter>
),
},
{
title: t("invoicelines.fields.cost_center"),
dataIndex: "cost_center",
key: "cost_center",
sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
sortOrder:
state.sortedInfo.columnKey === "cost_center" &&
state.sortedInfo.order,
},
];
return (
<div>
<Descriptions title="User Info">
<Descriptions.Item label="UserName">Zhou Maomao</Descriptions.Item>
<Descriptions.Item label="Telephone">1810000000</Descriptions.Item>
<Descriptions.Item label="Live">Hangzhou, Zhejiang</Descriptions.Item>
<Descriptions.Item label="Remark">empty</Descriptions.Item>
<Descriptions.Item label="Address">
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China
</Descriptions.Item>
</Descriptions>
<Table
size="small"
pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={record.invoicelines}
/>
</div>
);
};
return (
<Table
loading={loading}
size="small"
expandedRowRender={rowExpander}
pagination={{
position: "top",
defaultPageSize: 1,
onChange: (page, pageSize) => {
handleOnRowClick(page * pageSize);
},
}}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
dataSource={invoices}
onChange={handleTableChange}
expandable={{
expandedRowKeys: [selectedInvoice],
onExpand: (expanded, record) => {
handleOnRowClick(expanded ? record : null);
},
}}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selectedInvoice],
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
};
}}
/>
);
}

View File

@@ -1,57 +1,23 @@
import { useQuery } from "@apollo/react-hooks";
import { Col, Row } from "antd";
import React from "react";
import { QUERY_ALL_INVOICES_PAGINATED } from "../../graphql/invoices.queries";
import InvoicesPageComponent from "./invoices.page.component";
import AlertComponent from "../../components/alert/alert.component";
import queryString from "query-string";
import { useHistory, useLocation } from "react-router-dom";
import InvoicesByVendorList from "../../components/invoices-by-vendor-list/invoices-by-vendor-list.component";
import VendorsList from "../../components/invoices-vendors-list/invoices-vendors-list.component";
import InvoiceDetailEditContainer from "../../components/invoice-detail-edit/invoice-detail-edit.container";
export default function InvoicesPageContainer() {
const { loading, error, data, fetchMore } = useQuery(
QUERY_ALL_INVOICES_PAGINATED,
{
variables: { offset: 0, limit: 1 },
}
);
const search = queryString.parse(useLocation().search);
const history = useHistory();
const handleOnRowClick = (record) => {
if (record) {
if (record.id) {
search.invoiceid = record.id;
history.push({ search: queryString.stringify(search) });
}
} else {
delete search.invoiceid;
history.push({ search: queryString.stringify(search) });
}
};
const handleFetchMore = (offset) => {
fetchMore({
variables: {
offset: offset,
},
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
return Object.assign({}, prev, {
invoices: [...prev.invoices, ...fetchMoreResult.invoices],
});
},
});
};
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<div>
<InvoicesPageComponent
loading={loading}
invoices={data ? data.invoices : null}
selectedInvoice={search.invoiceid}
handleFetchMore={handleFetchMore}
handleOnRowClick={handleOnRowClick}
/>
</div>
<Row>
<Col span={8}>
<VendorsList />
</Col>
<Col span={16}>
<Row>
<InvoicesByVendorList />
</Row>
<Row>
<InvoiceDetailEditContainer />
</Row>
</Col>
</Row>
);
}

View File

@@ -60,8 +60,6 @@ exports.receive = (req, res) => {
Object.keys(i).map((k) => allTokens.push(k))
);
const uniqueTokens = [...new Set(allTokens)];
console.log("exports.receive -> uniqueTokens", uniqueTokens);
var message = {
notification: {
title: `New SMS From ${phone(req.body.From)[0]}`,
@@ -80,7 +78,10 @@ exports.receive = (req, res) => {
.sendMulticast(message)
.then((response) => {
// Response is a message ID string.
console.log("Successfully sent message:", response);
console.log(
"Successfully sent message:",
JSON.stringify(response)
);
})
.catch((error) => {
console.log("Error sending message:", error);