Skip to content

Instantly share code, notes, and snippets.

@jordanhudgens
Created August 10, 2021 17:28
Show Gist options
  • Save jordanhudgens/26e444b09f9a4066cbee549796aa50c1 to your computer and use it in GitHub Desktop.
Save jordanhudgens/26e444b09f9a4066cbee549796aa50c1 to your computer and use it in GitHub Desktop.
import * as React from "react";
import {
DTCheckbox,
DTTextField,
DTToggle,
Heading,
Pane,
PaneAccordianContainer,
PaneAccordionItem,
PaneContentContainer,
} from "@dashtrack/web-utility";
import { SketchPicker, ColorResult } from "react-color";
import { IPageCategory, MediaRecordType } from "@dashtrack/types";
import { formatErrors } from "@dashtrack/text-utility";
import QRCode from "qrcode.react";
import AppStateContext from "../../contexts/AppStateContext";
import PageManagerContext from "../../contexts/PageManagerContext";
import NotificationContext from "../../contexts/NotificationContext";
import { colorPrimary, paneTheme } from "../../../utils/colors";
import { orgApi } from "../../../utils/api";
import CurrentUserContext from "../../contexts/CurrentUserContext";
import MediaManager from "../organizations/media-records/MediaManager";
interface IQrCodePane {
isOpen: boolean;
handleClose: () => void;
pageCategory: IPageCategory;
}
export default function QrCodePane({
isOpen,
handleClose,
pageCategory,
}: IQrCodePane) {
const qrRef = React.useRef();
// Attempt this fix:
// https://github.com/zpao/qrcode.react/issues/143
const { organizationLogo } = React.useContext(CurrentUserContext);
const { paneWidth } = React.useContext(AppStateContext);
const [url, setUrl] = React.useState(undefined);
const { handlePageCategoryFormSubmission } =
React.useContext(PageManagerContext);
const { showErrorNotification } = React.useContext(NotificationContext);
const [isUpdatingQrDestination, setIsUpdatingQrDestination] =
React.useState(false);
const [embedMedia, setEmbedMedia] = React.useState(false);
const [imageSize, setImageSize] = React.useState("1000");
const [qrCode, setQrCode] = React.useState(undefined);
const [fgColor, setFgColor] = React.useState("#000000");
const [bgColor, setBgColor] = React.useState("#FFFFFF");
const [levelType, setLevelType] = React.useState<"L" | "M" | "Q" | "H">("L");
const [includeMargin, setIncludeMargin] = React.useState(true);
const [mediaRecordsToAssign, setMediaRecordsToAssign] = React.useState<
MediaRecordType[]
>([]);
React.useEffect(() => {
if (pageCategory?.qr_code_url) setUrl(pageCategory.qr_code_url);
}, [pageCategory, pageCategory?.qr_code_url]);
const updateQrDestination = (updatedQrDestination: any) => {
setIsUpdatingQrDestination(true);
const params = {
page_category: {
qr_destination: updatedQrDestination,
},
};
orgApi
.patch(`page_categories/${pageCategory?.token}`, params)
.then(
(response: {
data: { page_category: IPageCategory; errors?: any };
}) => {
const { page_category, errors } = response.data;
setIsUpdatingQrDestination(false);
if (page_category) {
handlePageCategoryFormSubmission(page_category);
} else if (errors) {
showErrorNotification({
title: formatErrors(errors),
});
} else {
showErrorNotification({
title: "Error updating QR code URL",
});
}
}
)
.catch((_error) => {
setIsUpdatingQrDestination(false);
showErrorNotification({
title: "Error updating QR code URL",
});
});
};
const downloadQRCode = () => {
// @ts-ignore
let canvas = qrRef.current.querySelector("canvas");
let image = canvas.toDataURL("image/png");
let anchor = document.createElement("a");
anchor.href = image;
anchor.download = `${pageCategory.name}-qr-code.png`;
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
};
const handleBgColorChange = (color: ColorResult) => {
const rgbaValue = `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.rgb.a})`;
setBgColor(rgbaValue);
};
const handleFgColorChange = (color: ColorResult) => {
const rgbaValue = `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.rgb.a})`;
console.log("UPDATD FG", rgbaValue);
setFgColor(rgbaValue);
};
const qrCodeRenderer = (
<div
className="qr-code-form-container"
style={{ margin: "5px 0px 21px 0px" }}
>
<QRCode
id="qrCodeElToRender"
size={470}
value={url}
bgColor={bgColor}
fgColor={fgColor}
includeMargin={includeMargin}
level={levelType}
imageSettings={
embedMedia
? {
src: organizationLogo,
excavate: true,
}
: undefined
}
/>
<div
style={{
visibility: "hidden",
position: "absolute",
overflow: "hidden",
width: "0px",
height: "0px",
}}
ref={qrRef}
>
<QRCode
id="qrCodeElToDownload"
size={parseInt(imageSize)}
value={url}
bgColor={bgColor}
fgColor={fgColor}
includeMargin={includeMargin}
level={levelType}
imageSettings={
embedMedia
? {
// src: organizationLogo,
src: "https://static.zpao.com/favicon.png",
excavate: true,
x: null,
y: null,
width: 100,
height: 100,
}
: undefined
}
/>
</div>
</div>
);
const destinationAccordion = (
<PaneAccordionItem showTopBorder label="URL destination">
<DTTextField
value={url}
name="URL"
setValue={setUrl}
handleSubmit={updateQrDestination}
isSaving={isUpdatingQrDestination}
clickToEdit
/>
</PaneAccordionItem>
);
const layoutAccordion = (
<PaneAccordionItem showTopBorder label="Layout">
<DTTextField
value={imageSize}
name="Size in pixels"
setValue={setImageSize}
handleSubmit={() => console.log("Updated size")}
isSaving={false}
clickToEdit
/>
<DTToggle
value={includeMargin}
onChange={setIncludeMargin}
label="Include margin?"
/>
<div className="flex-space-between">
<Heading size="sm" color={colorPrimary} fontWeight={700}>
Design type
</Heading>
<DTCheckbox
checked={levelType === "L"}
onChange={() => setLevelType("L")}
label="L"
/>
<DTCheckbox
checked={levelType === "M"}
onChange={() => setLevelType("M")}
label="M"
/>
<DTCheckbox
checked={levelType === "H"}
onChange={() => setLevelType("H")}
label="H"
/>
<DTCheckbox
checked={levelType === "Q"}
onChange={() => setLevelType("Q")}
label="Q"
/>
</div>
</PaneAccordionItem>
);
const bgColorAccordion = (
<PaneAccordionItem showTopBorder label="Colors">
<div className="grid-2">
<div className="grid-1" style={{ alignItems: "center" }}>
<Heading size="sm" color={colorPrimary} fontWeight={700}>
Background
</Heading>
<SketchPicker
color={bgColor}
onChangeComplete={handleBgColorChange}
/>
</div>
<div className="grid-1" style={{ alignItems: "center" }}>
<Heading size="sm" color={colorPrimary} fontWeight={700}>
Foreground
</Heading>
<SketchPicker
color={fgColor}
onChangeComplete={handleFgColorChange}
/>
</div>
</div>
</PaneAccordionItem>
);
const mediaAccordionElement = (
<PaneAccordionItem label="Media" showTopBorder showBottomBorder>
<DTToggle
value={embedMedia}
onChange={setEmbedMedia}
label="Embed media?"
/>
{embedMedia && (
<MediaManager
mediaRecordsToAssign={mediaRecordsToAssign}
setMediaRecordsToAssign={setMediaRecordsToAssign}
resourceData={{
resource_name: "QrCode",
resource_id: qrCode?.id,
}}
/>
)}
</PaneAccordionItem>
);
return (
<Pane
isOpen={isOpen}
handleClose={handleClose}
staticTitle="QR Generator"
paneWidth={paneWidth}
paneType="CONTENT"
theme={paneTheme}
actions={[
<a className="font-bold primary" onClick={downloadQRCode}>
Download
</a>,
]}
>
<PaneContentContainer>{qrCodeRenderer}</PaneContentContainer>
<PaneAccordianContainer>
{bgColorAccordion}
{destinationAccordion}
{layoutAccordion}
{mediaAccordionElement}
</PaneAccordianContainer>
</Pane>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment