Source: data/FormDecidir.js

import React, { useEffect, useRef, useState } from "react";
import { useReactorNavigation } from "../../_core";
import { FormContext, uuid } from "../..";
import { getFormData } from "./FormExt";

/**
 * Componente que renderiza un formulario especial para integrar Decidir.
 * Todos los input dentro de Form deben contener la propiedad name con el identificador del campo
 * @name Reactor.Components.Data.FormDecidir
 * @param {string!} url_decidir Url de la API de decidir
 * @param {string!} public_api_key Public key para acceder a los servicios
 * @param {string!} action Nombre de la operación de destino
 * @param {string?} data Json string con datos que pueden agregarse al form para evitar inputs de tipo hidden
 * @param {NavigationTarget} [target = "menu"] Destino del resultado 
 * @param {DirectionType} direction Dirección en la que va a mostrarse el menú
 * @param {string?} offcanvas_class Clase css que se va a dar al menú 
 * @param {BooleanString} [use_token = "false"] Establece si se debe guardar el token que devuelve Orquesta, sirve para luego poder continuar el flujo con otro form, si es false no se guarda y el flujo termina
 * @param {BooleanString} [use_prev_token = "true"] Establece si debe enviarse el token que está en memoria, sirve para continuar la ejecución de un flujo, si es false el token se envía null
 * @param {BooleanString} [use_spinner = "true"] Establece si se muestra un spinner mientras se espera la respuesta del servidor
 * @param {BooleanString} [inhabilitar_cs = "false"] Para inhabilitar el Servicio de Control de Fraude Cybersource
 * @class
 * @example
<form_decidir 
  url_decidir="https://developers.decidir.com/api/v2" 
  public_api_key="e9cdb99fff374b5f91da4480c8dca741" 
  action="PagoDecidir" 
  target="menu" 
  direction="bottom" 
  offcanvas_class="rounded-m" 
  inhabilitar_cs="true"
> 
  <div class="menu-size" style="height:auto;" >
    <div class="content mt-0 mb-2">
      <div class="form-custom form-label form-icon">
        <i class="bi bi-check-circle font-13"></i>
        <select class="form-select rounded-xs" name="medioPago" value="{{opcionSeleccionada}}" aria-label="">
          <optgroup label="Medios de Pago">          
            {{opciones|OpcionCombo}}
          </optgroup>
        </select>
        <label for="medioPago" class="form-label-always-active color-highlight font-11">Medio de pago</label>
      </div>
      <div class="pb-3"></div>
      <div class="form-custom form-label form-icon">
        <i class="bi bi-hash font-14"></i>
        <input type="number" class="form-control rounded-xs" name="importe" placeholder="ingrese el monto"/>
        <label for="importe" class="form-label-always-active color-highlight font-11">Importe</label>
        <span class="font-10">( Moneda: $ ARG )</span>
      </div>
      <div class="pb-3"></div>
      <input 
        type="submit" 
        class="form-control rounded-xs btn btn-full gradient-highlight shadow-bg shadow-bg-s" 
        value="Depositar" 
        offcanvas_class="rounded-m"/>
    </div>
  </div>
</form_decidir>
 */

export const FormDecidir = ({ public_api_key, url_decidir, action, direction, target, children, offcanvas_class, data = "{}", to, use_token = "false", use_prev_token = "true", use_spinner = "true", inhabilitar_cs = "false" }) => {
  
  const [formInputData, setFormInputData ] = useState({})
  const navigation = useReactorNavigation({target, to: action, direction, offcanvasClass: offcanvas_class});
  const ref = useRef();
  const [ formName ] = useState(() => `form_${uuid()}`);
  
  useEffect(()=>{
    return ()=>{
      ref.current = null;
    }
  }, [])
  
  const sdkResponseHandler = (status, response) => {
    if (status != 200 && status != 201) {
      //Manejo de error: Ver Respuesta de Error
      navigation.execute({response, ...getFormData(ref.current), ...JSON.parse(data), event: "error"});
    } else {
      //Manejo de respuesta donde response = {token: "99ab0740-4ef9-4b38-bdf9-c4c963459b22"}
      navigation.execute({response, ...getFormData(ref.current), ...JSON.parse(data), event: "ok"});
    }
  }

  const handleSubmit = (event) => {
    event?.preventDefault();
    const decidir = new window.Decidir(url_decidir, inhabilitar_cs === "true");
    //Se indica la public API Key
    decidir.setPublishableKey(public_api_key);
    decidir.setTimeout(5000);//timeout de 5 segundos
    //funcion para manejar la respuesta
    decidir.createToken(ref.current, sdkResponseHandler);//formulario y callback
    if(!to) return;
    navigation.ToFrameDiv({...getFormData(ref.current), ...JSON.parse(data), event: "createToken", element: event.target.name}, action, formName, to, null, use_token === "true", use_prev_token === "true", use_spinner === "true"  )
  }
  
  const handleChange = (event) => {
    setFormInputData({...getFormData(ref.current), ...JSON.parse(data), event: "change", element: event.target.name});
    if(!to) return;
    navigation.ToFrameDiv({...getFormData(ref.current), ...JSON.parse(data), event: "change", element: event.target.name}, action, formName, to, null, use_token === "true", use_prev_token === "true", use_spinner === "true"  )
  }

  return (
    <FormContext.Provider value={{submit: handleSubmit, change: handleChange, formInputData}}>
      <form 
        ref={ref}
        onSubmit={handleSubmit}
        onChange={handleChange}
      >
        {children}
      </form>
    </FormContext.Provider>
  )

}