Finish the majority of work on vendors page to add/delete/edit.
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { Button, Form, Input, notification } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import { Form, Input, notification, Button } from "antd";
|
||||
import { updateUserDetails } from "../../redux/user/user.actions";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import ResetForm from "../form-items-formatted/reset-form-item.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser
|
||||
@@ -47,33 +47,26 @@ export default connect(
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isFieldsTouched() ? (
|
||||
//TODO: Appropriate Error
|
||||
<AlertComponent
|
||||
message={t("jobs.errors.validation")}
|
||||
onClick={() => resetFields()}
|
||||
/>
|
||||
) : null}
|
||||
{isFieldsTouched() ? <ResetForm resetFields={resetFields} /> : null}
|
||||
|
||||
<Form onSubmit={handleSubmit} autoComplete={"no"}>
|
||||
<Form.Item label={t("user.fields.displayname")}>
|
||||
{getFieldDecorator("displayname", {
|
||||
initialValue: currentUser.displayName,
|
||||
rules: [{ required: true }]
|
||||
})(<Input name="displayname" />)}
|
||||
})(<Input name='displayname' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("user.fields.photourl")}>
|
||||
{getFieldDecorator("photoURL", {
|
||||
initialValue: currentUser.photoURL
|
||||
})(<Input name="photoURL" />)}
|
||||
})(<Input name='photoURL' />)}
|
||||
</Form.Item>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
key="submit"
|
||||
htmlType="submit"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
type='primary'
|
||||
key='submit'
|
||||
htmlType='submit'
|
||||
onClick={handleSubmit}>
|
||||
{t("user.actions.updateprofile")}
|
||||
</Button>
|
||||
</Form>
|
||||
|
||||
114
client/src/components/vendors-form/vendors-form.component.jsx
Normal file
114
client/src/components/vendors-form/vendors-form.component.jsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import { Button, Form, Input, InputNumber, Switch } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||
import ResetForm from "../form-items-formatted/reset-form-item.component";
|
||||
export default function VendorsFormComponent({ form, vendor, handleDelete }) {
|
||||
const {
|
||||
getFieldDecorator,
|
||||
isFieldsTouched,
|
||||
getFieldValue,
|
||||
resetFields
|
||||
} = form;
|
||||
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
{isFieldsTouched() ? <ResetForm resetFields={resetFields} /> : null}
|
||||
<Button htmlType='submit' type='primary'>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
<Button type='danger' onClick={handleDelete}>
|
||||
{t("general.actions.delete")}
|
||||
</Button>
|
||||
<Form.Item label={t("vendors.fields.zip")}>
|
||||
{getFieldDecorator("zip", {
|
||||
initialValue: vendor.zip
|
||||
})(<Input name='zip' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.terms")}>
|
||||
{getFieldDecorator("terms", {
|
||||
initialValue: vendor.terms
|
||||
})(<Input name='terms' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.taxid")}>
|
||||
{getFieldDecorator("taxid", {
|
||||
initialValue: vendor.taxid
|
||||
})(<Input name='taxid' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.street1")}>
|
||||
{getFieldDecorator("street1", {
|
||||
initialValue: vendor.street1
|
||||
})(<Input name='street1' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.street2")}>
|
||||
{getFieldDecorator("street2", {
|
||||
initialValue: vendor.street2
|
||||
})(<Input name='street2' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.state")}>
|
||||
{getFieldDecorator("state", {
|
||||
initialValue: vendor.state
|
||||
})(<Input name='state' />)}
|
||||
</Form.Item>{" "}
|
||||
<Form.Item label={t("vendors.fields.prompt_discount")}>
|
||||
{getFieldDecorator("prompt_discount", {
|
||||
initialValue: vendor.prompt_discount
|
||||
})(<InputNumber name='prompt_discount' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.name")}>
|
||||
{getFieldDecorator("name", {
|
||||
initialValue: vendor.name
|
||||
})(<Input name='name' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.favorite")}>
|
||||
{getFieldDecorator("favorite", {
|
||||
initialValue: vendor.favorite,
|
||||
valuePropName: "checked"
|
||||
})(<Switch name='favorite' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.email")}>
|
||||
{getFieldDecorator("email", {
|
||||
initialValue: vendor.email,
|
||||
rules: [
|
||||
{
|
||||
type: "email",
|
||||
message: t("general.validation.invalidemail")
|
||||
}
|
||||
]
|
||||
})(<FormItemEmail name='email' email={getFieldValue("email")} />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.due_date")}>
|
||||
{getFieldDecorator("due_date", {
|
||||
initialValue: vendor.due_date
|
||||
})(<InputNumber name='due_date' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.display_name")}>
|
||||
{getFieldDecorator("display_name", {
|
||||
initialValue: vendor.display_name
|
||||
})(<Input name='display_name' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.discount")}>
|
||||
{getFieldDecorator("discount", {
|
||||
initialValue: vendor.discount
|
||||
})(<InputNumber name='discount' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.country")}>
|
||||
{getFieldDecorator("country", {
|
||||
initialValue: vendor.country
|
||||
})(<Input name='country' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.cost_center")}>
|
||||
{getFieldDecorator("cost_center", {
|
||||
initialValue: vendor.cost_center,
|
||||
rules: [{ required: true, message: t("general.validation.required") }]
|
||||
})(<Input name='cost_center' />)}
|
||||
</Form.Item>
|
||||
<Form.Item label={t("vendors.fields.city")}>
|
||||
{getFieldDecorator("city", {
|
||||
initialValue: vendor.city
|
||||
})(<Input name='city' />)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
109
client/src/components/vendors-form/vendors-form.container.jsx
Normal file
109
client/src/components/vendors-form/vendors-form.container.jsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React from "react";
|
||||
import { Form } from "antd";
|
||||
import VendorsFormComponent from "./vendors-form.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { notification } from "antd";
|
||||
import {
|
||||
UPDATE_VENDOR,
|
||||
INSERT_NEW_VENDOR,
|
||||
DELETE_VENDOR
|
||||
} from "../../graphql/vendors.queries";
|
||||
import { useMutation } from "react-apollo";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
function VendorsFormContainer({ form, vendor, refetch, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
const [updateVendor] = useMutation(UPDATE_VENDOR);
|
||||
const [insertvendor] = useMutation(INSERT_NEW_VENDOR);
|
||||
const [deleteVendor] = useMutation(DELETE_VENDOR);
|
||||
const handleDelete = () => {
|
||||
deleteVendor({ variables: { id: vendor.id } })
|
||||
.then(r => {
|
||||
notification["success"]({
|
||||
message: t("vendors.successes.deleted")
|
||||
});
|
||||
//TODO: Better way to reset the field decorators?
|
||||
if (refetch) refetch().then(r => form.resetFields());
|
||||
})
|
||||
.catch(error => {
|
||||
notification["error"]({
|
||||
message: t("vendors.errors.deleting")
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
form.validateFieldsAndScroll((err, values) => {
|
||||
if (err) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.validationtitle"),
|
||||
description: t("jobs.errors.validation")
|
||||
});
|
||||
}
|
||||
if (!err) {
|
||||
if (vendor.id) {
|
||||
//It's a vendor to update.
|
||||
updateVendor({
|
||||
variables: { id: vendor.id, vendor: values }
|
||||
})
|
||||
.then(r => {
|
||||
notification["success"]({
|
||||
message: t("vendors.successes.saved")
|
||||
});
|
||||
//TODO: Better way to reset the field decorators?
|
||||
if (refetch) refetch().then(r => form.resetFields());
|
||||
})
|
||||
.catch(error => {
|
||||
notification["error"]({
|
||||
message: t("vendors.errors.saving")
|
||||
});
|
||||
});
|
||||
} else {
|
||||
//It's a new vendor to insert.
|
||||
insertvendor({
|
||||
variables: { vendorInput: [{ ...values, bodyshopid: bodyshop.id }] }
|
||||
})
|
||||
.then(r => {
|
||||
notification["success"]({
|
||||
message: t("vendors.successes.saved")
|
||||
});
|
||||
//TODO: Better way to reset the field decorators?
|
||||
if (refetch) refetch().then(r => form.resetFields());
|
||||
})
|
||||
.catch(error => {
|
||||
notification["error"]({
|
||||
message: t("vendors.errors.saving")
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form onSubmit={handleSubmit} autoComplete='new-password'>
|
||||
{vendor ? (
|
||||
<VendorsFormComponent
|
||||
form={form}
|
||||
vendor={vendor}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
) : (
|
||||
t("vendors.labels.noneselected")
|
||||
)}
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(Form.create({ name: "VendorsFormContainer" })(VendorsFormContainer));
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Input, Table } from "antd";
|
||||
import { Input, Table, Button } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
export default function VendorsListComponent({
|
||||
selectedVendor,
|
||||
setSelectedVendor,
|
||||
handleNewVendor,
|
||||
loading,
|
||||
refetch,
|
||||
handleOnRowClick,
|
||||
vendors
|
||||
}) {
|
||||
const [state, setState] = useState({
|
||||
@@ -57,14 +59,6 @@ export default function VendorsListComponent({
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
};
|
||||
|
||||
const handleOnRowClick = record => {
|
||||
if (record) {
|
||||
setSelectedVendor(record);
|
||||
return;
|
||||
}
|
||||
setSelectedVendor(null);
|
||||
};
|
||||
|
||||
//TODO Implement search
|
||||
return (
|
||||
<div>
|
||||
@@ -72,19 +66,25 @@ export default function VendorsListComponent({
|
||||
loading={loading}
|
||||
title={() => {
|
||||
return (
|
||||
<Input.Search
|
||||
placeholder={t("general.labels.search")}
|
||||
onSearch={value => {
|
||||
console.log(value);
|
||||
}}
|
||||
enterButton
|
||||
/>
|
||||
<div>
|
||||
{" "}
|
||||
<Input.Search
|
||||
placeholder={t("general.labels.search")}
|
||||
onSearch={value => {
|
||||
console.log(value);
|
||||
}}
|
||||
enterButton
|
||||
/>
|
||||
<Button onClick={handleNewVendor}>
|
||||
{t("vendors.actions.new")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
size='small'
|
||||
pagination={{ position: "top" }}
|
||||
columns={columns.map(item => ({ ...item }))}
|
||||
rowKey="id"
|
||||
rowKey='id'
|
||||
onChange={handleTableChange}
|
||||
dataSource={vendors}
|
||||
rowSelection={{
|
||||
@@ -92,7 +92,7 @@ export default function VendorsListComponent({
|
||||
setSelectedVendor(record);
|
||||
},
|
||||
type: "radio",
|
||||
selectedRowKeys: selectedVendor.id || null
|
||||
selectedRowKeys: selectedVendor ? selectedVendor.id : null
|
||||
}}
|
||||
onRow={(record, rowIndex) => {
|
||||
return {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { useQuery } from "react-apollo";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import { QUERY_ALL_VENDORS, QUERY_VENDOR_BY_ID } from "../../graphql/vendors.queries";
|
||||
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
|
||||
import VendorsListComponent from "./vendors-list.component";
|
||||
|
||||
export default function VendorsListContainer({ selectedVendorState }) {
|
||||
@@ -10,23 +10,28 @@ export default function VendorsListContainer({ selectedVendorState }) {
|
||||
fetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
const vendorDetail = useQuery(QUERY_VENDOR_BY_ID, {
|
||||
fetchPolicy: "network-only",
|
||||
variables: { id: selectedVendor.id },
|
||||
skip: !selectedVendor.id
|
||||
});
|
||||
const handleNewVendor = () => {
|
||||
setSelectedVendor({});
|
||||
};
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
const handleOnRowClick = record => {
|
||||
if (record) {
|
||||
setSelectedVendor(record);
|
||||
return;
|
||||
}
|
||||
setSelectedVendor(null);
|
||||
};
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
return (
|
||||
<div>
|
||||
<VendorsListComponent
|
||||
selectedVendor={selectedVendor}
|
||||
setSelectedVendor={setSelectedVendor}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
vendors={data ? data.vendors : null}
|
||||
/>
|
||||
{JSON.stringify(vendorDetail && vendorDetail.data)}
|
||||
</div>
|
||||
<VendorsListComponent
|
||||
selectedVendor={selectedVendor}
|
||||
setSelectedVendor={setSelectedVendor}
|
||||
handleNewVendor={handleNewVendor}
|
||||
handleOnRowClick={handleOnRowClick}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
vendors={data ? data.vendors : null}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user