import { createContext, useCallback, useContext, useMemo, useRef, useState } from "react"
import { useDispatch, useSelector } from "react-redux";
import { appActions } from "../../redux";
import { booleanString, emptyObject, FormContext } from "../../_core";
import beepFX from './QrBeep.aac';
import objectPath from "object-path";
const CryptoJS = require("crypto-js");
/**
* Componente que renderiza un mati-button
* @name Reactor.Components.Input.QrOqt
* @param {string} open nombre de variable booleana que indica si esta abierto o cerrado el lector QR
* @param {string} variable nombre de variable que va a contener el resultado
* @param {string} context
* @param {string} verify
* @param {string} [list = "false"] indica si tiene que leer varios codigos
* @param {string} list_count
* @param {string} [debug = "false"]
* @param {string} [decode = "true"]
* @class
* @example
<qr open="qr" variable="usuario" context="login" decode="false" auto_submit="true" >
<qr_offcanvas options='{"style": {}}'>
<div class="d-flex flex-column h-100" style="background-color:black;color:white">
<div class="mt-2 pt-2 pb-3 mx-2 text-center">
<div class="titulo-camara">Enfoque el código del DNI</div>
</div>
<div style="max-height: calc(100vh - 210px) ; overflow: hidden; width: 100vw">
<qr_cam options='{
"width":"100%",
"height": "-",
"formats":["PDF_417", "QR_CODE"]
}'></qr_cam>
</div>
<qr_torch_on>
<div class="d-flex justify-content-center mt-2 pt-2 mx-2">
<div class="align-self-center font-14">
Encender
</div>
<div class="align-self-center ps-1 mt-n1">
<img src="images/light-on.png" width="24"/>
</div>
</div>
</qr_torch_on>
<qr_torch_off>
<div class="d-flex justify-content-center mt-2 pt-2 mx-2">
<div class="align-self-center font-14">
Apagar
</div>
<div class="align-self-center ps-1 mt-n1">
<img src="images/light-off.png" width="26"/>
</div>
</div>
</qr_torch_off>
<qr_close>
<div id="footer-bar" class="footer-bar-4 footer-bar-attached iosTabBar mx-2">
<div class="d-flex w-100">
<div class="align-self-center w-100">
<a class="btn btn-full bg-danger shadow-bg shadow-bg-s font-14 text-button" href="x">
<img src="images/previous.png" width="30">
VOLVER
</a>
</div>
</div>
</div>
</qr_close>
<div>
<qr_error>Error: código inválido.</qr_error>
</div>
</div>
</qr_offcanvas>
<qr_open>
<div class="mt-4 mx-4 text-center">
<div class="btn btn-full gradient-highlight py-1 mb-2">
<img src="images/dni.png" width="40px">
<span class="ps-2">Ingrese con su DNI</span>
</div>
</div>
</qr_open>
</qr>
*/
export const QrOqt = ({children, auto_submit = "false", open, variable, context, verify, list = "false", list_count, debug = "false", decode = "true", beep = "true", beepData}) => {
const dispatch = useDispatch();
const key = useSelector(state => state.app.key);
const variablesState = useSelector(state => state.app.variables[context]) || emptyObject;
const openState = useMemo(() => objectPath.get(variablesState, open), [context, open, variablesState]);
const audioRef = useRef();
const formContext = useContext(FormContext);
const handleClose = useCallback(() => {
dispatch(appActions.setVariable(open, false, context));
}, [open, context]);
const handleOpen = useCallback(() => {
dispatch(appActions.setVariable(open, true, context));
}, [open, context]);
const decrypt = useCallback((ciphertext) => {
var bytes = CryptoJS.AES.decrypt(ciphertext, key);
return bytes.toString(CryptoJS.enc.Utf8);
}, [key])
const handleReadDecode = useCallback((value, image) => {
if(booleanString(list)){
dispatch(appActions.setVariable(variable, value.map(item => decrypt(item)), context));
}else{
dispatch(appActions.setVariable(variable, decrypt(value), context));
}
dispatch(appActions.setVariable(`${variable}_image`, image, context));
audioRef.current?.play();
if(booleanString(auto_submit)){
setTimeout(() => {
formContext.submit();
}, 100);
}
}, [list, variable, context, auto_submit])
const handleRead = useCallback((value, image) => {
//console.log({value, image});
dispatch(appActions.setVariable(variable, value, context));
dispatch(appActions.setVariable(`${variable}_image`, image, context));
audioRef.current?.play();
if(booleanString(auto_submit)){
setTimeout(() => {
formContext.submit();
}, 100);
}
}, [variable, context, auto_submit])
const qrDF = useQrDefaultContext({
openState,
errorState: useState(false),
torchState: useState(false),
valueState: useState([]),
imagesState: useState([]),
setClose: handleClose,
setOpen: handleOpen,
onRead: booleanString(decode) ? handleReadDecode : handleRead,
verify,
list: booleanString(list),
listCount: parseInt(list_count),
currentValue: objectPath.get(variablesState, variable),
});
return (
<QrContext.Provider value={qrDF}>
{children}
{booleanString(beep) &&
<audio ref={audioRef} src={beepData || beepFX} />
}
</QrContext.Provider>
)
}
const useQrDefaultContext = ({openState = false, currentValue, errorState, torchState, valueState, imagesState, setOpen, setClose, onRead, verify, list = false, listCount = 0}) => {
const [error, setShowError] = errorState || [false, () => {}];
const [torch, setTorch] = torchState || [false, () => {}];
const [value, setValue] = valueState || [null, () => {}];
const [images, setImages] = imagesState || [null, () => {}];
const reset = () => {
setShowError(false);
setTorch(false);
setValue([]);
}
const showError = useCallback(() => {
setShowError(true);
}, []);
const hideError = useCallback(() => {
setShowError(false);
}, []);
const torchOn = () => {
setTorch(true);
}
const torchOff = () => {
setTorch(false);
}
const read = useCallback((content, image) => {
if(list){
let newValue = value || [];
if(!newValue.some(item => item === content)){
const newImages = [...images, image];
newValue.push(content);
setValue(newValue);
setImages(newImages);
onRead(newValue, newImages);
if(newValue.length === listCount){
setClose();
}
}
return;
}
if ((verify && verify===content) || !verify) {
onRead(content, image);
setClose();
hideError();
}else{
showError();
}
}, [list, onRead, verify, onRead, hideError, showError, setClose])
return {close: setClose, open: setOpen, openState, error, showError, hideError, read, torch, torchOn, torchOff, currentValue, list, reset};
}
export const QrContext = createContext();