Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for scanning qr from images/pdfs #8

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
./inji-verify/node_modules
/.pnp
.pnp.js

Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
# inji-verify
Repository host the source code, documentation, and other related files for the Inji Verify project.

# Project Setup - Development

Prerequisites:
* Node 18 - Can be installed using [nvm](https://github.com/nvm-sh/nvm). Run following command to install node

```curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash```

```nvm install 18```

Run following commands to start the application

```npm install```

```npm start```


38 changes: 38 additions & 0 deletions inji-verify/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions inji-verify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"@emotion/styled": "^11.11.5",
"@mui/material": "^5.15.14",
"@mui/styled-engine": "^5.15.14",
"@openhealthnz-credentials/pdf-image-qr-scanner": "^1.0.2",
"@sunbird-rc/verification-sdk": "^0.1.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
Expand Down
2 changes: 1 addition & 1 deletion inji-verify/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/inji-logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
Expand Down
Binary file added inji-verify/public/inji-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions inji-verify/src/assets/qr.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import {Box, Step, StepContent, StepLabel, Stepper, Typography} from "@mui/material";
import {InjiStepperStep} from "../../../../types/data-types";

function DesktopStepper({steps, activeStep}: {steps: InjiStepperStep[], activeStep: number}) {
return (
<Stepper activeStep={activeStep} orientation="vertical">
{steps.map((step, index) => (
<Step key={step.label} style={{alignContent: 'start'}}>
<StepLabel>
<Typography style={{font: 'normal normal bold 16px/20px Inter'}}>
{step.label}
</Typography>
</StepLabel>
<StepContent
TransitionProps={{appear: true, unmountOnExit: false}}
hidden={false} style={{borderColor: '#FF7F00', display: 'block'}}>
<Typography>{step.description}</Typography>
</StepContent>
</Step>
))}
</Stepper>
);
}

export default DesktopStepper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import {Step, StepLabel, Stepper, Typography} from "@mui/material";
import {InjiStepperStep} from "../../../../types/data-types";

function MobileStepper({steps, activeStep}: {steps: InjiStepperStep[], activeStep: number}) {
return (
<Stepper style={{maxHeight: '350px'}} activeStep={activeStep} orientation="horizontal" alternativeLabel>
{steps.map((step, index) => (
<Step key={step.label} style={{alignContent: 'start'}}>
<StepLabel>
<Typography style={{font: 'normal normal bold 16px/20px Inter'}}>
{step.label}
</Typography>
</StepLabel>
</Step>
))}
</Stepper>
);
}

export default MobileStepper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import {Box, Step, StepContent, StepLabel, Stepper, Typography, useMediaQuery} from "@mui/material";
import DesktopStepper from "./DesktopStepper";
import MobileStepper from "./MobileStepper";
import {InjiStepperStep} from "../../../../types/data-types";

const steps: InjiStepperStep[] = [
{
label: 'Scan QR Code',
description: 'Tap the button and display the QR code shown on your digital certificate / card',
},
{
label: 'Activate your device’s camera',
description:
'A notification will prompt to activate your device’s camera',
},
{
label: 'Verification',
description: 'Validating and verification of your digital document / card'
},
{
label: 'Result',
description: 'Credibility result of your digital document / card'
}
];

const InjiStepper = ({activeStep}: {activeStep: number}) => {
const isDesktop = useMediaQuery('@media (min-width:768px)');

return (
<Box style={{marginTop: '30px'}}>
{
isDesktop
? (<DesktopStepper steps={steps} activeStep={activeStep}/>)
: (<MobileStepper steps={steps} activeStep={activeStep}/>)
}
</Box>
);
}

export default InjiStepper;
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, {useCallback, useState} from 'react';
import {Scanner} from '@yudiel/react-qr-scanner';


function QrScanner({setVerifying, setActiveStep, setQrData}: any) {
function QrScanner({setVerifying, setActiveStep, setQrData}: {
setVerifying: (verifying: boolean) => void, setQrData: (data: string) => void, setActiveStep: (activeStep: number) => void
}) {
const [dataRead, setDataRead] = useState(false)
const isDataRead = useCallback(() => dataRead, [dataRead]);

Expand Down Expand Up @@ -46,8 +47,7 @@ function QrScanner({setVerifying, setActiveStep, setQrData}: any) {
video: {
zIndex: 1000
}
}
}
}}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import {Box, Typography} from "@mui/material";
import {Box, Typography, useMediaQuery} from "@mui/material";

function StepperContentHeader(props: any) {
const isTabletOrAbove = useMediaQuery("@media(min-width:600px)");
return (
<Box>
<Typography variant='h4' style={{
Expand All @@ -10,12 +11,16 @@ function StepperContentHeader(props: any) {
}}>
Verify your credentials in <span style={{color: '#FF7F00'}}>4 easy steps</span>
</Typography>
<Typography variant='body1' style={{
font: 'normal normal normal 16px/21px Inter',
margin: '6px 0'
}}>
Credentials are digitally signed documents with tamper-evident QR codes. These QR codes can be easily verified using the Inji Verify app. Simply scan the QR code with your smartphone camera or use the dedicated verification tool on this page.
</Typography>
{
isTabletOrAbove && (
<Typography variant='body1' style={{
font: 'normal normal normal 16px/21px Inter',
margin: '6px 0'
}}>
Credentials are digitally signed documents with tamper-evident QR codes. These QR codes can be easily verified using the Inji Verify app. Simply scan the QR code with your smartphone camera or use the dedicated verification tool on this page.
</Typography>
)
}
</Box>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ export const VerificationProgressTrackerContainer = styled(Box)`
margin-top: 0;
height: 100vh;
max-height: 100vh;
overflow-y: scroll;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {scanFilesForQr} from "../../../utils/qr-utils";
import {QrScanResult} from "../../../types/data-types";
import {SetScanResultFunction} from "../../../types/function-types";
import StyledButton from "./commons/StyledButton";

export const ImportFromFile = ({setScanResult}: {setScanResult: SetScanResultFunction}) => {
return (
<div style={{margin: "12px auto", display: "grid", placeContent: "center"}}>
<StyledButton>
<label htmlFor={"upload-qr"}>
Upload your certificate</label>
</StyledButton>
<br/>
<input
type="file"
id="upload-qr"
name="upload-qr"
accept=".png, .jpeg, .jpg, .pdf"
style={{
margin: "8px auto",
display: "none"
}}
onChange={e => {
const file = e?.target?.files && e?.target?.files[0];
if (!file) return;
scanFilesForQr(file)
.then(scanResult => {
setScanResult(scanResult);
});
}}
/>
</div>);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import React from 'react';
import {Grid, Typography} from "@mui/material";
import {ReactComponent as VerificationSuccessIcon} from "../../../../assets/verification-success-icon.svg";
import {ReactComponent as VerificationFailedIcon} from "../../../../assets/verification-failed-icon.svg";
import {SetActiveStepFunction} from "../../../../types/function-types";

const ResultSummary = ({success, vc, setActiveStep}: {
success: boolean,
vc: any,
setActiveStep: (activeStep: number) => void
setActiveStep: SetActiveStepFunction
}) => {
return (
<Grid container>
Expand Down
Loading
Loading