UNPKG

canner

Version:

Build CMS in few lines of code for different data sources

190 lines (175 loc) 5.81 kB
// @flow import * as React from 'react'; import RefId from 'canner-ref-id'; import {createEmptyData} from 'canner-helpers'; import {get, update, mapValues, merge} from 'lodash'; import {List} from 'react-content-loader'; import type {HOCProps, Args} from './types'; import type {Query} from '../query'; type State = { canRender: boolean, refId: RefId }; export default function connectId(Com: React.ComponentType<*>) { return class ComponentConnectId extends React.Component<HOCProps, State> { refId: RefId; query: Query; reset: Function; args: Args; constructor(props: HOCProps) { super(props); const {routerParams, pattern, refId, keyName, routes} = props; let myRefId = refId; // route to children if (routerParams.operator === 'create' && pattern === 'array') { this.state = { canRender: false, refId: refId }; } else if (pattern === 'array' && routes.length > 1) { // in this case, // this hoc will fetch data with query {where: {id: id}} in componentDidMount this.state = { canRender: false, refId: null }; } else { myRefId = myRefId ? myRefId.child(keyName) : new RefId(keyName); this.state = { canRender: true, refId: myRefId }; } } UNSAFE_componentWillReceiveProps(props: HOCProps) { const {routerParams: {operator, payload}, pattern, items, keyName, routes, updateQuery} = props; if (operator === 'create' && this.props.routerParams.operator === 'update' && pattern ==='array') { // posts => posts?op=create let value = createEmptyData(items); update(value, 'id', id => id || randomId()); update(value, '__typename', typename => typename || null); this.setState({ canRender: false }); if (payload) { value = merge(value, payload); } this.createArray(keyName, value); } if (operator === 'update' && this.props.routerParams.operator === 'create' && pattern === 'array') { // posts?op=create => posts updateQuery([keyName], {first: 10, where: {}}) .then(() => { this.setState({ refId: new RefId(keyName) }); }); } if (pattern === 'array' && routes.length > 1 && this.props.routes.length === 1) { // posts => posts/<postId> this.setState({ canRender: false }); this.fetchById(routes[1], 400); } if (pattern === 'array' && routes.length === 1 && this.args && this.props.routes.length > 1) { // posts/<postId> => posts this.setState({ refId: new RefId(`${keyName}`) }); updateQuery([keyName], this.args) .then(() => { delete this.args; }); } } componentDidMount() { const {routerParams, pattern, keyName, items, routes} = this.props; if (routerParams.operator === 'create' && pattern === 'array') { // posts?op=create let value = createEmptyData(items); update(value, 'id', id => id || randomId()); update(value, '__typename', typename => typename || null); if (routerParams.payload) { value = merge(value, routerParams.payload); } this.createArray(keyName, value); } else if (pattern === 'array' && routes.length > 1) { // posts/<postId>/title this.fetchById(routes[1]); } else { this.setState({ canRender: true }); } } componentWillUnmount() { const {updateQuery, keyName, pattern} = this.props; if (pattern === 'array' && this.args) { updateQuery([keyName], this.args); } } fetchById = (id: string, timeIntervale?: number) => { const {query, keyName, updateQuery, fetch} = this.props; const paths = [keyName]; const queries = query.getQueries(paths).args || {pagination: {first: 10}}; const variables = query.getVairables(); // get current args this.args = mapValues(queries, v => variables[v.substr(1)]); this.setState({ canRender: false }) updateQuery(paths, { ...this.args, where: {id: id}, }).then(() => fetch(keyName)) .then(result => { let index = 0; if (result[keyName].edges) { index = result[keyName].edges.findIndex(edge => edge.cursor === id); } else { index = result[keyName].findIndex(item => item.id === id); } setTimeout(() => { this.setState({ canRender: true, refId: new RefId(`${keyName}/${index}`) }); }, timeIntervale || 0) }); } createArray = async (keyName: string, value: any) => { const {fetch, request, updateQuery} = this.props; await updateQuery([keyName], {first: 0}) await fetch(keyName) .then(result => { const size = get(result, [keyName, 'edges']).length; // $FlowFixMe return request({ type: 'CREATE_ARRAY', payload: { id: value.id, value, key: keyName, } }).then(() => size); }) .then(size => { this.setState({ canRender: true, refId: new RefId(`${keyName}/${size}`) }); }); } render() { let {canRender, refId} = this.state; if (!canRender) return <List style={{maxWidth: 600}}/>; return <Com {...this.props} refId={refId} /> } }; } function randomId() { return Math.random().toString(36).substr(2, 12); }