Last active
November 15, 2021 21:44
-
-
Save 1forh/52c301a4f45fa10749e262e5b8dc5ca8 to your computer and use it in GitHub Desktop.
React hook that generates a PDF based on an array of images and some other things
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useState, createContext, useContext } from 'react'; | |
import jsPDF from 'jspdf'; | |
import toast from 'react-hot-toast'; | |
import toDataUrl from '../utilities/toDataUrl'; | |
import { logEvent } from '../utilities/ga'; | |
import useStorage from './useStorage'; | |
import { STORAGE_KEYS } from '../config'; | |
const CARD_WIDTH_DEFAULT = 66; | |
const CARD_HEIGHT_DEFAULT = 92; | |
const PDFContext = createContext(null); | |
export const usePDF = () => useContext(PDFContext); | |
export const PDFProvider = ({ children }) => { | |
const [padding, setPadding] = useState(false); | |
const [format, setFormat] = useState('letter'); | |
const [scale, setScale] = useState('100%'); | |
const { storage } = useStorage(); | |
const [cardWidth, setCardWidth] = useState(CARD_WIDTH_DEFAULT); | |
const [cardHeight, setCardHeight] = useState(CARD_HEIGHT_DEFAULT); | |
const [rows, setRows] = useState(2); | |
const [columns, setColumns] = useState(3); | |
const [downloadStatus, setDownloadStatus] = useState(null); | |
const getPaddingSettingFromStorage = async () => { | |
const r = await storage.getItem(STORAGE_KEYS.PDF_PADDING); | |
if (r) { | |
setPadding(r); | |
} | |
}; | |
const savePaddingSettingToStorage = async (input) => { | |
await storage.setItem(STORAGE_KEYS.PDF_PADDING, input); | |
}; | |
const getFormatSettingFromStorage = async () => { | |
const r = await storage.getItem(STORAGE_KEYS.PDF_FORMAT); | |
if (r) { | |
setFormat(r); | |
} | |
}; | |
const saveFormatSettingToStorage = async (input) => { | |
await storage.setItem(STORAGE_KEYS.PDF_FORMAT, input); | |
}; | |
const getScaleSettingFromStorage = async () => { | |
const r = await storage.getItem(STORAGE_KEYS.PDF_SCALE); | |
if (r) { | |
setScale(r); | |
} | |
}; | |
const saveScaleSettingToStorage = async (input) => { | |
await storage.setItem(STORAGE_KEYS.PDF_SCALE, input); | |
}; | |
useEffect(() => { | |
if (!storage) return; | |
getPaddingSettingFromStorage(); | |
getFormatSettingFromStorage(); | |
getScaleSettingFromStorage(); | |
}, [storage]); | |
useEffect(() => { | |
if (!storage) return; | |
savePaddingSettingToStorage(padding); | |
}, [storage, padding]); | |
useEffect(() => { | |
if (!storage) return; | |
saveFormatSettingToStorage(format); | |
}, [storage, format]); | |
useEffect(() => { | |
if (!storage) return; | |
if (scale === '100%') { | |
setCardWidth(CARD_WIDTH_DEFAULT); | |
setCardHeight(CARD_HEIGHT_DEFAULT); | |
if (padding) { | |
setRows(2); | |
setColumns(3); | |
} else { | |
setRows(3); | |
setColumns(3); | |
} | |
} else if (scale === '110%') { | |
setCardWidth(CARD_WIDTH_DEFAULT * 1.1); | |
setCardHeight(CARD_HEIGHT_DEFAULT * 1.1); | |
setRows(2); | |
setColumns(2); | |
} else if (scale === '90%') { | |
setCardWidth(CARD_WIDTH_DEFAULT * 0.9); | |
setCardHeight(CARD_HEIGHT_DEFAULT * 0.9); | |
setRows(3); | |
setColumns(3); | |
} | |
saveScaleSettingToStorage(scale); | |
}, [storage, scale, padding]); | |
const downloadPDF = async (cards) => { | |
setDownloadStatus('pending'); | |
logEvent({ | |
action: 'startDownloadPDF', | |
params: { | |
scale, | |
padding, | |
format, | |
}, | |
}); | |
console.log(padding, format, scale); | |
try { | |
const images = cards.map((card) => ({ quantity: card.quantity, image: card?.details?.image_uris?.normal })); | |
const imagesToPrint = []; | |
for (const image of images) { | |
for (let index = 0; index < image.quantity; index++) { | |
imagesToPrint.push(image.image); | |
} | |
} | |
const pdf = new jsPDF({ | |
unit: 'mm', | |
format: format.toLowerCase(), | |
}); | |
const outerPadding = padding ? 6 : 0; | |
let u = 0; | |
for (let p = 0; p < imagesToPrint.length / 9; p++) { | |
if (p > 0) pdf.addPage(); | |
for (let j = 0; j < rows; j++) { | |
for (let i = 0; i < columns; i++) { | |
if (u < imagesToPrint.length) { | |
const image = await toDataUrl(imagesToPrint[u]); | |
const x = i * cardWidth + outerPadding; | |
const y = j * cardHeight + outerPadding; | |
pdf.addImage(image, 'PNG', x, y, cardWidth, cardHeight); | |
u++; | |
} | |
} | |
} | |
} | |
await pdf.save('mtg-proxies.pdf', { | |
returnPromise: true, | |
}); | |
logEvent({ | |
action: 'successDownloadPDF', | |
params: { | |
scale, | |
padding, | |
format, | |
}, | |
}); | |
setDownloadStatus('success'); | |
} catch (error) { | |
toast.error(`Unexpected error. Try again later.`); | |
logEvent({ | |
action: 'errorDownloadPDF', | |
params: { | |
error, | |
}, | |
}); | |
setDownloadStatus('error'); | |
throw error; | |
} | |
}; | |
return ( | |
<PDFContext.Provider | |
value={{ | |
downloadPDF, | |
setPadding, | |
padding, | |
format, | |
setFormat, | |
scale, | |
setScale, | |
downloadStatus, | |
setDownloadStatus, | |
}} | |
> | |
{children} | |
</PDFContext.Provider> | |
); | |
}; | |
export default usePDF; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment