summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eug-vs@keemail.me>2021-03-14 07:05:45 +0300
committereug-vs <eug-vs@keemail.me>2021-03-14 07:05:45 +0300
commitde4811ce8d2e739901c047f39e9b4b7c18298e74 (patch)
tree01450303f497bb6c8433a360efc732f9fb9b4f08
parente615ad0282fa02ce7e81a847b43dd3146f69b769 (diff)
downloadcommercel-ui-de4811ce8d2e739901c047f39e9b4b7c18298e74.tar.gz
feat: add Contractors section
-rw-r--r--src/containers/ContractorForm.tsx52
-rw-r--r--src/containers/Contractors.tsx33
-rw-r--r--src/hooks/useAPIClient.ts31
-rw-r--r--src/index.tsx5
4 files changed, 119 insertions, 2 deletions
diff --git a/src/containers/ContractorForm.tsx b/src/containers/ContractorForm.tsx
new file mode 100644
index 0000000..7f0d660
--- /dev/null
+++ b/src/containers/ContractorForm.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import { useParams, useHistory } from 'react-router-dom';
+import { Formik, Form, Field } from 'formik';
+import Page, { Action } from './Page';
+import Input from '../components/Input';
+import { useContractor } from '../hooks/useAPIClient';
+import { post, patch } from '../requests';
+
+interface Params {
+ id: string;
+}
+
+const actions: Action[] = [
+ { name: 'Назад', variant: 'outlined', route: '..' },
+ { name: 'Сохранить', type: 'submit', form: 'contractorForm' },
+];
+
+const ContractorForm: React.FC = () => {
+ const history = useHistory();
+ const { id } = useParams<Params>();
+ const { data: contractor } = useContractor(id);
+
+ const onSubmit = (values: any) => {
+ const promise = id
+ ? patch(`/contractors/${id}`, values)
+ : post('/contractors', values);
+ return promise.then(() => history.push('/contractors'));
+ };
+
+ return (
+ <Page title={id ? contractor?.name : 'Новый контрагент'} actions={actions}>
+ {(!id || contractor) && (
+ <Formik
+ initialValues={contractor || { name: '', debt: '', vatId: '' }}
+ onSubmit={onSubmit}
+ >
+ {() => (
+ <Form id="contractorForm">
+ <div className="max-w-lg">
+ <Field name="name" label="Название" as={Input} />
+ <Field name="vatId" label="УНП" as={Input} />
+ <Field name="debt" type="number" label="Долг ($)" as={Input} />
+ </div>
+ </Form>
+ )}
+ </Formik>
+ )}
+ </Page>
+ );
+};
+
+export default ContractorForm;
diff --git a/src/containers/Contractors.tsx b/src/containers/Contractors.tsx
new file mode 100644
index 0000000..5d589ea
--- /dev/null
+++ b/src/containers/Contractors.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import Page from './Page';
+import ListTable from '../components/ListTable';
+import { useContractors } from '../hooks/useAPIClient';
+
+const fields = [
+ { key: 'vatId', label: 'УНП' },
+ { key: 'name', label: 'Название' },
+ { key: 'debt', label: 'Долг' },
+];
+
+const actions = [
+ { name: 'Добавить', route: 'contractors/add' },
+];
+
+const Contractors: React.FC = () => {
+ const history = useHistory();
+ const { data: contractors } = useContractors();
+
+ const handleRowClick = (index: number) => {
+ const contractor = contractors && contractors[index];
+ history.push(`/contractors/edit/${contractor?._id}`);
+ };
+
+ return (
+ <Page title="Контрагенты" actions={actions}>
+ <ListTable items={contractors} fields={fields} handleRowClick={handleRowClick} />
+ </Page>
+ );
+};
+
+export default Contractors;
diff --git a/src/hooks/useAPIClient.ts b/src/hooks/useAPIClient.ts
index f2f2782..eb427f1 100644
--- a/src/hooks/useAPIClient.ts
+++ b/src/hooks/useAPIClient.ts
@@ -4,6 +4,9 @@ import { get } from '../requests';
type Response<T> = responseInterface<T, Error>;
+const fetcher = (endpoint: string) => get(endpoint).then(response => response.data);
+
+// Products
export interface Product {
_id: string;
name: string;
@@ -15,8 +18,6 @@ export interface Product {
updatedAt: string;
}
-const fetcher = (endpoint: string) => get(endpoint).then(response => response.data);
-
export const useProducts = (options = {}): Response<Product[]> => {
return useSWR('/products', fetcher, options);
};
@@ -33,3 +34,29 @@ export const useProduct = (_id: string): Response<Product> => {
return result;
};
+
+// Contractors
+export interface Contractor {
+ _id: string;
+ name: string;
+ fullName: string;
+ vatId: string;
+ type: string;
+ debt: number;
+}
+
+export const useContractors = (options = {}): Response<Product[]> => {
+ return useSWR('/contractors', fetcher, options);
+};
+
+export const useContractor = (_id: string): Response<Product> => {
+ const { data: preloadedContractors } = useContractors({ revalidateOnMount: false });
+ const result = useSWR(_id && `/contractors/${_id}`, fetcher);
+ if (!result.data && result.isValidating) {
+ // If we are waiting for the first result, check if we can maybe
+ // get the data from already cached list for the time-being
+ const contractor = _.find(preloadedContractors, { _id });
+ return { ...result, data: contractor };
+ }
+ return result;
+};
diff --git a/src/index.tsx b/src/index.tsx
index 8af383e..4ec1db0 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -10,6 +10,8 @@ import Header from './components/Header';
import Home from './containers/Home';
import Products from './containers/Products';
import ProductForm from './containers/ProductForm';
+import Contractors from './containers/Contractors';
+import ContractorForm from './containers/ContractorForm';
const navigation = [
{ name: 'Главная', route: '/' },
@@ -26,6 +28,9 @@ const App: React.FC = () => (
<Route exact path="/products" component={Products} />
<Route exact path="/products/add" component={ProductForm} />
<Route exact path="/products/edit/:id" component={ProductForm} />
+ <Route exact path="/contractors" component={Contractors} />
+ <Route exact path="/contractors/add" component={ContractorForm} />
+ <Route exact path="/contractors/edit/:id" component={ContractorForm} />
</Switch>
</Router>
);