From 0bba63330d813202e7074979384d196468c50a7a Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 1 Sep 2021 06:33:42 -0300 Subject: [PATCH 1/5] First working prototype --- package-lock.json | 90 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/Title.tsx | 42 ++++++++++++++++++++++ 3 files changed, 133 insertions(+) diff --git a/package-lock.json b/package-lock.json index e0422fc..21ccd93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "license": "MIT", "dependencies": { + "@blackbox-vision/react-qr-reader": "^5.0.0", "@chainlink/contracts": "^0.2.1", "@craco/craco": "^6.2.0", "@fontsource/fira-code": "^4.5.1", @@ -1209,6 +1210,19 @@ "version": "0.2.3", "license": "MIT" }, + "node_modules/@blackbox-vision/react-qr-reader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@blackbox-vision/react-qr-reader/-/react-qr-reader-5.0.0.tgz", + "integrity": "sha512-VLNKwwJTv4UX1inUNgt2aGC2yIhKBYptW9EOhn7Nq//WzjD5KvHG7WR48HTzGUZ2s/EA0XlxZSfKOarHV1Vb/A==", + "dependencies": { + "@zxing/browser": "0.0.7", + "@zxing/library": "^0.18.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/@chainlink/contracts": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.2.1.tgz", @@ -3512,6 +3526,37 @@ "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz", "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==" }, + "node_modules/@zxing/browser": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@zxing/browser/-/browser-0.0.7.tgz", + "integrity": "sha512-AepzMgDnD6EjxewqmXpHJsi4S3Gw9ilZJLIbTf6fWuWySEcHBodnGu3p7FWlgq1Sd5QyfPhTum5z3CBkkhMVng==", + "optionalDependencies": { + "@zxing/text-encoding": "^0.9.0" + }, + "peerDependencies": { + "@zxing/library": "^0.18.3" + } + }, + "node_modules/@zxing/library": { + "version": "0.18.6", + "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.18.6.tgz", + "integrity": "sha512-bulZ9JHoLFd9W36pi+7e7DnEYNJhljYjZ1UTsKPOoLMU3qtC+REHITeCRNx40zTRJZx18W5TBRXt5pq2Uopjsw==", + "dependencies": { + "ts-custom-error": "^3.0.0" + }, + "engines": { + "node": ">= 10.4.0" + }, + "optionalDependencies": { + "@zxing/text-encoding": "~0.9.0" + } + }, + "node_modules/@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, "node_modules/abab": { "version": "2.0.5", "license": "BSD-3-Clause" @@ -17825,6 +17870,14 @@ "version": "1.0.1", "license": "MIT" }, + "node_modules/ts-custom-error": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", + "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/ts-pnp": { "version": "1.2.0", "license": "MIT", @@ -20240,6 +20293,15 @@ "@bcoe/v8-coverage": { "version": "0.2.3" }, + "@blackbox-vision/react-qr-reader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@blackbox-vision/react-qr-reader/-/react-qr-reader-5.0.0.tgz", + "integrity": "sha512-VLNKwwJTv4UX1inUNgt2aGC2yIhKBYptW9EOhn7Nq//WzjD5KvHG7WR48HTzGUZ2s/EA0XlxZSfKOarHV1Vb/A==", + "requires": { + "@zxing/browser": "0.0.7", + "@zxing/library": "^0.18.3" + } + }, "@chainlink/contracts": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.2.1.tgz", @@ -21700,6 +21762,29 @@ "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz", "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==" }, + "@zxing/browser": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@zxing/browser/-/browser-0.0.7.tgz", + "integrity": "sha512-AepzMgDnD6EjxewqmXpHJsi4S3Gw9ilZJLIbTf6fWuWySEcHBodnGu3p7FWlgq1Sd5QyfPhTum5z3CBkkhMVng==", + "requires": { + "@zxing/text-encoding": "^0.9.0" + } + }, + "@zxing/library": { + "version": "0.18.6", + "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.18.6.tgz", + "integrity": "sha512-bulZ9JHoLFd9W36pi+7e7DnEYNJhljYjZ1UTsKPOoLMU3qtC+REHITeCRNx40zTRJZx18W5TBRXt5pq2Uopjsw==", + "requires": { + "@zxing/text-encoding": "~0.9.0", + "ts-custom-error": "^3.0.0" + } + }, + "@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, "abab": { "version": "2.0.5" }, @@ -31387,6 +31472,11 @@ "tryer": { "version": "1.0.1" }, + "ts-custom-error": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", + "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==" + }, "ts-pnp": { "version": "1.2.0" }, diff --git a/package.json b/package.json index 938ff28..fb6e41e 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "license": "MIT", "dependencies": { + "@blackbox-vision/react-qr-reader": "^5.0.0", "@chainlink/contracts": "^0.2.1", "@craco/craco": "^6.2.0", "@fontsource/fira-code": "^4.5.1", diff --git a/src/Title.tsx b/src/Title.tsx index 46e1e5c..0a017f7 100644 --- a/src/Title.tsx +++ b/src/Title.tsx @@ -1,5 +1,11 @@ import React, { useState, useRef, useContext } from "react"; +import { isAddress } from "@ethersproject/address"; import { Link, useHistory } from "react-router-dom"; +import { QrReader } from "@blackbox-vision/react-qr-reader"; +import { OnResultFunction } from "@blackbox-vision/react-qr-reader/dist-types/types"; +import { BarcodeFormat } from "@zxing/library"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faQrcode } from "@fortawesome/free-solid-svg-icons/faQrcode"; import useKeyboardShortcut from "use-keyboard-shortcut"; import PriceBox from "./PriceBox"; import { RuntimeContext } from "./useRuntime"; @@ -29,6 +35,28 @@ const Title: React.FC = () => { searchRef.current?.focus(); }); + const [isScanning, setScanning] = useState(); + const onScan = () => { + setScanning(!isScanning); + }; + const evaluateScan: OnResultFunction = (result, error, codeReader) => { + console.log("scan"); + if (!error && result?.getBarcodeFormat() === BarcodeFormat.QR_CODE) { + const text = result.getText(); + console.log(`Scanned: ${text}`); + if (!isAddress(text)) { + console.log("Not an ETH address"); + return; + } + + if (searchRef.current) { + searchRef.current.value = text; + searchRef.current.dispatchEvent(new Event("input", { bubbles: true })); + } + setScanning(false); + } + }; + return (
@@ -60,6 +88,20 @@ const Title: React.FC = () => { onChange={handleChange} ref={searchRef} /> + + {isScanning && ( + + )} - {isScanning && ( + <> + setScanning(false)} + > +
+ + + Point an ETH address QR code to camera + +
- )} -
+
+
+ +
+ An otter scanning + Otterscan +
+ +
+ {provider?.network.chainId === 1 && } + - Search - - + + + + +
-
+ ); }; From 51b18b763fa4c4752fcd24d3f7b090d04cbd6972 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 1 Sep 2021 17:40:42 -0300 Subject: [PATCH 3/5] Extract common camera scan code; apply it to home also --- src/Home.tsx | 30 ++++++++++++++------ src/Title.tsx | 46 +++--------------------------- src/search/CameraScanner.tsx | 54 ++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 50 deletions(-) create mode 100644 src/search/CameraScanner.tsx diff --git a/src/Home.tsx b/src/Home.tsx index 31ecb9a..6fb58c8 100644 --- a/src/Home.tsx +++ b/src/Home.tsx @@ -3,7 +3,9 @@ import { NavLink, useHistory } from "react-router-dom"; import { commify } from "@ethersproject/units"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBurn } from "@fortawesome/free-solid-svg-icons/faBurn"; +import { faQrcode } from "@fortawesome/free-solid-svg-icons/faQrcode"; import Logo from "./Logo"; +import CameraScanner from "./search/CameraScanner"; import Timestamp from "./components/Timestamp"; import { RuntimeContext } from "./useRuntime"; import { useLatestBlock } from "./useLatestBlock"; @@ -30,11 +32,13 @@ const Home: React.FC = () => { }; const latestBlock = useLatestBlock(provider); + const [isScanning, setScanning] = useState(false); document.title = "Home | Otterscan"; return (
+ {isScanning && setScanning(false)} />}
{ autoComplete="off" spellCheck={false} > - +
+ + +
diff --git a/src/search/CameraScanner.tsx b/src/search/CameraScanner.tsx new file mode 100644 index 0000000..b32d707 --- /dev/null +++ b/src/search/CameraScanner.tsx @@ -0,0 +1,54 @@ +import React from "react"; +import { useHistory } from "react-router-dom"; +import { isAddress } from "@ethersproject/address"; +import { QrReader } from "@blackbox-vision/react-qr-reader"; +import { OnResultFunction } from "@blackbox-vision/react-qr-reader/dist-types/types"; +import { BarcodeFormat } from "@zxing/library"; +import { Dialog } from "@headlessui/react"; + +type CameraScannerProps = { + turnOffScan: () => void; +}; + +const CameraScanner: React.FC = ({ turnOffScan }) => { + const history = useHistory(); + + const evaluateScan: OnResultFunction = (result, error, codeReader) => { + console.log("scan"); + if (!error && result?.getBarcodeFormat() === BarcodeFormat.QR_CODE) { + const text = result.getText(); + console.log(`Scanned: ${text}`); + if (!isAddress(text)) { + console.warn("Not an ETH address"); + return; + } + + history.push(`/search?q=${text}`); + turnOffScan(); + } + }; + + return ( + +
+ + + Point an ETH address QR code to camera + +
+ +
+
+
+ ); +}; + +export default CameraScanner; From b204c7cf55e7813380ca56b031990003883fa26e Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 1 Sep 2021 17:56:12 -0300 Subject: [PATCH 4/5] Create test theme --- src/index.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/index.css b/src/index.css index 6088bfb..4cd29ee 100644 --- a/src/index.css +++ b/src/index.css @@ -11,4 +11,12 @@ --color-table-row-hover: 243, 244, 246; } + .test-theme { + --color-from-border: 251, 146, 60; + --color-from-text: 249, 115, 22; + --color-from-fill: 254, 215, 170; + --color-to-fill: 125, 211, 252; + + --color-table-row-hover: 2, 132, 199; + } } From 54f5c9e6c7757eab5f81917bb7d4817fa943747a Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 1 Sep 2021 18:12:35 -0300 Subject: [PATCH 5/5] Extract action button theme --- src/Home.tsx | 4 ++-- src/Title.tsx | 4 ++-- src/index.css | 8 ++++++++ tailwind.config.js | 5 +++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Home.tsx b/src/Home.tsx index 6fb58c8..650c86c 100644 --- a/src/Home.tsx +++ b/src/Home.tsx @@ -56,7 +56,7 @@ const Home: React.FC = () => { autoFocus />