diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c6c8b36 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.github/README.md b/.github/README.md index 5038a9b..963bfe9 100644 --- a/.github/README.md +++ b/.github/README.md @@ -84,6 +84,7 @@ import Share from 'fe-pilot/Share'; > > ### > 01. :white_check_mark: AutoFillOtp             [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/AutoFillOtp/README.md) +> 00. :white_check_mark: ColorPicker            [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/ColorPicker/README.md) > 00. :white_check_mark: CopyToClipboard  [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/CopyToClipboard/README.md) > 00. :white_check_mark: FaceDetector        [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/FaceDetector/README.md) > 00. :white_check_mark: LiveLocation          [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/LiveLocationTracking/README.md) @@ -193,14 +194,23 @@ Thanks goes to these wonderful people -

- - Fossa Bot -
- Fossa Bot -
-

- +

+ + Fossa Bot +
+ Fossa Bot +
+

+ + +

+ + Vineet Gupta +
+ Vineet Gupta +
+

+ diff --git a/.gitignore b/.gitignore index d690bd3..ee63b42 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ node_modules/ __build/ -**/index.js \ No newline at end of file +**/index.js + +!__app/component/**/index.js + diff --git a/.vscode/settings.json b/.vscode/settings.json index 88f12eb..35c7d5e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,7 @@ "**/index.js": true, "**/__build-es/**": true }, - "editor.tabSize": 2, + "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, diff --git a/README.md b/README.md index f9e9aa9..347d803 100644 --- a/README.md +++ b/README.md @@ -83,17 +83,18 @@ import Share from 'fe-pilot/Share'; See the list of components ### -:white_check_mark: AutoFillOtp               [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/AutoFillOtp/README.md) -:white_check_mark: CopyToClipboard  [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/CopyToClipboard/README.md) -:white_check_mark: FaceDetector        [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/FaceDetector/README.md) -:white_check_mark: LiveLocation            [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/LiveLocationTracking/README.md) -:white_check_mark: LocateMe                  [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/LocateMe/README.md) -:white_check_mark: PhoneBook              [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/PhoneBook/README.md) -:white_check_mark: Scanner                     [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/Scanner/README.md) -:white_check_mark: Share                          [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/Share/README.md) -:white_check_mark: TextToSpeech         [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/TextToSpeech/README.md) -:white_check_mark: VoiceRecognition  [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/VoiceRecognition/README.md) -:white_check_mark: Vibrate                      [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/Vibrate/README.md) +1. :white_check_mark: AutoFillOtp               [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/AutoFillOtp/README.md) +2. :white_check_mark: ColorPicker        [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/ColorPicker/README.md) +3. :white_check_mark: CopyToClipboard  [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/CopyToClipboard/README.md) +4. :white_check_mark: FaceDetector        [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/FaceDetector/README.md) +5. :white_check_mark: LiveLocation            [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/LiveLocationTracking/README.md) +6. :white_check_mark: LocateMe                  [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/LocateMe/README.md) +7. :white_check_mark: PhoneBook              [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/PhoneBook/README.md) +8. :white_check_mark: Scanner                     [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/Scanner/README.md) +9. :white_check_mark: Share                          [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/Share/README.md) +10. :white_check_mark: TextToSpeech         [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/TextToSpeech/README.md) +11. :white_check_mark: VoiceRecognition  [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/VoiceRecognition/README.md) +12. :white_check_mark: Vibrate                      [Implementation & Structure](https://github.com/opensrc0/fe-pilot/blob/main/__app/component/Vibrate/README.md) > ## Online Editor Templates @@ -191,15 +192,24 @@ Thanks goes to these wonderful people -

- - Fossa Bot -
- Fossa Bot -
-

- - +

+ + Fossa Bot +
+ Fossa Bot +
+

+ + +

+ + Vineet Gupta +
+ Vineet Gupta +
+

+ + diff --git a/__app/component/AutoFillOtp/README.md b/__app/component/AutoFillOtp/README.md index e69de29..aa51fa8 100644 --- a/__app/component/AutoFillOtp/README.md +++ b/__app/component/AutoFillOtp/README.md @@ -0,0 +1,86 @@ +## 1. Happy Flow + +```js +import AutoFillOtp from "fe-pilot/AutoFillOtp"; +``` + +#### a) Call AutoFillOtp function + +```js +AutoFillOtp(); +``` + +> [!Important] +> To work AutoFillOtp successfully, your otp message template should follow the below format. +>
+> ```Your OTP is 123456``` +>
+> ```@your-domain.com #123456``` + + +## 2. Success: successCb callBack function definition + +```js +const successCb = ({ msgType, msg, data, status }) => { + console.log(msgType); // SUCCESSFUL + console.log(msg); // Success OTP Autofill + console.log(data); // logs - otp + console.log(status); // SUCCESS +}; + +AutoFillOtp({ + successCb, + successMsg: "Success OTP Autofill", +}); +``` + +> [!Note] +> **successCb** function will get an object contains the property `msgType`, `msg`, `data`, `status` + + +## 3. Failure: failureCb callBack function definition + +```js +const failureCb = ({ msgType, msg, status }) => { + console.log(msgType); + console.log(msg); + console.log(status); + // UN_SUPPORTED_FEATURE ERROR + // Your device does not support AutoFillOtp + // FAILURE + + // ----------OR---------- + + // ERROR + // Unable to auto fill otp + // FAILURE +}; + +AutoFillOtp({ + failureCb, + failureMsg: { + unSupported: "Your device does not support AutoFillOtp", + error: "Unable to auto fill otp", + }, +}); +``` + +> [!Note] +> **failureCb** function will get an object contains the property `msgType`, `msg`, `status` + +> [!Important] +> Failure can happend due to multiple reasons, due to that reason `failureMsg` is an object having different kind of error property according to the error can occur in component + +## 4. Combine with all props + +```js +AutoFillOtp({ + successCb, + successMsg: "Success OTP Autofill", + failureCb, + failureMsg: { + unSupported: "Your device does not support AutoFillOtp", + error: "Unable to auto fill otp", + }, +}); +``` diff --git a/__app/component/AutoFillOtp/index.js b/__app/component/AutoFillOtp/index.js new file mode 100644 index 0000000..3020f35 --- /dev/null +++ b/__app/component/AutoFillOtp/index.js @@ -0,0 +1,5 @@ +import AutoFillOtp from './AutoFillOtp'; + +export { AutoFillOtp }; + +export default AutoFillOtp; diff --git a/__app/component/ColorPicker/ColorPicker.js b/__app/component/ColorPicker/ColorPicker.js index a183d77..f3f76d3 100644 --- a/__app/component/ColorPicker/ColorPicker.js +++ b/__app/component/ColorPicker/ColorPicker.js @@ -51,7 +51,7 @@ ColorPicker.propTypes = { ColorPicker.defaultProps = { successCb: () => {}, failureCb: () => {}, - successMsg: 'Color copied successfully!!', + successMsg: 'Color picked successfully!!', failureMsg: { ...failureMsgDefault }, }; diff --git a/__app/component/ColorPicker/README.md b/__app/component/ColorPicker/README.md index b848b21..c76e32d 100644 --- a/__app/component/ColorPicker/README.md +++ b/__app/component/ColorPicker/README.md @@ -6,7 +6,7 @@ ```js Pass clickable(button, anchor etc) element here to bind onClick event @@ -17,13 +17,13 @@ ```js const successCb = ({ msgType, msg, data }) => { console.log(msgType); // Success - console.log(msg); // Color copied successfully!! + console.log(msg); // Color picked successfully!! console.log(data); // #FFFFFF (Color Code) } @@ -80,7 +80,7 @@ Failure can happend due to multiple reasons, due to that reason ```failureMsg``` ```js `} > - Pass Copy Icon here + Pass clickable(button, anchor, icon etc) element here to bind onClick event ``` @@ -50,7 +50,9 @@ const successCb = ({ msgType, msg, data }) => { successCb={successCb} successMsg="Copied Successfully" elementToBeCopy={`Fe-pilot library offers component like scanner, voice search, autofill otp, phonebook, share`} -/> +> + Click here to copy (Element, String, etc) + ``` > [!Note] > **successCb** will get an object contains the property ```msgType```, ```msg```, ```data``` diff --git a/__app/component/CopyToClipboard/index.js b/__app/component/CopyToClipboard/index.js new file mode 100644 index 0000000..00802d5 --- /dev/null +++ b/__app/component/CopyToClipboard/index.js @@ -0,0 +1,5 @@ +import CopyToClipboard from './CopyToClipboard'; + +export { CopyToClipboard }; + +export default CopyToClipboard; diff --git a/__app/component/FaceDetector/FaceDetector.js b/__app/component/FaceDetector/FaceDetector.js index 4521552..3962517 100644 --- a/__app/component/FaceDetector/FaceDetector.js +++ b/__app/component/FaceDetector/FaceDetector.js @@ -1,18 +1,224 @@ -import FaceDetectorInit from './FaceDetectorInit'; -import FaceDetectorFlash from './FaceDetectorFlash'; -import FaceDetectorClose from './FaceDetectorClose'; -import FaceDetectorFacing from './FaceDetectorFacing'; - -export { - FaceDetectorInit, - FaceDetectorFlash, - FaceDetectorClose, - FaceDetectorFacing, +/* eslint-disable no-inner-declarations */ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { handleError, handleLoading } from '../services/handlerService'; +import Wrapper from '../Wrapper/Wrapper'; + +let mediaStream = null; +let videoUnmount = null; +let unmoutRenderLoop = null; +const failureMsgDefault = { + unSupported: 'Face Detector is not supporting in your device', + streamingFailed: 'Camera streaming failed', + barCodeDetectionFailed: 'Bar code detection failed', + flashUnsupported: 'Flash is not supporting in your device', +}; + +function FaceDetector({ + // successCb, + failureCb, + loadingCb, + // successMsg, + failureMsg: failureMsgProps, + cameraType, + zIndex, + children, +}) { + const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; + let list = null; + let video = null; + let facingMode; + + const [flash, setFlash] = useState(false); + const [isBrowser, setIsBrowser] = useState(false); + const [faces, setFaces] = useState([]); + + const stopStreaming = () => { + if (mediaStream) { + mediaStream.getTracks().forEach((track) => { + track.stop(); + }); + } + }; + + const allClear = () => { + cancelAnimationFrame(videoUnmount); + stopStreaming(); + clearTimeout(unmoutRenderLoop); + }; + + const detectCodes = async () => { + const WindowFaceDetector = globalThis.FaceDetector; + const faceDetector = new WindowFaceDetector(); + + // eslint-disable-next-line consistent-return + async function render() { + try { + const getFaces = await faceDetector.detect(video); + + if (getFaces[0]) { + setFaces(getFaces); + // cancelAnimationFrame(videoUnmount); + // stopStreaming(); + // clearTimeout(unmoutRenderLoop); + } + } catch (error) { + return handleError({ msgType: 'BAR_CODE_DETECTION_FAILED', msg: failureMsg.barCodeDetectionFailed || JSON.stringify(error), failureCb }); + } + } + + unmoutRenderLoop = setTimeout(() => { + (function renderLoop() { + videoUnmount = requestAnimationFrame(() => { + setTimeout(renderLoop, 1500); + }); + render(); + }()); + }, 100); + }; + + const createVideo = async (id) => { + document.getElementById('streaming-video')?.remove(); + + video = document.createElement('video'); + + video.id = 'streaming-video'; + video.srcObject = mediaStream; + video.autoplay = true; + video.play(); + // video.style.width = '100vh'; + // video.style.height = '100%'; + video.style.position = 'absolute'; + // video.style.overflow = 'hidden'; + // video.style.display = 'block'; + video.style.zIndex = zIndex; + video.style.top = '0'; + video.style.left = '0'; + video.style.objectFit = 'fill'; + list = document.getElementById(id); + list.before(video); + }; + + const startStreaming = async () => { + try { + mediaStream = await navigator.mediaDevices.getUserMedia({ + video: { + // deviceId: camera.deviceId, + facingMode, + zoom: true, + resizeMode: true, + focusDistance: true, + focusMode: true, + }, + }); + } catch (error) { + return handleError({ msgType: 'STREAMING_FAILED', msg: failureMsg.streamingFailed || JSON.stringify(error), failureCb }); + } + return mediaStream; + }; + + const startVideo = async (id = 'camera') => { + mediaStream = await startStreaming(); + createVideo(id); + detectCodes(); + }; + + const toggleFlash = async () => { + const track = mediaStream.getVideoTracks()[0]; + try { + await track.applyConstraints({ + advanced: [{ torch: !flash }], + }); + setFlash((s) => !s); + } catch (error) { + return handleError({ msgType: 'FLASH_UPSUPPORTED', msg: failureMsg.flashUnsupported, failureCb }); + } + return true; + }; + + const toggleCamera = () => { + facingMode = facingMode === 'user' ? 'environment' : 'user'; + + stopStreaming(); + cancelAnimationFrame(videoUnmount); + clearTimeout(unmoutRenderLoop); + startVideo(); + }; + + const handleBrowserSupport = () => { + if (FaceDetector.isBrowserSupport()) { + facingMode = cameraType === 'back' ? 'environment' : 'user'; + handleLoading({ loadingCb }); + + startVideo(); + } else { + return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); + } + + return true; + }; + + useEffect(() => { + setIsBrowser(true); + handleBrowserSupport(); + + return () => { + allClear(); + }; + }, []); + + return isBrowser && FaceDetector.isBrowserSupport() && ( +
+
+ { + React.Children.map(children, (child) => React.cloneElement(child, { + zIndex, + allClear, + toggleCamera, + toggleFlash, + })) + } + { + faces.map((face) => ( +
+ )) + } +
+ ); +} + +FaceDetector.isBrowserSupport = () => navigator?.mediaDevices && globalThis.FaceDetector; + +FaceDetector.propTypes = { + // successCb: PropTypes.func, + failureCb: PropTypes.func, + loadingCb: PropTypes.func, + // successMsg: PropTypes.string, + failureMsg: PropTypes.object, + zIndex: PropTypes.number, + cameraType: PropTypes.oneOf(['back', 'front']), }; -export default { - Init: FaceDetectorInit, - Flash: FaceDetectorFlash, - Close: FaceDetectorClose, - Facing: FaceDetectorFacing, +FaceDetector.defaultProps = { + // successCb: () => {}, + failureCb: () => {}, + loadingCb: () => {}, + // successMsg: '', + failureMsg: { ...failureMsgDefault }, + zIndex: 9, + cameraType: 'back', }; + +export default Wrapper(FaceDetector); diff --git a/__app/component/FaceDetector/FaceDetectorInit.js b/__app/component/FaceDetector/FaceDetectorInit.js deleted file mode 100644 index 894da6a..0000000 --- a/__app/component/FaceDetector/FaceDetectorInit.js +++ /dev/null @@ -1,224 +0,0 @@ -/* eslint-disable no-inner-declarations */ -import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { handleError, handleLoading } from '../services/handlerService'; -import Wrapper from '../Wrapper/Wrapper'; - -let mediaStream = null; -let videoUnmount = null; -let unmoutRenderLoop = null; -const failureMsgDefault = { - unSupported: 'Face Detector is not supporting in your device', - streamingFailed: 'Camera streaming failed', - barCodeDetectionFailed: 'Bar code detection failed', - flashUnsupported: 'Flash is not supporting in your device', -}; - -function FaceDetectorInit({ - // successCb, - failureCb, - loadingCb, - // successMsg, - failureMsg: failureMsgProps, - cameraType, - zIndex, - children, -}) { - const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; - let list = null; - let video = null; - let facingMode; - - const [flash, setFlash] = useState(false); - const [isBrowser, setIsBrowser] = useState(false); - const [faces, setFaces] = useState([]); - - const stopStreaming = () => { - if (mediaStream) { - mediaStream.getTracks().forEach((track) => { - track.stop(); - }); - } - }; - - const allClear = () => { - cancelAnimationFrame(videoUnmount); - stopStreaming(); - clearTimeout(unmoutRenderLoop); - }; - - const detectCodes = async () => { - const WindowFaceDetector = globalThis.FaceDetector; - const faceDetector = new WindowFaceDetector(); - - // eslint-disable-next-line consistent-return - async function render() { - try { - const getFaces = await faceDetector.detect(video); - - if (getFaces[0]) { - setFaces(getFaces); - // cancelAnimationFrame(videoUnmount); - // stopStreaming(); - // clearTimeout(unmoutRenderLoop); - } - } catch (error) { - return handleError({ msgType: 'BAR_CODE_DETECTION_FAILED', msg: failureMsg.barCodeDetectionFailed || JSON.stringify(error), failureCb }); - } - } - - unmoutRenderLoop = setTimeout(() => { - (function renderLoop() { - videoUnmount = requestAnimationFrame(() => { - setTimeout(renderLoop, 1500); - }); - render(); - }()); - }, 100); - }; - - const createVideo = async (id) => { - document.getElementById('streaming-video')?.remove(); - - video = document.createElement('video'); - - video.id = 'streaming-video'; - video.srcObject = mediaStream; - video.autoplay = true; - video.play(); - // video.style.width = '100vh'; - // video.style.height = '100%'; - video.style.position = 'absolute'; - // video.style.overflow = 'hidden'; - // video.style.display = 'block'; - video.style.zIndex = zIndex; - video.style.top = '0'; - video.style.left = '0'; - video.style.objectFit = 'fill'; - list = document.getElementById(id); - list.before(video); - }; - - const startStreaming = async () => { - try { - mediaStream = await navigator.mediaDevices.getUserMedia({ - video: { - // deviceId: camera.deviceId, - facingMode, - zoom: true, - resizeMode: true, - focusDistance: true, - focusMode: true, - }, - }); - } catch (error) { - return handleError({ msgType: 'STREAMING_FAILED', msg: failureMsg.streamingFailed || JSON.stringify(error), failureCb }); - } - return mediaStream; - }; - - const startVideo = async (id = 'camera') => { - mediaStream = await startStreaming(); - createVideo(id); - detectCodes(); - }; - - const toggleFlash = async () => { - const track = mediaStream.getVideoTracks()[0]; - try { - await track.applyConstraints({ - advanced: [{ torch: !flash }], - }); - setFlash((s) => !s); - } catch (error) { - return handleError({ msgType: 'FLASH_UPSUPPORTED', msg: failureMsg.flashUnsupported, failureCb }); - } - return true; - }; - - const toggleCamera = () => { - facingMode = facingMode === 'user' ? 'environment' : 'user'; - - stopStreaming(); - cancelAnimationFrame(videoUnmount); - clearTimeout(unmoutRenderLoop); - startVideo(); - }; - - const handleBrowserSupport = () => { - if (FaceDetectorInit.isBrowserSupport()) { - facingMode = cameraType === 'back' ? 'environment' : 'user'; - handleLoading({ loadingCb }); - - startVideo(); - } else { - return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); - } - - return true; - }; - - useEffect(() => { - setIsBrowser(true); - handleBrowserSupport(); - - return () => { - allClear(); - }; - }, []); - - return isBrowser && FaceDetectorInit.isBrowserSupport() && ( -
-
- { - React.Children.map(children, (child) => React.cloneElement(child, { - zIndex, - allClear, - toggleCamera, - toggleFlash, - })) - } - { - faces.map((face) => ( -
- )) - } -
- ); -} - -FaceDetectorInit.isBrowserSupport = () => navigator?.mediaDevices && globalThis.FaceDetector; - -FaceDetectorInit.propTypes = { - // successCb: PropTypes.func, - failureCb: PropTypes.func, - loadingCb: PropTypes.func, - // successMsg: PropTypes.string, - failureMsg: PropTypes.object, - zIndex: PropTypes.number, - cameraType: PropTypes.oneOf(['back', 'front']), -}; - -FaceDetectorInit.defaultProps = { - // successCb: () => {}, - failureCb: () => {}, - loadingCb: () => {}, - // successMsg: '', - failureMsg: { ...failureMsgDefault }, - zIndex: 9, - cameraType: 'back', -}; - -export default Wrapper(FaceDetectorInit); diff --git a/__app/component/FaceDetector/index.js b/__app/component/FaceDetector/index.js new file mode 100644 index 0000000..42a4287 --- /dev/null +++ b/__app/component/FaceDetector/index.js @@ -0,0 +1,18 @@ +import FaceDetector from './FaceDetector'; +import FaceDetectorFlash from './FaceDetectorFlash'; +import FaceDetectorClose from './FaceDetectorClose'; +import FaceDetectorFacing from './FaceDetectorFacing'; + +export { + FaceDetector, + FaceDetectorFlash, + FaceDetectorClose, + FaceDetectorFacing, +}; + +export default { + Init: FaceDetector, + Flash: FaceDetectorFlash, + Close: FaceDetectorClose, + Facing: FaceDetectorFacing, +}; diff --git a/__app/component/LiveLocationTracking/index.js b/__app/component/LiveLocationTracking/index.js new file mode 100644 index 0000000..b230cdb --- /dev/null +++ b/__app/component/LiveLocationTracking/index.js @@ -0,0 +1,5 @@ +import LiveLocationTracking from './LiveLocationTracking'; + +export { LiveLocationTracking }; + +export default LiveLocationTracking; diff --git a/__app/component/LocateMe/index.js b/__app/component/LocateMe/index.js new file mode 100644 index 0000000..68aa381 --- /dev/null +++ b/__app/component/LocateMe/index.js @@ -0,0 +1,5 @@ +import LocateMe from './LocateMe'; + +export { LocateMe }; + +export default LocateMe; diff --git a/__app/component/PhoneBook/index.js b/__app/component/PhoneBook/index.js new file mode 100644 index 0000000..c401a42 --- /dev/null +++ b/__app/component/PhoneBook/index.js @@ -0,0 +1,5 @@ +import PhoneBook from './PhoneBook'; + +export { PhoneBook }; + +export default PhoneBook; diff --git a/__app/component/Scanner/Scanner.js b/__app/component/Scanner/Scanner.js index 11878f2..dcdd2c9 100644 --- a/__app/component/Scanner/Scanner.js +++ b/__app/component/Scanner/Scanner.js @@ -1,28 +1,216 @@ -import ScannerInit from './ScannerInit'; -import ScannerScanBox from './ScannerScanBox'; -import ScannerFlash from './ScannerFlash'; -import ScannerClose from './ScannerClose'; - -import ScannerFacing from './ScannerFacing'; -import ScannerGallery from './ScannerGallery'; -import ScannerCamera from './ScannerCamera'; - -export { - ScannerInit, - ScannerFlash, - ScannerClose, - ScannerScanBox, - ScannerFacing, - ScannerGallery, - ScannerCamera, +/* eslint-disable no-inner-declarations */ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { handleSuccess, handleError, handleLoading } from '../services/handlerService'; +import Wrapper from '../Wrapper/Wrapper'; + +let mediaStream = null; +let videoUnmount = null; +let unmoutRenderLoop = null; + +const failureMsgDefault = { + unSupported: 'QR-Code/Bar-Code/UPI Scanner is not supporting in your device', + streamingFailed: 'Camera streaming failed', + barCodeDetectionFailed: 'Bar code detection failed', + invalidImage: 'Invalid Images', + flashUnsupported: 'Flash is not supporting in your device', + unableToScan: 'Unable to scan', }; -export default { - Init: ScannerInit, - Flash: ScannerFlash, - Close: ScannerClose, - ScanBox: ScannerScanBox, - Facing: ScannerFacing, - Gallery: ScannerGallery, - Camera: ScannerCamera, +function Scanner({ + successCb, + failureCb, + loadingCb, + successMsg, + failureMsg: failureMsgProps, + cameraType, + zIndex, + children, +}) { + let list = null; + let video = null; + let facingMode; + const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; + + const [flash, setFlash] = useState(false); + const [isBrowser, setIsBrowser] = useState(false); + + const stopStreaming = () => { + if (mediaStream) { + mediaStream.getTracks().forEach((track) => { + track.stop(); + }); + } + }; + + const detectCodes = async () => { + const WindowBarcodeDetector = globalThis.BarcodeDetector; + const barcodeDetector = new WindowBarcodeDetector(); + const itemsFound = []; + + // eslint-disable-next-line consistent-return + async function render() { + try { + const barcodes = await barcodeDetector.detect(video); + barcodes.forEach((barcode) => { + if (!itemsFound.includes(barcode.rawValue)) { + itemsFound.push(barcode.rawValue); + handleSuccess({ + msgType: 'SUCCESSFUL', + msg: successMsg, + successCb, + data: { barCodeValue: barcode.rawValue, barCodeType: barcode.format }, + }); + } + }); + } catch (error) { + return handleError({ msgType: 'BAR_CODE_DETECTION_FAILED', msg: failureMsg.barCodeDetectionFailed || JSON.stringify(error), failureCb }); + } + } + + unmoutRenderLoop = setTimeout(() => { + (function renderLoop() { + videoUnmount = requestAnimationFrame(renderLoop); + render(); + }()); + }, 1000); + }; + + const createVideo = async (id) => { + document.getElementById('streaming-video')?.remove(); + + video = document.createElement('video'); + + video.id = 'streaming-video'; + video.srcObject = mediaStream; + video.autoplay = true; + video.play(); + video.style.width = '100%'; + video.style.height = '100%'; + video.style.position = 'absolute'; + video.style.overflow = 'hidden'; + video.style.display = 'block'; + video.style.zIndex = zIndex; + video.style.top = '0'; + video.style.left = '0'; + video.style.objectFit = 'fill'; + list = document.getElementById(id); + list.before(video); + }; + + const startStreaming = async () => { + try { + mediaStream = await navigator.mediaDevices.getUserMedia({ + video: { + // deviceId: camera.deviceId, + facingMode, + zoom: true, + resizeMode: true, + focusDistance: true, + focusMode: true, + }, + }); + } catch (error) { + return handleError({ msgType: 'STREAMING_FAILED', msg: failureMsg.streamingFailed || JSON.stringify(error), failureCb }); + } + return mediaStream; + }; + + const startVideo = async (id = 'camera') => { + mediaStream = await startStreaming(); + createVideo(id); + detectCodes(); + }; + + const allClear = () => { + cancelAnimationFrame(videoUnmount); + stopStreaming(); + clearTimeout(unmoutRenderLoop); + }; + + const toggleFlash = async () => { + const track = mediaStream.getVideoTracks()[0]; + try { + await track.applyConstraints({ + advanced: [{ torch: !flash }], + }); + setFlash((s) => !s); + } catch (error) { + return handleError({ msgType: 'FLASH_UPSUPPORTED', msg: failureMsg.flashUnsupported, failureCb }); + } + return true; + }; + + const toggleCamera = () => { + facingMode = facingMode === 'user' ? 'environment' : 'user'; + + stopStreaming(); + cancelAnimationFrame(videoUnmount); + clearTimeout(unmoutRenderLoop); + startVideo(); + }; + + const handleBrowserSupport = () => { + if (Scanner.isBrowserSupport()) { + facingMode = cameraType === 'back' ? 'environment' : 'user'; + handleLoading({ loadingCb }); + + startVideo(); + } else { + return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); + } + + return true; + }; + + useEffect(() => { + setIsBrowser(true); + handleBrowserSupport(); + + return () => { + allClear(); + }; + }, []); + + return isBrowser && Scanner.isBrowserSupport() && ( +
+
+ { + React.Children.map(children, (child) => React.cloneElement(child, { + zIndex, + allClear, + toggleCamera, + toggleFlash, + successCb, + successMsg, + failureCb, + failureMsg, + })) + } +
+ ); +} + +Scanner.isBrowserSupport = () => navigator?.mediaDevices && globalThis.BarcodeDetector; + +Scanner.propTypes = { + successCb: PropTypes.func, + failureCb: PropTypes.func, + loadingCb: PropTypes.func, + successMsg: PropTypes.string, + failureMsg: PropTypes.object, + zIndex: PropTypes.number, + cameraType: PropTypes.oneOf(['back', 'front']), }; + +Scanner.defaultProps = { + successCb: () => {}, + failureCb: () => {}, + loadingCb: () => {}, + successMsg: '', + failureMsg: { ...failureMsgDefault }, + zIndex: 9, + cameraType: 'back', +}; + +export default Wrapper(Scanner); diff --git a/__app/component/Scanner/ScannerInit.js b/__app/component/Scanner/ScannerInit.js deleted file mode 100644 index 56f4ea9..0000000 --- a/__app/component/Scanner/ScannerInit.js +++ /dev/null @@ -1,216 +0,0 @@ -/* eslint-disable no-inner-declarations */ -import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { handleSuccess, handleError, handleLoading } from '../services/handlerService'; -import Wrapper from '../Wrapper/Wrapper'; - -let mediaStream = null; -let videoUnmount = null; -let unmoutRenderLoop = null; - -const failureMsgDefault = { - unSupported: 'QR-Code/Bar-Code/UPI Scanner is not supporting in your device', - streamingFailed: 'Camera streaming failed', - barCodeDetectionFailed: 'Bar code detection failed', - invalidImage: 'Invalid Images', - flashUnsupported: 'Flash is not supporting in your device', - unableToScan: 'Unable to scan', -}; - -function ScannerInit({ - successCb, - failureCb, - loadingCb, - successMsg, - failureMsg: failureMsgProps, - cameraType, - zIndex, - children, -}) { - let list = null; - let video = null; - let facingMode; - const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; - - const [flash, setFlash] = useState(false); - const [isBrowser, setIsBrowser] = useState(false); - - const stopStreaming = () => { - if (mediaStream) { - mediaStream.getTracks().forEach((track) => { - track.stop(); - }); - } - }; - - const detectCodes = async () => { - const WindowBarcodeDetector = globalThis.BarcodeDetector; - const barcodeDetector = new WindowBarcodeDetector(); - const itemsFound = []; - - // eslint-disable-next-line consistent-return - async function render() { - try { - const barcodes = await barcodeDetector.detect(video); - barcodes.forEach((barcode) => { - if (!itemsFound.includes(barcode.rawValue)) { - itemsFound.push(barcode.rawValue); - handleSuccess({ - msgType: 'SUCCESSFUL', - msg: successMsg, - successCb, - data: { barCodeValue: barcode.rawValue, barCodeType: barcode.format }, - }); - } - }); - } catch (error) { - return handleError({ msgType: 'BAR_CODE_DETECTION_FAILED', msg: failureMsg.barCodeDetectionFailed || JSON.stringify(error), failureCb }); - } - } - - unmoutRenderLoop = setTimeout(() => { - (function renderLoop() { - videoUnmount = requestAnimationFrame(renderLoop); - render(); - }()); - }, 1000); - }; - - const createVideo = async (id) => { - document.getElementById('streaming-video')?.remove(); - - video = document.createElement('video'); - - video.id = 'streaming-video'; - video.srcObject = mediaStream; - video.autoplay = true; - video.play(); - video.style.width = '100%'; - video.style.height = '100%'; - video.style.position = 'absolute'; - video.style.overflow = 'hidden'; - video.style.display = 'block'; - video.style.zIndex = zIndex; - video.style.top = '0'; - video.style.left = '0'; - video.style.objectFit = 'fill'; - list = document.getElementById(id); - list.before(video); - }; - - const startStreaming = async () => { - try { - mediaStream = await navigator.mediaDevices.getUserMedia({ - video: { - // deviceId: camera.deviceId, - facingMode, - zoom: true, - resizeMode: true, - focusDistance: true, - focusMode: true, - }, - }); - } catch (error) { - return handleError({ msgType: 'STREAMING_FAILED', msg: failureMsg.streamingFailed || JSON.stringify(error), failureCb }); - } - return mediaStream; - }; - - const startVideo = async (id = 'camera') => { - mediaStream = await startStreaming(); - createVideo(id); - detectCodes(); - }; - - const allClear = () => { - cancelAnimationFrame(videoUnmount); - stopStreaming(); - clearTimeout(unmoutRenderLoop); - }; - - const toggleFlash = async () => { - const track = mediaStream.getVideoTracks()[0]; - try { - await track.applyConstraints({ - advanced: [{ torch: !flash }], - }); - setFlash((s) => !s); - } catch (error) { - return handleError({ msgType: 'FLASH_UPSUPPORTED', msg: failureMsg.flashUnsupported, failureCb }); - } - return true; - }; - - const toggleCamera = () => { - facingMode = facingMode === 'user' ? 'environment' : 'user'; - - stopStreaming(); - cancelAnimationFrame(videoUnmount); - clearTimeout(unmoutRenderLoop); - startVideo(); - }; - - const handleBrowserSupport = () => { - if (ScannerInit.isBrowserSupport()) { - facingMode = cameraType === 'back' ? 'environment' : 'user'; - handleLoading({ loadingCb }); - - startVideo(); - } else { - return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); - } - - return true; - }; - - useEffect(() => { - setIsBrowser(true); - handleBrowserSupport(); - - return () => { - allClear(); - }; - }, []); - - return isBrowser && ScannerInit.isBrowserSupport() && ( -
-
- { - React.Children.map(children, (child) => React.cloneElement(child, { - zIndex, - allClear, - toggleCamera, - toggleFlash, - successCb, - successMsg, - failureCb, - failureMsg, - })) - } -
- ); -} - -ScannerInit.isBrowserSupport = () => navigator?.mediaDevices && globalThis.BarcodeDetector; - -ScannerInit.propTypes = { - successCb: PropTypes.func, - failureCb: PropTypes.func, - loadingCb: PropTypes.func, - successMsg: PropTypes.string, - failureMsg: PropTypes.object, - zIndex: PropTypes.number, - cameraType: PropTypes.oneOf(['back', 'front']), -}; - -ScannerInit.defaultProps = { - successCb: () => {}, - failureCb: () => {}, - loadingCb: () => {}, - successMsg: '', - failureMsg: { ...failureMsgDefault }, - zIndex: 9, - cameraType: 'back', -}; - -export default Wrapper(ScannerInit); diff --git a/__app/component/Scanner/index.js b/__app/component/Scanner/index.js new file mode 100644 index 0000000..94f4375 --- /dev/null +++ b/__app/component/Scanner/index.js @@ -0,0 +1,28 @@ +import Scanner from './Scanner'; +import ScannerScanBox from './ScannerScanBox'; +import ScannerFlash from './ScannerFlash'; +import ScannerClose from './ScannerClose'; +import ScannerFacing from './ScannerFacing'; +import ScannerGallery from './ScannerGallery'; +import ScannerCamera from './ScannerCamera'; + +// Helps in tree shaking +export { + Scanner, + ScannerFlash, + ScannerClose, + ScannerScanBox, + ScannerFacing, + ScannerGallery, + ScannerCamera, +}; + +export default { + Init: Scanner, + Flash: ScannerFlash, + Close: ScannerClose, + ScanBox: ScannerScanBox, + Facing: ScannerFacing, + Gallery: ScannerGallery, + Camera: ScannerCamera, +}; diff --git a/__app/component/Share/index.js b/__app/component/Share/index.js new file mode 100644 index 0000000..5429b11 --- /dev/null +++ b/__app/component/Share/index.js @@ -0,0 +1,5 @@ +import Share from './Share'; + +export { Share }; + +export default Share; diff --git a/__app/component/TextToSpeech/TextToSpeech.js b/__app/component/TextToSpeech/TextToSpeech.js index ded764d..f94165e 100644 --- a/__app/component/TextToSpeech/TextToSpeech.js +++ b/__app/component/TextToSpeech/TextToSpeech.js @@ -1,15 +1,94 @@ -import TextToSpeechInit from './TextToSpeechInit'; -import TextToSpeechStart from './TextToSpeechStart'; -import TextToSpeechStop from './TextToSpeechStop'; - -export { - TextToSpeechInit, - TextToSpeechStart, - TextToSpeechStop, +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import Wrapper from '../Wrapper/Wrapper'; +import textToSpeech from './textToSpeechService'; +import { handleSuccess, handleError, handleLoading } from '../services/handlerService'; + +const failureMsgDefault = { + unSupported: 'Text To Speech feature is not supporting in your device', + badRequest: 'Missing props', + error: 'Unable to convert text to voice', }; -export default { - Init: TextToSpeechInit, - Start: TextToSpeechStart, - Stop: TextToSpeechStop, +function TextToSpeech({ + successCb, + failureCb, + loadingCb, + successMsg, + failureMsg: failureMsgProps, + children, + text, +}) { + const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; + const [isAudioOn, setIsAudioOn] = useState(false); + + const handlePlay = async () => { + if (TextToSpeech.isBrowserSupport()) { + if (text) { + handleLoading({ loadingCb }); + setIsAudioOn(true); + try { + const utteranceCbk = await textToSpeech(text); + utteranceCbk.onend = () => { + setIsAudioOn(false); + handleSuccess({ msgType: 'SUCCESSFULFUL', msg: successMsg, successCb, data: text }); + }; + utteranceCbk.onerror = () => setIsAudioOn(false); + } catch (error) { + return handleError({ msgType: 'ERROR', msg: failureMsg.error, failureCb }); + } + } else { + return handleError({ msgType: 'MISSING_PARAMS', msg: failureMsg.badRequest, failureCb }); + } + } else { + return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); + } + + return true; + }; + + const handleStop = () => { + globalThis.speechSynthesis.cancel(); + setIsAudioOn(false); + }; + + useEffect(() => { + globalThis.speechSynthesis.cancel(); + return () => { + globalThis.speechSynthesis.cancel(); + }; + }, []); + + return React.Children.map(children, (child) => React.cloneElement(child, { + handleStop, + handlePlay, + isAudioOn, + successCb, + successMsg, + failureCb, + failureMsg, + })); +} + +TextToSpeech.isBrowserSupport = () => globalThis.speechSynthesis + && globalThis.speechSynthesis?.cancel + && globalThis.speechSynthesis?.speak + && true; + +TextToSpeech.propTypes = { + successCb: PropTypes.func, + failureCb: PropTypes.func, + loadingCb: PropTypes.func, + successMsg: PropTypes.string, + failureMsg: PropTypes.object, }; + +TextToSpeech.defaultProps = { + successCb: () => {}, + failureCb: () => {}, + loadingCb: () => {}, + successMsg: 'Converted text to voice Successfully', + failureMsg: { ...failureMsgDefault }, +}; + +export default Wrapper(TextToSpeech); diff --git a/__app/component/TextToSpeech/TextToSpeechInit.js b/__app/component/TextToSpeech/TextToSpeechInit.js deleted file mode 100644 index 6b71c23..0000000 --- a/__app/component/TextToSpeech/TextToSpeechInit.js +++ /dev/null @@ -1,94 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import Wrapper from '../Wrapper/Wrapper'; -import textToSpeech from './textToSpeechService'; -import { handleSuccess, handleError, handleLoading } from '../services/handlerService'; - -const failureMsgDefault = { - unSupported: 'Text To Speech feature is not supporting in your device', - badRequest: 'Missing props', - error: 'Unable to convert text to voice', -}; - -function TextToSpeechInit({ - successCb, - failureCb, - loadingCb, - successMsg, - failureMsg: failureMsgProps, - children, - text, -}) { - const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; - const [isAudioOn, setIsAudioOn] = useState(false); - - const handlePlay = async () => { - if (TextToSpeechInit.isBrowserSupport()) { - if (text) { - handleLoading({ loadingCb }); - setIsAudioOn(true); - try { - const utteranceCbk = await textToSpeech(text); - utteranceCbk.onend = () => { - setIsAudioOn(false); - handleSuccess({ msgType: 'SUCCESSFULFUL', msg: successMsg, successCb, data: text }); - }; - utteranceCbk.onerror = () => setIsAudioOn(false); - } catch (error) { - return handleError({ msgType: 'ERROR', msg: failureMsg.error, failureCb }); - } - } else { - return handleError({ msgType: 'MISSING_PARAMS', msg: failureMsg.badRequest, failureCb }); - } - } else { - return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); - } - - return true; - }; - - const handleStop = () => { - globalThis.speechSynthesis.cancel(); - setIsAudioOn(false); - }; - - useEffect(() => { - globalThis.speechSynthesis.cancel(); - return () => { - globalThis.speechSynthesis.cancel(); - }; - }, []); - - return React.Children.map(children, (child) => React.cloneElement(child, { - handleStop, - handlePlay, - isAudioOn, - successCb, - successMsg, - failureCb, - failureMsg, - })); -} - -TextToSpeechInit.isBrowserSupport = () => globalThis.speechSynthesis - && globalThis.speechSynthesis?.cancel - && globalThis.speechSynthesis?.speak - && true; - -TextToSpeechInit.propTypes = { - successCb: PropTypes.func, - failureCb: PropTypes.func, - loadingCb: PropTypes.func, - successMsg: PropTypes.string, - failureMsg: PropTypes.object, -}; - -TextToSpeechInit.defaultProps = { - successCb: () => {}, - failureCb: () => {}, - loadingCb: () => {}, - successMsg: 'Converted text to voice Successfully', - failureMsg: { ...failureMsgDefault }, -}; - -export default Wrapper(TextToSpeechInit); diff --git a/__app/component/TextToSpeech/index.js b/__app/component/TextToSpeech/index.js new file mode 100644 index 0000000..48b2230 --- /dev/null +++ b/__app/component/TextToSpeech/index.js @@ -0,0 +1,15 @@ +import TextToSpeech from './TextToSpeech'; +import TextToSpeechStart from './TextToSpeechStart'; +import TextToSpeechStop from './TextToSpeechStop'; + +export { + TextToSpeech, + TextToSpeechStart, + TextToSpeechStop, +}; + +export default { + Init: TextToSpeech, + Start: TextToSpeechStart, + Stop: TextToSpeechStop, +}; diff --git a/__app/component/Vibrate/index.js b/__app/component/Vibrate/index.js new file mode 100644 index 0000000..aacb0e3 --- /dev/null +++ b/__app/component/Vibrate/index.js @@ -0,0 +1,5 @@ +import Vibrate from './Vibrate'; + +export { Vibrate }; + +export default Vibrate; diff --git a/__app/component/VoiceRecognition/VoiceRecognition.js b/__app/component/VoiceRecognition/VoiceRecognition.js index 33752d7..4cf84b2 100644 --- a/__app/component/VoiceRecognition/VoiceRecognition.js +++ b/__app/component/VoiceRecognition/VoiceRecognition.js @@ -1,15 +1,104 @@ -import VoiceRecognitionInit from './VoiceRecognitionInit'; -import VoiceRecognitionIcon from './VoiceRecognitionIcon'; -import VoiceRecognitionModal from './VoiceRecognitionModal'; - -export { - VoiceRecognitionInit, - VoiceRecognitionIcon, - VoiceRecognitionModal, +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import Wrapper from '../Wrapper/Wrapper'; +import { handleSuccess, handleError, handleLoading } from '../services/handlerService'; + +const failureMsgDefault = { + unSupported: 'Voice Recognition feature is not supporting in your device', + error: 'Unable to convert your voice to text', +}; + +function VoiceRecognition({ + successCb, + failureCb, + loadingCb, + successMsg, + failureMsg: failureMsgProps, + children, +}) { + const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; + const [isModalVisible, setIsModalVisible] = useState(false); + const [isVoiceStarted, setIsVoiceStarted] = useState(false); + const [voiceText, setVoiceText] = useState(''); + + const listen = () => { + if (VoiceRecognition.isBrowserSupport()) { + handleLoading({ loadingCb }); + + const SpeechRecognition = globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition; + const recognition = new SpeechRecognition(); + + recognition.continuous = false; + recognition.lang = 'en-US'; + recognition.interimResults = true; + recognition.maxAlternatives = 1; + recognition.onresult = (event) => { + const text = event.results[0][0].transcript; + setVoiceText(text); + if (event.results[0].isFinal) { + setTimeout(() => { + handleSuccess({ msgType: 'SUCCESSFUL', msg: successMsg, successCb, data: text }); + setIsModalVisible(false); + setVoiceText(''); + }, 1500); + } + }; + recognition.start(); + recognition.onsoundstart = () => { + setIsVoiceStarted(true); + }; + recognition.onsoundend = () => { + setIsVoiceStarted(false); + }; + recognition.onerror = () => { + setIsModalVisible(false); + return handleError({ msgType: 'ERROR', msg: failureMsg.error, failureCb }); + }; + recognition.onend = () => { + recognition.abort(); + recognition.onresult = () => {}; + recognition.stop(); + setTimeout(() => setIsModalVisible(false), 1500); + }; + setIsModalVisible(true); + } else { + return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); + } + + return true; + }; + + return React.Children.map(children, (child) => React.cloneElement(child, { + successCb, + successMsg, + failureCb, + failureMsg, + listen, + isVoiceStarted, + isModalVisible, + voiceText, + onClose: () => setIsModalVisible(false), + + })); +} + +VoiceRecognition.isBrowserSupport = () => globalThis.SpeechRecognition + || globalThis.webkitSpeechRecognition; + +VoiceRecognition.propTypes = { + successCb: PropTypes.func, + failureCb: PropTypes.func, + loadingCb: PropTypes.func, + successMsg: PropTypes.string, + failureMsg: PropTypes.object, }; -export default { - Init: VoiceRecognitionInit, - Icon: VoiceRecognitionIcon, - Modal: VoiceRecognitionModal, +VoiceRecognition.defaultProps = { + successCb: () => {}, + failureCb: () => {}, + loadingCb: () => {}, + successMsg: 'Successfully converted your voice to text', + failureMsg: { ...failureMsgDefault }, }; + +export default Wrapper(VoiceRecognition); diff --git a/__app/component/VoiceRecognition/VoiceRecognitionInit.js b/__app/component/VoiceRecognition/VoiceRecognitionInit.js deleted file mode 100644 index 4cf84b2..0000000 --- a/__app/component/VoiceRecognition/VoiceRecognitionInit.js +++ /dev/null @@ -1,104 +0,0 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import Wrapper from '../Wrapper/Wrapper'; -import { handleSuccess, handleError, handleLoading } from '../services/handlerService'; - -const failureMsgDefault = { - unSupported: 'Voice Recognition feature is not supporting in your device', - error: 'Unable to convert your voice to text', -}; - -function VoiceRecognition({ - successCb, - failureCb, - loadingCb, - successMsg, - failureMsg: failureMsgProps, - children, -}) { - const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; - const [isModalVisible, setIsModalVisible] = useState(false); - const [isVoiceStarted, setIsVoiceStarted] = useState(false); - const [voiceText, setVoiceText] = useState(''); - - const listen = () => { - if (VoiceRecognition.isBrowserSupport()) { - handleLoading({ loadingCb }); - - const SpeechRecognition = globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition; - const recognition = new SpeechRecognition(); - - recognition.continuous = false; - recognition.lang = 'en-US'; - recognition.interimResults = true; - recognition.maxAlternatives = 1; - recognition.onresult = (event) => { - const text = event.results[0][0].transcript; - setVoiceText(text); - if (event.results[0].isFinal) { - setTimeout(() => { - handleSuccess({ msgType: 'SUCCESSFUL', msg: successMsg, successCb, data: text }); - setIsModalVisible(false); - setVoiceText(''); - }, 1500); - } - }; - recognition.start(); - recognition.onsoundstart = () => { - setIsVoiceStarted(true); - }; - recognition.onsoundend = () => { - setIsVoiceStarted(false); - }; - recognition.onerror = () => { - setIsModalVisible(false); - return handleError({ msgType: 'ERROR', msg: failureMsg.error, failureCb }); - }; - recognition.onend = () => { - recognition.abort(); - recognition.onresult = () => {}; - recognition.stop(); - setTimeout(() => setIsModalVisible(false), 1500); - }; - setIsModalVisible(true); - } else { - return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported, failureCb }); - } - - return true; - }; - - return React.Children.map(children, (child) => React.cloneElement(child, { - successCb, - successMsg, - failureCb, - failureMsg, - listen, - isVoiceStarted, - isModalVisible, - voiceText, - onClose: () => setIsModalVisible(false), - - })); -} - -VoiceRecognition.isBrowserSupport = () => globalThis.SpeechRecognition - || globalThis.webkitSpeechRecognition; - -VoiceRecognition.propTypes = { - successCb: PropTypes.func, - failureCb: PropTypes.func, - loadingCb: PropTypes.func, - successMsg: PropTypes.string, - failureMsg: PropTypes.object, -}; - -VoiceRecognition.defaultProps = { - successCb: () => {}, - failureCb: () => {}, - loadingCb: () => {}, - successMsg: 'Successfully converted your voice to text', - failureMsg: { ...failureMsgDefault }, -}; - -export default Wrapper(VoiceRecognition); diff --git a/__app/component/VoiceRecognition/index.js b/__app/component/VoiceRecognition/index.js new file mode 100644 index 0000000..80a169c --- /dev/null +++ b/__app/component/VoiceRecognition/index.js @@ -0,0 +1,15 @@ +import VoiceRecognition from './VoiceRecognition'; +import VoiceRecognitionIcon from './VoiceRecognitionIcon'; +import VoiceRecognitionModal from './VoiceRecognitionModal'; + +export { + VoiceRecognition, + VoiceRecognitionIcon, + VoiceRecognitionModal, +}; + +export default { + Init: VoiceRecognition, + Icon: VoiceRecognitionIcon, + Modal: VoiceRecognitionModal, +}; diff --git a/__app/component/WakeLock/WakeLock.js b/__app/component/WakeLock/WakeLock.js index 48a05a8..6d81707 100644 --- a/__app/component/WakeLock/WakeLock.js +++ b/__app/component/WakeLock/WakeLock.js @@ -1,26 +1,57 @@ +import PropTypes from 'prop-types'; import { handleError, handleSuccess } from '../services/handlerService'; function WakeLock(props = {}) { - const successCb = props.successCb || (() => {}); - const failureCb = props.failureCb || (() => {}); + const successCb = props.successCb || (() => { }); + const failureCb = props.failureCb || (() => { }); const successMsg = props.successMsg || ''; const failureMsg = props.failureMsg || {}; if (WakeLock.isBrowserSupport()) { - // const abort = new AbortController(); - // abortAutoFill(abort, 3); - // navigator.credentials.get({ - // otp: { transport: ['sms'] }, - // signal: abort.signal, - // }).then((otp) => { - // const { code } = otp; - // handleSuccess({ msgType: 'SUCCESSFUL', msg: successMsg, successCb, data: code }); - // }).catch((error) => handleError({ msgType: 'ERROR', msg: error, failureCb })); + let wakeLocker = null; + wakeLocker = navigator.wakeLock.request('screen'); + try { + if (wakeLocker) { + handleSuccess({ msgType: 'SUCCESSFUL', msg: successMsg, successCb }); + } else { + return handleError({ + msgType: 'CANCELLED', + failureCb, + }); + } + } catch (error) { + return handleError({ + msgType: 'ERROR', + msg: failureMsg.error || JSON.stringify(error), + failureCb, + }); + } } else { - return handleError({ msgType: 'UN_SUPPORTED_FEATURE', msg: failureMsg.unSupported || 'WakeLock is not supporting in your device', failureCb }); + return handleError({ + msgType: 'UN_SUPPORTED_FEATURE', + msg: + failureMsg.unSupported || 'WakeLock is not supporting in your device', + failureCb, + }); } } WakeLock.isBrowserSupport = () => 'wakeLock' in navigator; +WakeLock.propTypes = { + successCb: PropTypes.func, + failureCb: PropTypes.func, + successMsg: PropTypes.string, + failureMsg: PropTypes.object, +}; + +WakeLock.defaultProps = { + successCb: () => { }, + failureCb: () => { }, + successMsg: 'WakeLock successfully!!', + failureMsg: { + unSupported: 'Your browser does not support the WakeLock fetaure', + error: 'Unable to apply WakeLock', + }, +}; export default WakeLock; diff --git a/__app/component/WakeLock/index.js b/__app/component/WakeLock/index.js new file mode 100644 index 0000000..9c33f38 --- /dev/null +++ b/__app/component/WakeLock/index.js @@ -0,0 +1,5 @@ +import WakeLock from './WakeLock'; + +export { WakeLock }; + +export default WakeLock; diff --git a/__app/script/boilerPlate.js b/__app/script/boilerPlate.js new file mode 100644 index 0000000..508feb9 --- /dev/null +++ b/__app/script/boilerPlate.js @@ -0,0 +1,117 @@ +// console.log('Boiler Plate'); +// console.log(process.env.COMPONENT); +const fs = require('fs'); +const path = require('path'); +const { mkdirp } = require('mkdirp'); + +const { COMPONENT } = process.env; +// const srcPath = path.resolve(__dirname, '__app/component'); +const componentDir = path.resolve(`${__dirname}`, `../component/${COMPONENT}`); + +mkdirp(componentDir).then(() => { + const componentContent = `import React from 'react'; +import PropTypes from 'prop-types'; +import { handleSuccess, handleError, handleLoading } from '../services/handlerService'; +import Wrapper from '../Wrapper/Wrapper'; + +const failureMsgDefault = { + unSupported: '${COMPONENT} is not supporting in your device', + error: 'Unable to fetch details from ${COMPONENT}', +}; + +function ${COMPONENT}({ + successCb, + failureCb, + loadingCb, + successMsg, + failureMsg: failureMsgProps, + children, +}) { + const failureMsg = { ...failureMsgDefault, ...failureMsgProps }; + + const get${COMPONENT} = () => { + + }; + + return ( + React.Children.map(children || 'PhoneBook', (child) => React.cloneElement(typeof child === 'string' ? {child} : child, { + onClick: get${COMPONENT}, + })) + ); +} + +${COMPONENT}.isBrowserSupport = () => globalThis && true; + +${COMPONENT}.propTypes = { + successCb: PropTypes.func, + failureCb: PropTypes.func, + loadingCb: PropTypes.func, + successMsg: PropTypes.string, + failureMsg: PropTypes.object, +}; + +${COMPONENT}.defaultProps = { + successCb: () => {}, + failureCb: () => {}, + loadingCb: () => {}, + successMsg: 'Phonebook details fetch Successfully', + failureMsg: { ...failureMsgDefault }, +}; + +export default Wrapper(${COMPONENT}); +`; + const IndexContent = `import ${COMPONENT} from './${COMPONENT}'; + +export { ${COMPONENT} }; + +export default ${COMPONENT}; +`; + + const READMEContent = `## 1. Happy Flow +#### a) Passing child + + + + +## 2. Success: successCb callBack Fn along with success msg + + + + + +> [!Note] +> **successCb** will get an object contains the property **msgType**, **msg**, **data** + +## 3. Failure: failureCb callBack Fn along with failure msg + + + + + +> [!Note] +> **failureCb** will get an object contains the property **msgType**, **msg** + +> [!Important] +Failure can happend due to multiple reasons, due to that reason **failureMsg** is an object having different kind of error property according to the error can occur in component + +## 4. Failure: Device don't support the feature and you want to hide the feauture from User + + + + + +> [!Note] +> if **showForever** props value is false, feature will be hidden in case of unSupported by the device + +## 5. Combine with all props + + + + + + `; + + fs.writeFile((`${componentDir}/${COMPONENT}.js`), componentContent, () => {}); + fs.writeFile((`${componentDir}/index.js`), IndexContent, () => {}); + fs.writeFile((`${componentDir}/README.md`), READMEContent, () => {}); +}); diff --git a/__app/script/generateIndex.js b/__app/script/generateIndex.js index 653d668..24a00d8 100644 --- a/__app/script/generateIndex.js +++ b/__app/script/generateIndex.js @@ -29,11 +29,15 @@ const srcPath = path.resolve(__dirname, '../component'); const components = fs.readdirSync(srcPath).filter((files) => !ignoreFiles.includes(files) && !files.includes('WIP-')); let count = 0; +let indexImport = ''; +let indexExport = '\nexport {'; components.forEach((component) => { + indexImport += `import ${component} from './${component}';\n`; + indexExport += `\n ${component},`; const componentDir = path.resolve(`${__dirname}`, `../../${component}`); mkdirp(componentDir).then(() => { const componentFile = path.resolve(componentDir, 'index.js'); - const componentContent = `export { default } from '../__build/${component}/${component}';\nexport * from '../__build/${component}/${component}';\n`; + const componentContent = `export { default } from '../__build/${component}';\nexport * from '../__build/${component}';\n`; // const componentContent = `import ${component} // from '../__build/${component}/${component}';\nexport default ${component};\n`; fs.writeFile(componentFile, componentContent, (writeFileErr) => { @@ -50,3 +54,5 @@ components.forEach((component) => { }); }); }); +indexExport += '\n};\n'; +fs.writeFile(('index.js'), indexImport + indexExport, () => {}); diff --git a/package.json b/package.json index f15fadf..7e2133f 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,10 @@ "name": "fe-pilot", "version": "1.0.65", "description": "Advance JS features, Plug & Play", - "main": "", + "main": "index.js", "scripts": { "test": "echo \"Success: Verified\"", + "create": "node ./__app/script/boilerPlate.js", "start": "npm run local", "local": "npm run local:indexfile && npm run local:component", "local:indexfile": "node ./__app/script/generateIndex.js", @@ -57,7 +58,8 @@ "share", "livelocationtracking", "detectmylocation", - "colorpicker" + "colorpicker", + "wakelock" ], "config": { "commitizen": { @@ -80,7 +82,9 @@ }, "files": [ "__build/**", + "./index.js", "AutoFillOtp/", + "ABCD/", "Bluetooth/", "FaceDetector/", "CopyToClipboard/",