Source: data/PermissionsOqt.js

import { useEffect, useMemo, useState } from "react";
import { emptyArray, emptyObject, useVariables } from "../.."
import { useSelector } from "react-redux";

/**
 * Componente que solicita los permisos que van a usarse en la app, y guarda el resultado de la solicitud en variables.app.permissions.
 * @name Reactor.Components.Data.Permissions
 * @param {string} list Lista de permisos que van a procesarse, separados por un espacio
 * @class
 * @example
<permissions list="geolocation audio_video notifications"></permissions>
 */
export const PermissionsOqt = ({list, children}) => {

  const variables = useVariables({variable: "permissions", context: "app", storage: false});
  const currentPermissions = useSelector(state => state.app.variables.app.permissions) || emptyObject;
  const [ localPermissions, setLocalPermissions ] = useState(() => emptyObject);

  const listObj = useMemo(()=>{
    return !!list ? list.split(" ") : emptyArray;
  }, [list]);

  useEffect(()=>{
    const arrayPromises = listObj.map(item => {
      if(!!resolvers[item]){
        return resolvers[item](item);
      }else{
        return emptyPromise(item);
      }
    });
    arrayPromises.reduce((prev, curr) => {
      curr().then(r => {
        if(r.result !== null){
          setLocalPermissions(localPermissions => ({...localPermissions, [r.permission]: r.result}))
        }
      });
    }, 0)
  }, [listObj]);

  useEffect(()=>{
    variables.setData({...currentPermissions, ...localPermissions});
  }, [localPermissions]);

  return <>{children}</>
}

const permissionsResult = {
  UNSUPPORTED: "error",
  DENIED: "denied",
  SUCCESS: "accepted",
}

const emptyPromise = (permission) => () => {
  return new Promise((resolve)=>{resolve({permission, result: "not implemented"})});
}

const resolvers = {
  geolocation: (permission) => () => new Promise((resolve, reject)=>{
    const successCallback = (position) => {
      resolve({permission, result: permissionsResult.SUCCESS});
    }
    const errorCallback = (error) => {
      resolve({permission, result: permissionsResult.DENIED});
    }
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
    } else {
      resolve({permission, result: permissionsResult.UNSUPPORTED});
    }
  }),
  video: (permission) => () => new Promise((resolve, reject)=>{
    const constraints = { video: true };
    if (!navigator.mediaDevices) {
      resolve({permission, result: permissionsResult.UNSUPPORTED});
    }
    navigator.mediaDevices.getUserMedia(constraints)
      .then((stream) => {
        const tracks = stream.getTracks(); // Obtiene los tracks del stream
        tracks.forEach((track) => {
          track.stop(); // Detiene cada track del stream
        });
        stream = null; // Borra la variable 'stream'
        resolve({permission, result: permissionsResult.UNSUPPORTED});
      })
      .catch((error) => {
        resolve({permission, result: permissionsResult.DENIED});
      });    
  }),
  audio: (permission) => () => new Promise((resolve, reject)=>{
    const constraints = { audio: true };
    if (!navigator.mediaDevices) {
      resolve({permission, result: permissionsResult.UNSUPPORTED});
    }
    navigator.mediaDevices.getUserMedia(constraints)
      .then((stream) => {
        const tracks = stream.getTracks(); // Obtiene los tracks del stream
        tracks.forEach((track) => {
          track.stop(); // Detiene cada track del stream
        });
        stream = null; // Borra la variable 'stream'
        resolve({permission, result: permissionsResult.SUCCESS});
      })
      .catch((error) => {
        resolve({permission, result: permissionsResult.DENIED});
      });        
  }),
  audio_video: (permission) => () => new Promise((resolve, reject)=>{
    const constraints = { audio: true, video: true };
    if (!navigator.mediaDevices) {
      resolve({permission, result: permissionsResult.UNSUPPORTED});
    }
    navigator.mediaDevices.getUserMedia(constraints)
      .then((stream) => {
        const tracks = stream.getTracks(); // Obtiene los tracks del stream
        tracks.forEach((track) => {
          track.stop(); // Detiene cada track del stream
        });
        stream = null; // Borra la variable 'stream'
        resolve({permission, result: permissionsResult.SUCCESS});
      })
      .catch((error) => {
        resolve({permission, result: permissionsResult.DENIED});
      });        
  }),
  notifications: (permission) => () => new Promise((resolve, reject)=>{
    if (Notification.permission !== "granted") {
      Notification.requestPermission().then((result) => {
        if (result === "granted") {
          resolve({permission, result: permissionsResult.SUCCESS});
        } else {
          resolve({permission, result: permissionsResult.DENIED});
        }
      });
    } else {
      resolve({permission, result: permissionsResult.SUCCESS});
    }
  }),
}