Source: input/GeolocationOqt.js

import React, { useContext, useEffect, useState } from "react";
import useGeolocation from 'react-hook-geolocation'
import { booleanString, fakeEvent, FormContext, processOptions } from "../../_core";

/**
 * Componente que permite obtener la ubicación del usuario, 
 * si la app no tiene permisos para obtener las coordenadas del dispositivo, 
 * solicitará acceso, y al darlo obtendrá la obicación, 
 * de lo contrario mostrata el contenido del componente.
 * @name Reactor.Components.Input.GeolocationOqt
 * @param {string!} name
 *    El nombre o identificador del elemento
 * @param {("true"|"false")} [use_change="true"] 
 *    Determina si se usara el evento de cambio
 * @param {string} [delay="1000"] 
 *    El tiempo que demora en enviar el evento de cambio al form (en ms)
 * @param {GeolocationOqtOptions} [options={}] 
 *    Json string con las opciones de useGeolocation
 * @class 
 * @returns {GeolocationOqtResult} 
 * @example 
<geolocation name="ubicacion">
  debe aceptar los datos de geolocalizacion
</geolocation>
*/

export const GeolocationOqt = ({name, change_on_load = "false", use_change = "true", delay = "1000", options, children}) => {

  const {latitude, longitude, speed, error} = useGeolocation(processOptions(options));
  const formContext = useContext(FormContext);
  const [loaded, setLoaded] = useState(false);
  const [changes, setChanges] = useState(0);

  useEffect(()=>{
    setLoaded(true);
  }, []);

  useEffect(()=>{
    if(loaded && !!latitude && !!longitude){
      setChanges(changes => changes + 1);
    }
  }, [latitude, longitude, speed, loaded]);

  useEffect(()=>{
    if(changes === 1){
      if(booleanString(change_on_load) || booleanString(use_change)){
        formContext?.change(fakeEvent({name, use_change: "true", delay}));
      }
    }
    if(changes > 1){
      if(booleanString(use_change)){
        formContext?.change(fakeEvent({name, use_change, delay}));
      }
    }
  }, [changes, change_on_load, use_change, name, delay]);

  return (
    <>
      {!error && 
        <>
          <input type="hidden" name={`${name}.lat`} value={latitude} use_change="false"/>
          <input type="hidden" name={`${name}.lng`} value={longitude} use_change="false"/>
          <input type="hidden" name={`${name}.speed`} value={speed} use_change="false"/>
        </>
      }
      {error?.code && 
        <>
          <input type="hidden" name={`${name}.error.code`} value={error.code} use_change="false"/>
          <input type="hidden" name={`${name}.error.message`} value={error.message} use_change="false"/>
          {children}
        </>
      }
    </>
  )
}

/**
 * @typedef {Object} GeolocationOqtOptions
 * @property {boolean} enableHighAccuracy
 * @property {number} maximumAge
 * @property {number} timeout
*/

/**
 * @typedef {Object} GeolocationOqtResult
 * @property {number} lat Latitud
 * @property {number} lng Longitud
 * @property {number} speed Velocidad
 * @property {GeolocationOqtError?} error Se obtiene un error cuando hay un problema del dispositivo o porque el usuario no otorgo acceso a la ubicación
*/

/**
 * @typedef {Object} GeolocationOqtError
 * @property {number} code Código de error
 * @property {string} message Descripción
*/