diff --git a/.lintstagedrc.js b/.lintstagedrc.js index 5f4fac86d3de9dabc4b23ccff0801fc3d5882e11..f44e52aacba3468ded7f859823e3462c337c3652 100644 --- a/.lintstagedrc.js +++ b/.lintstagedrc.js @@ -14,7 +14,7 @@ const buildPrettierPhpCommand = (filenames) => .join(" ")}`; module.exports = { - "src/**/*.{js,jsx,ts,tsx}": [buildEslintCommand], + // "src/**/*.{js,jsx,ts,tsx}": [buildEslintCommand], "*.{json,js,ts,jsx,tsx,html,css}": [buildPrettierCommand], "*.php": [buildPrettierPhpCommand], }; diff --git a/includes/class-rest-controller.php b/includes/class-rest-controller.php index 7e29bbff58676ebb64a3a32ff2de68bfbb3d05e5..962733399288183f189a27ff6878413ebb0d22d6 100644 --- a/includes/class-rest-controller.php +++ b/includes/class-rest-controller.php @@ -42,6 +42,20 @@ class REST_Controller ] ); + register_rest_route( + "{$this->namespace}/v{$this->version}", + '/erp-forms/form/(?P<id>[\d]+)', + [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => function ($req) { + return $this->form_fields($req); + }, + 'permission_callback' => function () { + return $this->permission_callback(); + }, + ] + ); + register_rest_route( "{$this->namespace}/v{$this->version}", '/erp-forms/settings/', @@ -79,6 +93,26 @@ class REST_Controller return $response; } + private function form_fields($req) + { + $target = null; + $form_id = $req->get_url_params()['id']; + $forms = Settings::get_forms(); + foreach ($forms as $form) { + if ($form->id === $form_id) { + $target = $form; + break; + } + } + + if (!$target) { + throw new Exception('Unkown form'); + } + + $fields = apply_filters('wpct_erp_forms_form_fields', [], $form_id); + return $fields; + } + private function get_settings() { $settings = []; diff --git a/includes/class-settings.php b/includes/class-settings.php index 554d81735019dcece1215b9427a2ef36fb9c5141..083af89db3b2ec0721315f5ea4e8fc2323358043 100644 --- a/includes/class-settings.php +++ b/includes/class-settings.php @@ -2,7 +2,6 @@ namespace WPCT_ERP_FORMS; -use Exception; use WPCT_ABSTRACT\Settings as BaseSettings; class Settings extends BaseSettings @@ -114,6 +113,16 @@ class Settings extends BaseSettings 'form_id' => ['type' => 'string'], 'endpoint' => ['type' => 'string'], 'ref' => ['type' => 'string'], + 'pipes' => [ + 'type' => 'array', + 'items' => [ + 'type' => 'object', + 'properties' => [ + 'from' => ['type' => 'string'], + 'to' => ['type' => 'string'], + ], + ], + ], ], ], ], @@ -125,6 +134,7 @@ class Settings extends BaseSettings 'form_id' => null, 'endpoint' => '/api/crm-lead', 'ref' => null, + 'pipes' => [], ], ], ] @@ -154,6 +164,16 @@ class Settings extends BaseSettings 'form_id' => ['type' => 'string'], 'model' => ['type' => 'string'], 'ref' => ['type' => 'string'], + 'pipes' => [ + 'type' => 'array', + 'items' => [ + 'type' => 'object', + 'properties' => [ + 'from' => ['type' => 'string'], + 'to' => ['type' => 'string'], + ], + ], + ], ], ], ], @@ -169,6 +189,7 @@ class Settings extends BaseSettings 'form_id' => 0, 'model' => 'crm.lead', 'ref' => null, + 'pipes' => [], ], ], ] diff --git a/src/FormPipes/Table.jsx b/src/FormPipes/Table.jsx new file mode 100644 index 0000000000000000000000000000000000000000..49ac9697fd130e0a03024cdd01c33b39c975dc2c --- /dev/null +++ b/src/FormPipes/Table.jsx @@ -0,0 +1,105 @@ +// vendor +import React from "react"; +import { __ } from "@wordpress/i18n"; +import { + SelectControl, + TextControl, + Button, + __experimentalSpacer as Spacer, +} from "@wordpress/components"; +import { useEffect } from "@wordpress/element"; + +// vendor +import useFormFields from "../hooks/useFormFields"; + +export default function PipesTable({ formId, pipes, setPipes }) { + const { fields, loading } = useFormFields({ formId }); + const fromOptions = fields.map((field) => ({ + label: field.label, + value: field.name, + })); + + const setPipe = (attr, index, value) => { + const newPipes = pipes.map((pipe, i) => { + if (index === i) pipe[attr] = value; + return { ...pipe }; + }); + + setPipes(newPipes); + }; + + const addPipe = () => { + const newPipes = pipes.concat([{ from: "", to: "" }]); + setPipes(newPipes); + }; + + const dropPipe = (index) => { + const newPipes = pipes.slice(0, index).concat(pipes.slice(index + 2)); + setPipes(newPipes); + }; + + useEffect(() => { + if (!pipes.length) addPipe(); + }, [pipes]); + + if (loading) return <p>Loading...</p>; + + return ( + <div className="components-base-control__label"> + <label + className="components-base-control__label" + style={{ + fontSize: "11px", + textTransform: "uppercase", + fontWeight: 500, + marginBottom: "calc(8px)", + }} + > + {__("Form format pipes", "wpct-erp-forms")} + </label> + <table style={{ width: "100%" }}> + <tbody> + {pipes.map(({ from, to }, i) => ( + <tr key={i}> + <td> + <SelectControl + label={__("From", "wpct-erp-forms")} + value={from} + onChange={(value) => setPipe("from", i, value)} + options={fromOptions} + __nextHasNoMarginBottom + /> + </td> + <td> + <TextControl + placeholder={__("To", "wpct-erp-forms")} + value={to} + onChange={(value) => setPipe("to", i, value)} + __nextHasNoMarginBottom + /> + </td> + <td style={{ borderLeft: "1rem solid transparent" }}> + <Button + isDestructive + variant="secondary" + onClick={() => dropPipe(i)} + style={{ height: "32px" }} + > + {__("Drop", "wpct-erp-forms")} + </Button> + </td> + </tr> + ))} + </tbody> + </table> + <Spacer paddingY="calc(3px)" /> + <Button + variant="secondary" + onClick={() => addPipe()} + style={{ height: "32px" }} + > + {__("Add", "wpct-erp-forms")} + </Button> + </div> + ); +} diff --git a/src/FormPipes/index.jsx b/src/FormPipes/index.jsx new file mode 100644 index 0000000000000000000000000000000000000000..5ca60af02dda811913f351a1fd2a73b3573e3913 --- /dev/null +++ b/src/FormPipes/index.jsx @@ -0,0 +1,32 @@ +// vendor +import React from "react"; +import { __ } from "@wordpress/i18n"; +import { Button, Modal } from "@wordpress/components"; +import { useState } from "@wordpress/element"; + +// source +import PipesTable from "./Table"; + +export default function FormPipes({ formId, pipes, setPipes }) { + const [open, setOpen] = useState(false); + + return ( + <> + <Button + variant="secondary" + onClick={() => setOpen(true)} + style={{ width: "130px", justifyContent: "center", height: "32px" }} + > + {__("Pipes", "wpct-erp-forms")} + </Button> + {open && ( + <Modal + title={__("Form pipes", "wpct-erp-forms")} + onRequestClose={() => setOpen(false)} + > + <PipesTable formId={formId} pipes={pipes} setPipes={setPipes} /> + </Modal> + )} + </> + ); +} diff --git a/src/GeneralSettings/Backends/Headers.jsx b/src/GeneralSettings/Backends/Headers.jsx index 62d3161cadf5d204bcc135033b887ae73a529580..cfa0233290b5a80c33e097326684ca3c47f3fa85 100644 --- a/src/GeneralSettings/Backends/Headers.jsx +++ b/src/GeneralSettings/Backends/Headers.jsx @@ -6,6 +6,7 @@ import { Button, __experimentalSpacer as Spacer, } from "@wordpress/components"; +import { useEffect } from "@wordpress/element"; export default function BackendHeaders({ headers, setHeaders }) { const setHeader = (attr, index, value) => { @@ -27,6 +28,10 @@ export default function BackendHeaders({ headers, setHeaders }) { setHeaders(newHeaders); }; + useEffect(() => { + if (!headers.length) addHeader(); + }, [headers]); + return ( <div className="components-base-control__label"> <label @@ -54,7 +59,7 @@ export default function BackendHeaders({ headers, setHeaders }) { </td> <td> <TextControl - placeholder={__("Value")} + placeholder={__("Value", "wpct-erp-forms")} value={value} onChange={(value) => setHeader("value", i, value)} __nextHasNoMarginBottom diff --git a/src/RestApiSettings/Forms/Form.jsx b/src/RestApiSettings/Forms/Form.jsx index cad6f665fc68a662655a7e0600e35276d3204ef0..49d51bad39d5d2bd34e77c98959afeacc6509031 100644 --- a/src/RestApiSettings/Forms/Form.jsx +++ b/src/RestApiSettings/Forms/Form.jsx @@ -7,6 +7,7 @@ import { useState, useRef, useEffect } from "@wordpress/element"; // source import { useForms } from "../../providers/Forms"; import { useGeneral } from "../../providers/Settings"; +import FormPipes from "../../FormPipes"; function NewForm({ add }) { const [{ backends }] = useGeneral(); @@ -164,6 +165,24 @@ export default function Form({ update, remove, ...data }) { options={formOptions} __nextHasNoMarginBottom /> + <div> + <label + style={{ + display: "block", + fontWeight: 500, + textTransform: "uppercase", + fontSize: "11px", + marginBottom: "calc(4px)", + }} + > + {__("Edit pipes", "wpct-erp-forms")} + </label> + <FormPipes + formId={data.form_id} + pipes={data.pipes} + setPipes={(pipes) => update({ ...data, pipes })} + /> + </div> <div> <label style={{ diff --git a/src/RestApiSettings/Forms/index.jsx b/src/RestApiSettings/Forms/index.jsx index 93598ce453c7cb0b3ea66e2fc4efcf740cf6c713..d113d28649576572d4f38df927f0ac354ddfafe7 100644 --- a/src/RestApiSettings/Forms/index.jsx +++ b/src/RestApiSettings/Forms/index.jsx @@ -8,12 +8,13 @@ import Form from "./Form"; export default function Forms({ forms, setForms }) { const tabs = forms - .map(({ backend, endpoint, form_id, ref }) => ({ + .map(({ backend, endpoint, form_id, ref, pipes }) => ({ name: ref, title: ref, form_id, endpoint, backend, + pipes, })) .concat([ { diff --git a/src/RpcApiSettings/Forms/Form.jsx b/src/RpcApiSettings/Forms/Form.jsx index 5c55b40c9ee4e489ab05f4cb82f6af1d823b53bc..0e51fce2e1a7e24e4f9ba9e18604b85eff359d3f 100644 --- a/src/RpcApiSettings/Forms/Form.jsx +++ b/src/RpcApiSettings/Forms/Form.jsx @@ -7,6 +7,7 @@ import { useState, useRef, useEffect } from "@wordpress/element"; // source import { useForms } from "../../providers/Forms"; import { useGeneral } from "../../providers/Settings"; +import FormPipes from "../../FormPipes"; function NewForm({ add }) { const [{ backends }] = useGeneral(); @@ -165,6 +166,24 @@ export default function Form({ update, remove, ...data }) { options={formOptions} __nextHasNoMarginBottom /> + <div> + <label + style={{ + display: "block", + fontWeight: 500, + textTransform: "uppercase", + fontSize: "11px", + marginBottom: "calc(4px)", + }} + > + {__("Edit pipes", "wpct-erp-forms")} + </label> + <FormPipes + formId={data.form_id} + pipes={data.pipes} + setPipes={(pipes) => update({ ...data, pipes })} + /> + </div> <div> <label style={{ diff --git a/src/RpcApiSettings/Forms/index.jsx b/src/RpcApiSettings/Forms/index.jsx index 0f734c1680e04574d6acc211d2c829a2df6b5d8d..fb1baff861ecf556e55dee9518a3ee671b4f0bde 100644 --- a/src/RpcApiSettings/Forms/index.jsx +++ b/src/RpcApiSettings/Forms/index.jsx @@ -8,12 +8,13 @@ import Form from "./Form"; export default function Forms({ forms, setForms }) { const tabs = forms - .map(({ backend, model, form_id, ref }) => ({ + .map(({ backend, model, form_id, ref, pipes }) => ({ name: ref, title: ref, form_id, model, backend, + pipes, })) .concat([ { diff --git a/src/hooks/useFormFields.js b/src/hooks/useFormFields.js new file mode 100644 index 0000000000000000000000000000000000000000..dfe491aee7dfde6915365d6c622e0d60c8618d6d --- /dev/null +++ b/src/hooks/useFormFields.js @@ -0,0 +1,22 @@ +// vendor +import { __ } from "@wordpress/i18n"; +import apiFetch from "@wordpress/api-fetch"; +import { useState, useEffect } from "@wordpress/element"; + +export default function useFormFields({ formId }) { + const [loading, setLoading] = useState(); + const [fields, setFields] = useState([]); + + useEffect(() => { + apiFetch({ + path: `${window.wpApiSettings.root}wpct/v1/erp-forms/form/${formId}`, + headers: { + "X-WP-Nonce": wpApiSettings.nonce, + }, + }) + .then((fields) => setFields(fields)) + .finally(() => setLoading(false)); + }, []); + + return { loading, fields }; +}