mirror of
https://github.com/covidpass-org/covidpass.git
synced 2025-02-22 22:47:44 +01:00
new receipt handling
- dynamically load receipt payload into obj keyed by dose number - select dose number option based on receipt
This commit is contained in:
parent
bebc470d88
commit
b90cabb5d5
@ -30,31 +30,48 @@ function Form(): JSX.Element {
|
||||
// Currently selected color
|
||||
const [selectedColor, setSelectedColor] = useState<COLORS>(COLORS.WHITE);
|
||||
|
||||
// Currently selected dose
|
||||
const [selectedDose, setSelectedDose] = useState<number>(2);
|
||||
|
||||
// Global camera controls
|
||||
const [globalControls, setGlobalControls] = useState<IScannerControls>(undefined);
|
||||
|
||||
// Currently selected QR Code / File. Only one of them is set.
|
||||
const [qrCode, setQrCode] = useState<Result>(undefined);
|
||||
const [file, setFile] = useState<File>(undefined);
|
||||
const [payloadBody, setPayloadBody] = useState<PayloadBody>(undefined);
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [saveLoading, setSaveLoading] = useState<boolean>(false);
|
||||
const [fileLoading, setFileLoading] = useState<boolean>(false);
|
||||
|
||||
const [generated, setGenerated] = useState<boolean>(false); // this flag represents the file has been used to generate a pass
|
||||
|
||||
const [isDisabledAppleWallet, setIsDisabledAppleWallet] = useState<boolean>(false);
|
||||
const [errorMessages, _setErrorMessages] = useState<Array<string>>([]);
|
||||
const [addErrorMessages, _setAddErrorMessages] = useState<Array<string>>([]);
|
||||
const [fileErrorMessages, _setFileErrorMessages] = useState<Array<string>>([]);
|
||||
|
||||
const [showDoseOption, setShowDoseOption] = useState<boolean>(false);
|
||||
// const [warningMessages, _setWarningMessages] = useState<Array<string>>([]);
|
||||
const hitcountHost = 'https://stats.vaccine-ontario.ca';
|
||||
|
||||
|
||||
// Check if there is a translation and replace message accordingly
|
||||
const setErrorMessage = (message: string) => {
|
||||
const setAddErrorMessage = (message: string) => {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
const translation = t('errors:'.concat(message));
|
||||
_setErrorMessages(Array.from(new Set([...errorMessages, translation !== message ? translation : message])));
|
||||
_setAddErrorMessages(Array.from(new Set([...addErrorMessages, translation !== message ? translation : message])));
|
||||
};
|
||||
|
||||
const setFileErrorMessage = (message: string) => {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
const translation = t('errors:'.concat(message));
|
||||
_setFileErrorMessages(Array.from(new Set([...addErrorMessages, translation !== message ? translation : message])));
|
||||
};
|
||||
|
||||
// const setWarningMessage = (message: string) => {
|
||||
@ -66,9 +83,11 @@ function Form(): JSX.Element {
|
||||
// _setWarningMessages(Array.from(new Set([...warningMessages, translation !== message ? translation : message])));
|
||||
// }
|
||||
|
||||
const deleteErrorMessage = (message: string) =>{
|
||||
console.log(errorMessages)
|
||||
_setErrorMessages(errorMessages.filter(item => item !== message))
|
||||
const deleteAddErrorMessage = (message: string) =>{
|
||||
_setAddErrorMessages(addErrorMessages.filter(item => item !== message))
|
||||
}
|
||||
const deleteFileErrorMessage = (message: string) =>{
|
||||
_setFileErrorMessages(addErrorMessages.filter(item => item !== message))
|
||||
}
|
||||
|
||||
// File Input ref
|
||||
@ -80,17 +99,55 @@ function Form(): JSX.Element {
|
||||
inputFile.current.addEventListener('input', () => {
|
||||
let selectedFile = inputFile.current.files[0];
|
||||
if (selectedFile !== undefined) {
|
||||
setFileLoading(true);
|
||||
setQrCode(undefined);
|
||||
setFile(selectedFile);
|
||||
setPayloadBody(undefined);
|
||||
setFile(undefined);
|
||||
setShowDoseOption(false);
|
||||
setGenerated(false);
|
||||
deleteErrorMessage(t('errors:'.concat('noFileOrQrCode')));
|
||||
deleteAddErrorMessage(t('errors:'.concat('noFileOrQrCode')));
|
||||
_setFileErrorMessages([]);
|
||||
checkBrowserType();
|
||||
getPayload(selectedFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
checkBrowserType();
|
||||
}, [inputFile])
|
||||
|
||||
async function getPayload(file){
|
||||
try {
|
||||
const payload = await getPayloadBodyFromFile(file, COLORS.GREEN);
|
||||
setPayloadBody(payload);
|
||||
setFileLoading(false);
|
||||
setFile(file);
|
||||
|
||||
if (Object.keys(payload.receipts).length === 1) {
|
||||
setSelectedDose(parseInt(Object.keys(payload.receipts)[0]));
|
||||
}else{
|
||||
setShowDoseOption(true);
|
||||
}
|
||||
} catch (e) {
|
||||
setFile(file);
|
||||
setFileLoading(false);
|
||||
if (e != undefined) {
|
||||
console.error(e);
|
||||
|
||||
Sentry.captureException(e);
|
||||
|
||||
if (e.message != undefined) {
|
||||
setFileErrorMessage(e.message);
|
||||
} else {
|
||||
setFileErrorMessage("Unable to continue.");
|
||||
}
|
||||
|
||||
} else {
|
||||
setFileErrorMessage("Unexpected error. Sorry.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Show file Dialog
|
||||
async function showFileDialog() {
|
||||
inputFile.current.click();
|
||||
@ -124,13 +181,13 @@ function Form(): JSX.Element {
|
||||
try {
|
||||
deviceList = await BrowserQRCodeReader.listVideoInputDevices();
|
||||
} catch (e) {
|
||||
setErrorMessage('noCameraAccess');
|
||||
setAddErrorMessage('noCameraAccess');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if camera device is present
|
||||
if (deviceList.length == 0) {
|
||||
setErrorMessage("noCameraFound");
|
||||
setAddErrorMessage("noCameraFound");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -154,7 +211,7 @@ function Form(): JSX.Element {
|
||||
setIsCameraOpen(false);
|
||||
}
|
||||
if (error !== undefined) {
|
||||
setErrorMessage(error.message);
|
||||
setAddErrorMessage(error.message);
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -186,40 +243,33 @@ function Form(): JSX.Element {
|
||||
async function addToWallet(event: FormEvent<HTMLFormElement>) {
|
||||
|
||||
event.preventDefault();
|
||||
setLoading(true);
|
||||
setSaveLoading(true);
|
||||
|
||||
if (!file && !qrCode) {
|
||||
setErrorMessage('noFileOrQrCode')
|
||||
setLoading(false);
|
||||
setAddErrorMessage('noFileOrQrCode')
|
||||
setSaveLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const color = selectedColor;
|
||||
let payloadBody: PayloadBody;
|
||||
|
||||
try {
|
||||
if (file) {
|
||||
|
||||
//console.log('> get payload');
|
||||
payloadBody = await getPayloadBodyFromFile(file, color);
|
||||
|
||||
const passName = payloadBody.receipt.name.replace(' ', '-');
|
||||
const vaxName = payloadBody.receipt.vaccineName.replace(' ', '-');
|
||||
const passDose = payloadBody.receipt.numDoses;
|
||||
if (payloadBody) {
|
||||
const passName = payloadBody.receipts[selectedDose].name.replace(' ', '-');
|
||||
const vaxName = payloadBody.receipts[selectedDose].vaccineName.replace(' ', '-');
|
||||
const passDose = payloadBody.receipts[selectedDose].numDoses;
|
||||
const covidPassFilename = `grassroots-receipt-${passName}-${vaxName}-${passDose}.pkpass`;
|
||||
|
||||
//console.log('> increment count');
|
||||
await incrementCount();
|
||||
|
||||
//console.log('> generatePass');
|
||||
let pass = await PassData.generatePass(payloadBody);
|
||||
// console.log('> generatePass');
|
||||
const pass = await PassData.generatePass(payloadBody, selectedDose);
|
||||
|
||||
//console.log('> create blob');
|
||||
const passBlob = new Blob([pass], {type: "application/vnd.apple.pkpass"});
|
||||
|
||||
//console.log(`> save blob as ${covidPassFilename}`);
|
||||
saveAs(passBlob, covidPassFilename);
|
||||
setLoading(false);
|
||||
setSaveLoading(false);
|
||||
}
|
||||
|
||||
|
||||
@ -231,16 +281,16 @@ function Form(): JSX.Element {
|
||||
Sentry.captureException(e);
|
||||
|
||||
if (e.message != undefined) {
|
||||
setErrorMessage(e.message);
|
||||
setAddErrorMessage(e.message);
|
||||
} else {
|
||||
setErrorMessage("Unable to continue.");
|
||||
setAddErrorMessage("Unable to continue.");
|
||||
}
|
||||
|
||||
} else {
|
||||
setErrorMessage("Unexpected error. Sorry.");
|
||||
setAddErrorMessage("Unexpected error. Sorry.");
|
||||
|
||||
}
|
||||
setLoading(false);
|
||||
setSaveLoading(false);
|
||||
|
||||
}
|
||||
}
|
||||
@ -249,21 +299,17 @@ function Form(): JSX.Element {
|
||||
|
||||
async function saveAsPhoto() {
|
||||
|
||||
setLoading(true);
|
||||
setSaveLoading(true);
|
||||
|
||||
if (!file && !qrCode) {
|
||||
setErrorMessage('noFileOrQrCode');
|
||||
setLoading(false);
|
||||
setAddErrorMessage('noFileOrQrCode');
|
||||
setSaveLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let payloadBody: PayloadBody;
|
||||
|
||||
try {
|
||||
payloadBody = await getPayloadBodyFromFile(file, COLORS.GREEN);
|
||||
await incrementCount();
|
||||
|
||||
let photoBlob = await Photo.generatePass(payloadBody);
|
||||
let photoBlob = await Photo.generatePass(payloadBody, selectedDose);
|
||||
saveAs(photoBlob, 'pass.png');
|
||||
|
||||
// need to clean up
|
||||
@ -273,11 +319,11 @@ function Form(): JSX.Element {
|
||||
const body = document.getElementById('pass-image');
|
||||
body.hidden = true;
|
||||
|
||||
setLoading(false);
|
||||
setSaveLoading(false);
|
||||
} catch (e) {
|
||||
Sentry.captureException(e);
|
||||
setErrorMessage(e.message);
|
||||
setLoading(false);
|
||||
setAddErrorMessage(e.message);
|
||||
setSaveLoading(false);
|
||||
}
|
||||
}
|
||||
const verifierLink = () => <li className="flex flex-row items-center">
|
||||
@ -292,23 +338,27 @@ function Form(): JSX.Element {
|
||||
</p>
|
||||
</li>
|
||||
|
||||
const setDose = (e) => {
|
||||
setSelectedDose(e.target.value);
|
||||
}
|
||||
|
||||
function checkBrowserType() {
|
||||
|
||||
// if (isIPad13) {
|
||||
// setErrorMessage('Sorry. Apple does not support the use of Wallet on iPad. Please use iPhone/Safari.');
|
||||
// setAddErrorMessage('Sorry. Apple does not support the use of Wallet on iPad. Please use iPhone/Safari.');
|
||||
// setIsDisabledAppleWallet(true);
|
||||
// }
|
||||
// if (!isSafari && !isChrome) {
|
||||
// setErrorMessage('Sorry. Apple Wallet pass can be added using Safari or Chrome only.');
|
||||
// setAddErrorMessage('Sorry. Apple Wallet pass can be added using Safari or Chrome only.');
|
||||
// setIsDisabledAppleWallet(true);
|
||||
// }
|
||||
// if (isIOS && (!osVersion.includes('13') && !osVersion.includes('14') && !osVersion.includes('15'))) {
|
||||
// setErrorMessage('Sorry, iOS 13+ is needed for the Apple Wallet functionality to work')
|
||||
// setAddErrorMessage('Sorry, iOS 13+ is needed for the Apple Wallet functionality to work')
|
||||
// setIsDisabledAppleWallet(true);
|
||||
// }
|
||||
if (isIOS && !isSafari) {
|
||||
// setErrorMessage('Sorry, only Safari can be used to add a Wallet Pass on iOS');
|
||||
setErrorMessage('Sorry, only Safari can be used to add a Wallet Pass on iOS');
|
||||
// setAddErrorMessage('Sorry, only Safari can be used to add a Wallet Pass on iOS');
|
||||
setAddErrorMessage('Sorry, only Safari can be used to add a Wallet Pass on iOS');
|
||||
setIsDisabledAppleWallet(true);
|
||||
console.log('not safari')
|
||||
}
|
||||
@ -346,13 +396,21 @@ function Form(): JSX.Element {
|
||||
<Card step="2" heading={t('index:selectCertificate')} content={
|
||||
<div className="space-y-5">
|
||||
<p>{t('index:selectCertificateDescription')}</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-5 items-center justify-start">
|
||||
<button
|
||||
type="button"
|
||||
onClick={showFileDialog}
|
||||
className="focus:outline-none h-20 bg-green-600 hover:bg-gray-700 text-white font-semibold rounded-md">
|
||||
{t('index:openFile')}
|
||||
</button>
|
||||
<div id="spin" className={fileLoading ? undefined : "hidden"}>
|
||||
<svg className="animate-spin h-5 w-5 ml-4" viewBox="0 0 24 24">
|
||||
<circle className="opacity-0" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
strokeWidth="4"/>
|
||||
<path className="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type='file'
|
||||
@ -378,10 +436,37 @@ function Form(): JSX.Element {
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
{fileErrorMessages.map((message, i) =>
|
||||
<Alert message={message} key={'error-' + i} type="error" />
|
||||
)}
|
||||
</div>
|
||||
}/>
|
||||
|
||||
<Card step="3" heading={t('index:addToWalletHeader')} content={
|
||||
{showDoseOption && <Card step="3" heading={'Choose dose number'} content={
|
||||
<div className="space-y-5">
|
||||
<p>
|
||||
{t('index:formatChange')}
|
||||
<br /><br />
|
||||
{t('index:saveMultiple')}
|
||||
</p>
|
||||
<link href="https://cdn.jsdelivr.net/npm/@tailwindcss/custom-forms@0.2.1/dist/custom-forms.css" rel="stylesheet"/>
|
||||
<div className="block">
|
||||
<div className="mt-2">
|
||||
{payloadBody && Object.keys(payloadBody.receipts).map(key =>
|
||||
<div key={key}>
|
||||
<label className="inline-flex items-center">
|
||||
<input onChange={setDose} type="radio" className="form-radio" name="radio" value={key} checked={parseInt(key) == selectedDose} />
|
||||
<span className="ml-2">Dose {key}</span>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} />}
|
||||
|
||||
<Card step={showDoseOption ? '4' : '3'} heading={t('index:addToWalletHeader')} content={
|
||||
<div className="space-y-5">
|
||||
{/* <p>
|
||||
{t('index:dataPrivacyDescription')}
|
||||
@ -401,17 +486,17 @@ function Form(): JSX.Element {
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-start">
|
||||
<button disabled={isDisabledAppleWallet || loading} id="download" type="submit" value='applewallet' name='action'
|
||||
<button disabled={isDisabledAppleWallet || saveLoading ||!payloadBody} id="download" type="submit" value='applewallet' name='action'
|
||||
className="focus:outline-none bg-green-600 py-2 px-3 text-white font-semibold rounded-md disabled:bg-gray-400">
|
||||
{t('index:addToWallet')}
|
||||
</button>
|
||||
|
||||
<button id="saveAsPhoto" type="button" disabled={loading} value='photo' name='action' onClick={saveAsPhoto}
|
||||
<button id="saveAsPhoto" type="button" disabled={saveLoading || !payloadBody} value='photo' name='action' onClick={saveAsPhoto}
|
||||
className="focus:outline-none bg-green-600 py-2 px-3 text-white font-semibold rounded-md disabled:bg-gray-400">
|
||||
{t('index:saveAsPhoto')}
|
||||
</button>
|
||||
|
||||
<div id="spin" className={loading ? undefined : "hidden"}>
|
||||
<div id="spin" className={saveLoading ? undefined : "hidden"}>
|
||||
<svg className="animate-spin h-5 w-5 ml-4" viewBox="0 0 24 24">
|
||||
<circle className="opacity-0" cx="12" cy="12" r="10" stroke="currentColor"
|
||||
strokeWidth="4"/>
|
||||
@ -420,7 +505,7 @@ function Form(): JSX.Element {
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
{errorMessages.map((message, i) =>
|
||||
{addErrorMessages.map((message, i) =>
|
||||
<Alert message={message} key={'error-' + i} type="error" />
|
||||
)}
|
||||
{/* {warningMessages.map((message, i) =>
|
||||
|
@ -15,6 +15,8 @@ ontarioHealth: Ontario Ministry of Health
|
||||
gotoOntarioHealth: Go to Ontario Ministry of Health
|
||||
downloadSignedPDF: and enter your information to display your official vaccination receipt. Press the Share Icon at the bottom, "Save As Files" to store it onto your iPhone.
|
||||
reminderNotToRepeat: If you have completed this step before, simply proceed to Step 2.
|
||||
formatChange: After the recent vaccination receipt formatting change, both doses are included in the same file. Please select which dose you which dose you want to save.
|
||||
saveMultiple: To save multiple receipts, please select the first one you want to save and click the Wallet or Photo button below, then change which dose is selected here and push the button again to generate another Wallet or Photo for another dose.
|
||||
pickColor: Pick a Color
|
||||
pickColorDescription: Pick a background color for your pass.
|
||||
colorWhite: white
|
||||
|
@ -81,11 +81,11 @@ export class PassData {
|
||||
return await response.arrayBuffer()
|
||||
}
|
||||
|
||||
static async generatePass(payloadBody: PayloadBody): Promise<Buffer> {
|
||||
static async generatePass(payloadBody: PayloadBody, numDose: number): Promise<Buffer> {
|
||||
|
||||
// Create Payload
|
||||
try {
|
||||
const payload: Payload = new Payload(payloadBody);
|
||||
const payload: Payload = new Payload(payloadBody, numDose);
|
||||
|
||||
payload.serialNumber = uuid4();
|
||||
|
||||
|
@ -4,6 +4,9 @@ import {COLORS} from "./colors";
|
||||
export class Receipt {
|
||||
constructor(public name: string, public vaccinationDate: string, public vaccineName: string, public dateOfBirth: string, public numDoses: number, public organization: string) {};
|
||||
}
|
||||
export interface HashTable<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
enum TextAlignment {
|
||||
right = 'PKTextAlignmentRight',
|
||||
@ -28,7 +31,7 @@ export interface PassDictionary {
|
||||
export interface PayloadBody {
|
||||
// color: COLORS;
|
||||
rawData: string;
|
||||
receipt: Receipt;
|
||||
receipts: HashTable<Receipt>;
|
||||
}
|
||||
|
||||
export class Payload {
|
||||
@ -43,12 +46,12 @@ export class Payload {
|
||||
serialNumber: string;
|
||||
generic: PassDictionary;
|
||||
|
||||
constructor(body: PayloadBody) {
|
||||
constructor(body: PayloadBody, numDose: number) {
|
||||
|
||||
// Get name and date of birth information
|
||||
const name = body.receipt.name;
|
||||
const dateOfBirth = body.receipt.dateOfBirth;
|
||||
const vaccineName = body.receipt.vaccineName;
|
||||
const name = body.receipts[numDose].name;
|
||||
const dateOfBirth = body.receipts[numDose].dateOfBirth;
|
||||
const vaccineName = body.receipts[numDose].vaccineName;
|
||||
let vaccineNameProper = vaccineName.charAt(0) + vaccineName.substr(1).toLowerCase();
|
||||
|
||||
if (vaccineName.includes('PFIZER'))
|
||||
@ -61,7 +64,7 @@ export class Payload {
|
||||
if (vaccineName.includes('ASTRAZENECA'))
|
||||
vaccineNameProper = 'AstraZeneca (Vaxzevria)'
|
||||
|
||||
let doseVaccine = "#" + String(body.receipt.numDoses) + ": " + vaccineNameProper;
|
||||
let doseVaccine = "#" + String(body.receipts[numDose].numDoses) + ": " + vaccineNameProper;
|
||||
|
||||
if (name == undefined) {
|
||||
throw new Error('nameMissing');
|
||||
@ -85,13 +88,13 @@ export class Payload {
|
||||
{
|
||||
key: "issuer",
|
||||
label: "Authorized Organization",
|
||||
value: body.receipt.organization
|
||||
value: body.receipts[numDose].organization
|
||||
},
|
||||
|
||||
{
|
||||
key: "dov",
|
||||
label: "Date",
|
||||
value: body.receipt.vaccinationDate,
|
||||
value: body.receipts[numDose].vaccinationDate,
|
||||
// textAlignment: TextAlignment.right
|
||||
}
|
||||
],
|
||||
@ -115,10 +118,10 @@ export class Payload {
|
||||
}
|
||||
|
||||
// Set Values
|
||||
this.receipt = body.receipt;
|
||||
this.receipt = body.receipts[numDose];
|
||||
this.rawData = body.rawData;
|
||||
|
||||
if (body.receipt.numDoses > 1 || body.receipt.vaccineName.toLowerCase().includes('janssen') || body.receipt.vaccineName.toLowerCase().includes('johnson') || body.receipt.vaccineName.toLowerCase().includes('j&j')) {
|
||||
if (body.receipts[numDose].numDoses > 1 || body.receipts[numDose].vaccineName.toLowerCase().includes('janssen') || body.receipts[numDose].vaccineName.toLowerCase().includes('johnson') || body.receipts[numDose].vaccineName.toLowerCase().includes('j&j')) {
|
||||
this.backgroundColor = COLORS.GREEN;
|
||||
} else {
|
||||
this.backgroundColor = COLORS.YELLOW;
|
||||
|
@ -35,11 +35,11 @@ export class Photo {
|
||||
|
||||
|
||||
|
||||
static async generatePass(payloadBody: PayloadBody): Promise<Blob> {
|
||||
static async generatePass(payloadBody: PayloadBody, numDose: number): Promise<Blob> {
|
||||
|
||||
// Create Payload
|
||||
try {
|
||||
const payload: Payload = new Payload(payloadBody);
|
||||
const payload: Payload = new Payload(payloadBody, numDose);
|
||||
|
||||
payload.serialNumber = uuid4();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {PayloadBody, Receipt} from "./payload";
|
||||
import {PayloadBody, Receipt, HashTable} from "./payload";
|
||||
import * as PdfJS from 'pdfjs-dist'
|
||||
import {COLORS} from "./colors";
|
||||
import { getCertificatesInfoFromPDF } from "@ninja-labs/verify-pdf"; // ES6
|
||||
@ -16,11 +16,11 @@ export async function getPayloadBodyFromFile(file: File, color: COLORS): Promise
|
||||
// Read file
|
||||
const fileBuffer = await file.arrayBuffer();
|
||||
|
||||
let receipt: Receipt;
|
||||
let receipts: HashTable<Receipt>;
|
||||
|
||||
switch (file.type) {
|
||||
case 'application/pdf':
|
||||
receipt = await loadPDF(fileBuffer)
|
||||
receipts = await loadPDF(fileBuffer)
|
||||
break
|
||||
default:
|
||||
throw Error('invalidFileType')
|
||||
@ -29,12 +29,12 @@ export async function getPayloadBodyFromFile(file: File, color: COLORS): Promise
|
||||
const rawData = ''; // unused at the moment, the original use was to store the QR code from issuer
|
||||
|
||||
return {
|
||||
receipt: receipt,
|
||||
receipts: receipts,
|
||||
rawData: rawData
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPDF(signedPdfBuffer : ArrayBuffer): Promise<any> {
|
||||
async function loadPDF(signedPdfBuffer : ArrayBuffer): Promise<HashTable<Receipt>> {
|
||||
|
||||
try {
|
||||
|
||||
@ -124,44 +124,47 @@ async function loadPDF(signedPdfBuffer : ArrayBuffer): Promise<any> {
|
||||
|
||||
}
|
||||
|
||||
async function getPdfDetails(fileBuffer: ArrayBuffer): Promise<Receipt> {
|
||||
async function getPdfDetails(fileBuffer: ArrayBuffer): Promise<HashTable<Receipt>> {
|
||||
|
||||
try {
|
||||
const typedArray = new Uint8Array(fileBuffer);
|
||||
let loadingTask = PdfJS.getDocument(typedArray);
|
||||
|
||||
const pdfDocument = await loadingTask.promise;
|
||||
// Load FIRST DUE TO NEW COVAXON FORMAT
|
||||
const pageNumber = 1;
|
||||
// Load all dose numbers
|
||||
const { numPages } = pdfDocument;
|
||||
const receiptObj = {};
|
||||
|
||||
const pdfPage = await pdfDocument.getPage(pageNumber);
|
||||
const content = await pdfPage.getTextContent();
|
||||
const numItems = content.items.length;
|
||||
let name, vaccinationDate, vaccineName, dateOfBirth, numDoses, organization;
|
||||
|
||||
for (let i = 0; i < numItems; i++) {
|
||||
let item = content.items[i] as TextItem;
|
||||
const value = item.str;
|
||||
if (value.includes('Name / Nom'))
|
||||
name = (content.items[i+1] as TextItem).str;
|
||||
if (value.includes('Date:')) {
|
||||
vaccinationDate = (content.items[i+1] as TextItem).str;
|
||||
vaccinationDate = vaccinationDate.split(',')[0];
|
||||
for (let pages = 1; pages <= numPages; pages++){
|
||||
const pdfPage = await pdfDocument.getPage(pages);
|
||||
const content = await pdfPage.getTextContent();
|
||||
const numItems = content.items.length;
|
||||
let name, vaccinationDate, vaccineName, dateOfBirth, numDoses, organization;
|
||||
|
||||
for (let i = 0; i < numItems; i++) {
|
||||
let item = content.items[i] as TextItem;
|
||||
const value = item.str;
|
||||
if (value.includes('Name / Nom'))
|
||||
name = (content.items[i+1] as TextItem).str;
|
||||
if (value.includes('Date:')) {
|
||||
vaccinationDate = (content.items[i+1] as TextItem).str;
|
||||
vaccinationDate = vaccinationDate.split(',')[0];
|
||||
}
|
||||
if (value.includes('Product name')) {
|
||||
vaccineName = (content.items[i+1] as TextItem).str;
|
||||
vaccineName = vaccineName.split(' ')[0];
|
||||
}
|
||||
if (value.includes('Date of birth'))
|
||||
dateOfBirth = (content.items[i+1] as TextItem).str;
|
||||
if (value.includes('Authorized organization'))
|
||||
organization = (content.items[i+1] as TextItem).str;
|
||||
if (value.includes('You have received'))
|
||||
numDoses = Number(value.split(' ')[3]);
|
||||
}
|
||||
if (value.includes('Product name')) {
|
||||
vaccineName = (content.items[i+1] as TextItem).str;
|
||||
vaccineName = vaccineName.split(' ')[0];
|
||||
}
|
||||
if (value.includes('Date of birth'))
|
||||
dateOfBirth = (content.items[i+1] as TextItem).str;
|
||||
if (value.includes('Authorized organization'))
|
||||
organization = (content.items[i+1] as TextItem).str;
|
||||
if (value.includes('You have received'))
|
||||
numDoses = Number(value.split(' ')[3]);
|
||||
receiptObj[numDoses] = new Receipt(name, vaccinationDate, vaccineName, dateOfBirth, numDoses, organization);
|
||||
}
|
||||
const receipt = new Receipt(name, vaccinationDate, vaccineName, dateOfBirth, numDoses, organization);
|
||||
|
||||
return Promise.resolve(receipt);
|
||||
return Promise.resolve(receiptObj);
|
||||
} catch (e) {
|
||||
Sentry.captureException(e);
|
||||
return Promise.reject(e);
|
||||
|
Loading…
x
Reference in New Issue
Block a user