Skip to content

Instantly share code, notes, and snippets.

@1forh
Last active November 15, 2021 21:44
Show Gist options
  • Save 1forh/52c301a4f45fa10749e262e5b8dc5ca8 to your computer and use it in GitHub Desktop.
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
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