diff options
author | eug-vs <eug-vs@keemail.me> | 2021-03-26 01:06:44 +0300 |
---|---|---|
committer | eug-vs <eug-vs@keemail.me> | 2021-03-26 01:06:44 +0300 |
commit | 865b41114060765308d560181f4996c0aa7a3e74 (patch) | |
tree | 578d3089e05131445b0a8b6d5e69a3a76aaf7e73 /src/lib | |
parent | 91e1a3b4ccaa822097e4adfea5f51056b010fdd6 (diff) | |
download | commercel-ui-865b41114060765308d560181f4996c0aa7a3e74.tar.gz |
refactor: move Service to lib/
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Service.tsx | 25 | ||||
-rw-r--r-- | src/lib/ServiceContext.tsx | 37 | ||||
-rw-r--r-- | src/lib/ServiceItem.tsx | 59 | ||||
-rw-r--r-- | src/lib/ServiceList.tsx | 35 |
4 files changed, 156 insertions, 0 deletions
diff --git a/src/lib/Service.tsx b/src/lib/Service.tsx new file mode 100644 index 0000000..b527531 --- /dev/null +++ b/src/lib/Service.tsx @@ -0,0 +1,25 @@ +import React, { useContext } from 'react'; +import { Route, Switch, useRouteMatch } from 'react-router-dom'; +import _ from 'lodash'; +import ServiceList from './ServiceList'; +import ServiceItem from './ServiceItem'; +import ServiceContext from './ServiceContext'; + + +const Service: React.FC = () => { + const { path } = useRouteMatch(); + const service = useContext(ServiceContext); + + return ( + <Switch> + <Route exact path={path} component={ServiceList} /> + <Route path={`${path}/add`} component={ServiceItem} /> + {_.map(service.routes, (component, route) => ( + <Route path={`${path}/${route}`} component={component} key={route} /> + ))} + <Route path={`${path}/:id`} component={ServiceItem} /> + </Switch> + ); +}; + +export default Service; diff --git a/src/lib/ServiceContext.tsx b/src/lib/ServiceContext.tsx new file mode 100644 index 0000000..93cac4e --- /dev/null +++ b/src/lib/ServiceContext.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { FormikProps } from 'formik'; +import { Props as ButtonProps } from '../components/Button'; +import { Field } from '../components/ListTable'; + +export interface Action extends ButtonProps { + name: string; +} + +export interface PanelProps { + item: any; + mutate: (item: any) => void; +} + +export interface ServiceParams { + route: string; + name: string; + tableFields: Field[]; + nameSingular?: string; + default?: Record<string, any>; + routes?: Record<string, React.FC>; + actions?: Action[]; + rowLink?: (item: any) => string; + Form?: React.FC<FormikProps<any>>; + Panel?: React.FC<PanelProps>; +} + +const ServiceContext = React.createContext<ServiceParams>({ + route: '', + name: '', + nameSingular: '', + tableFields: [], + default: {}, +}); + +export const ServiceProvider = ServiceContext.Provider; +export default ServiceContext; diff --git a/src/lib/ServiceItem.tsx b/src/lib/ServiceItem.tsx new file mode 100644 index 0000000..6a0a99b --- /dev/null +++ b/src/lib/ServiceItem.tsx @@ -0,0 +1,59 @@ +import React, { useContext } from 'react'; +import { useParams, useHistory } from 'react-router-dom'; +import { Formik } from 'formik'; +import _ from 'lodash'; +import Page from '../containers/Page'; +import hooks from '../hooks/useAPIClient'; +import useQuery from '../hooks/useQuery'; +import { post, patch, del } from '../requests'; +import ServiceContext, { Action } from './ServiceContext'; + +interface Params { + id: string; +} + +const ServiceItem: React.FC = () => { + const service = useContext(ServiceContext); + const history = useHistory(); + const query = useQuery(); + const { id } = useParams<Params>(); + const { data: item, mutate } = hooks[service.route].useItem(id); + + const handleDelete = () => del(`/${service.route}/${id}`) + .then(() => history.push(`/${service.route}`)); + + const onSubmit = (values: any) => { + const promise = id + ? patch(`/${service.route}/${id}`, values) + : post(`/${service.route}`, values); + return promise.then(response => { + mutate(response.data); + history.push(`/${service.route}`); + }); + }; + + const actions: Action[] = _.compact([ + { name: 'Назад', variant: 'outlined', onClick: history.goBack }, + id && { name: 'Удалить', variant: 'outlined', onClick: handleDelete }, + { name: 'Сохранить', type: 'submit', form: 'form' }, + ]); + + return ( + <Page + title={id ? item?.name : `Новый ${service.nameSingular}`} + actions={actions} + className="grid lg:grid-cols-2" + > + {(!id || item) && ( + <Formik + initialValues={_.defaults(item, query, service.default)} + onSubmit={onSubmit} + children={service.Form} + /> + )} + {item && service.Panel && <service.Panel item={item} mutate={mutate} />} + </Page> + ); +}; + +export default ServiceItem; diff --git a/src/lib/ServiceList.tsx b/src/lib/ServiceList.tsx new file mode 100644 index 0000000..74ad10b --- /dev/null +++ b/src/lib/ServiceList.tsx @@ -0,0 +1,35 @@ +import React, { useContext } from 'react'; +import { useHistory, useLocation } from 'react-router-dom'; +import Page from '../containers/Page'; +import ListTable from '../components/ListTable'; +import hooks from '../hooks/useAPIClient'; +import ServiceContext from './ServiceContext'; + +const ServiceList: React.FC = () => { + const service = useContext(ServiceContext); + const history = useHistory(); + const location = useLocation(); + const { data } = hooks[service.route].useList(location.search); + + const actions = service.actions || [{ + name: 'Добавить', + route: `/${service.route}/add${location.search}`, + }]; + + const handleRowClick = (index: number) => { + const item = data && data[index]; + const route = service.rowLink + ? service.rowLink(item) + : `/${service.route}/${item?._id}`; + + history.push(route); + }; + + return ( + <Page title={service.name} actions={actions}> + <ListTable items={data} fields={service.tableFields} handleRowClick={handleRowClick} /> + </Page> + ); +}; + +export default ServiceList; |