292 lines
9 KiB
TypeScript
292 lines
9 KiB
TypeScript
import { Box, Button, Checkbox, DialogActions, DialogContent, DialogTitle, Typography } from "@mui/material";
|
|
// import MaterialTable from "material-table";
|
|
import React, { useEffect, useState } from "react";
|
|
import ResponsiveDialog from "./ResponsiveDialog";
|
|
// import { getTableIcons } from "./ResponsiveTable";
|
|
import { Document, Image, Page, PDFViewer, StyleSheet, Text, View } from "@react-pdf/renderer";
|
|
import { useMobile } from "hooks";
|
|
import { cloneDeep } from "lodash";
|
|
import ResponsiveTable from "./ResponsiveTable";
|
|
|
|
export interface QrCodeKey {
|
|
name: string;
|
|
key: string;
|
|
}
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
close: () => void;
|
|
keyList: QrCodeKey[];
|
|
requiredUrlAffix: string;
|
|
url?: string;
|
|
}
|
|
|
|
export default function(props: Props) {
|
|
const { open, close, url, requiredUrlAffix, keyList } = props;
|
|
const [selectedKeys, setSelectedKeys] = useState<QrCodeKey[]>([]);
|
|
const [selectedPageRows, setSelectedPageRows] = useState<Map<number, number[]>>(new Map())//key is the page value is an array of row indexes for that page
|
|
const [tablePage, setTablePage] = useState(0)
|
|
const [pageSize, setPageSize] = useState(10)
|
|
const isMobile = useMobile();
|
|
const [displayedRows, setDisplayedRows] = useState<QrCodeKey[]>([]);
|
|
const codesPerPage = 4;
|
|
const pdfStyle = StyleSheet.create({
|
|
viewerDesktop: {
|
|
height: 500 * 1.44,
|
|
width: 500
|
|
},
|
|
viewerMobile: {
|
|
height: 500,
|
|
width: "100%"
|
|
},
|
|
page: {
|
|
padding: "3%",
|
|
textAlign: "center",
|
|
fontFamily: "Helvetica-Bold",
|
|
fontSize: 30
|
|
},
|
|
quadrant: {
|
|
width: "50%",
|
|
textAlign: "center",
|
|
//margin: 10,
|
|
borderRadius: 20
|
|
},
|
|
code: {
|
|
flexDirection: "column",
|
|
border: "2px dotted black",
|
|
margin: 10,
|
|
borderRadius: 20
|
|
},
|
|
image: {
|
|
padding: 20,
|
|
paddingBottom: 0
|
|
//height: "65%"
|
|
//border: "1px solid black", //used just to see a representation of where the view is
|
|
},
|
|
text: {
|
|
marginTop: 30,
|
|
marginBottom: 30,
|
|
textAlign: "center",
|
|
justifyContent: "center"
|
|
//border: "1px solid black", //used just to see a representation of where the view is
|
|
}
|
|
});
|
|
|
|
useEffect(()=>{
|
|
let clone: QrCodeKey[] = cloneDeep(keyList)
|
|
let rows = clone.splice(tablePage * pageSize, pageSize)
|
|
setDisplayedRows(rows)
|
|
},[keyList, tablePage, pageSize])
|
|
|
|
const handleRowsPerPageChange = (event: any) => {
|
|
const newRowsPerPage = parseInt(event.target.value, 10); // Get selected value
|
|
setPageSize(newRowsPerPage);
|
|
setTablePage(0)
|
|
//clear the selected rows
|
|
setSelectedPageRows(new Map())
|
|
//clear the selected keys
|
|
setSelectedKeys([])
|
|
}
|
|
|
|
const rowSelected = (row: QrCodeKey, index: number, checked: boolean) => {
|
|
//when a row is selected add it to the map for the page
|
|
let selected = cloneDeep(selectedKeys)
|
|
let pageMap = cloneDeep(selectedPageRows)
|
|
let pageSelect = pageMap.get(tablePage)
|
|
if(checked){ //add the page/index to the map
|
|
if(pageSelect){
|
|
pageSelect.push(index)
|
|
}else{
|
|
pageMap.set(tablePage, [index])
|
|
}
|
|
//handle the row data to add it to a list of keys that are selected
|
|
selected.push(row)
|
|
}else{ //remove the page/index from the map
|
|
if(pageSelect){
|
|
pageSelect.splice(pageSelect.indexOf(index), 1)
|
|
}
|
|
//remove the selected object from the array
|
|
selected.forEach((codeKey, index) => {
|
|
if(row.key === codeKey.key){
|
|
selected.splice(index, 1)
|
|
}
|
|
})
|
|
}
|
|
setSelectedKeys(selected)
|
|
setSelectedPageRows(pageMap)
|
|
}
|
|
|
|
const selectionTable = () => {
|
|
return (
|
|
<React.Fragment>
|
|
<ResponsiveTable
|
|
columns={[
|
|
{
|
|
cellStyle: {
|
|
padding: 2
|
|
},
|
|
title: "Name",
|
|
render: (row) => <Box>{row.name}</Box>
|
|
}
|
|
]}
|
|
rowSelect={rowSelected}
|
|
selectedRows={selectedPageRows.get(tablePage)}
|
|
rows={displayedRows}
|
|
page={tablePage}
|
|
pageSize={pageSize}
|
|
total={keyList.length}
|
|
setPage={(page) => {setTablePage(page)}}
|
|
handleRowsPerPageChange={handleRowsPerPageChange}
|
|
loadMore={() => {
|
|
let clone: QrCodeKey[] = cloneDeep(keyList)
|
|
let current = cloneDeep(displayedRows)
|
|
let newRows = clone.splice(current.length, pageSize)
|
|
setDisplayedRows(current.concat(newRows))
|
|
}}
|
|
renderMobile={(row, index) => {
|
|
return (
|
|
<Box display="flex">
|
|
<Checkbox
|
|
onChange={(e, checked) => {
|
|
rowSelected(row, index, checked)
|
|
}}
|
|
/>
|
|
<Typography>
|
|
{row.name}
|
|
</Typography>
|
|
</Box>
|
|
)
|
|
}}
|
|
/>
|
|
</React.Fragment>
|
|
);
|
|
};
|
|
|
|
const generatedCodes = () => {
|
|
let numPages = Math.ceil(selectedKeys.length / codesPerPage);
|
|
let keys = cloneDeep(selectedKeys);
|
|
let pages: JSX.Element[] = [];
|
|
|
|
let location = url ?? document.URL; //document.URL will append the ending slash to the url string
|
|
if (!location.includes(requiredUrlAffix)) {
|
|
location = location + requiredUrlAffix;
|
|
}
|
|
|
|
for (let i = 0; i < numPages; i++) {
|
|
let pageKeys = keys.splice(0, codesPerPage);
|
|
pages.push(
|
|
<React.Fragment key={i}>
|
|
<View style={{ height: "50%", flexDirection: "row" }}>
|
|
{pageKeys[0] && (
|
|
<View style={pdfStyle.quadrant}>
|
|
<View style={pdfStyle.code}>
|
|
<View style={pdfStyle.image}>
|
|
<Image
|
|
src={
|
|
"https://api.qrserver.com/v1/create-qr-code/?data=" +
|
|
location +
|
|
"/" +
|
|
pageKeys[0].key +
|
|
"&size=100x100"
|
|
}
|
|
/>
|
|
</View>
|
|
<View style={pdfStyle.text}>
|
|
<Text>{pageKeys[0].name}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
)}
|
|
{pageKeys[1] && (
|
|
<View style={pdfStyle.quadrant}>
|
|
<View style={pdfStyle.code}>
|
|
<View style={pdfStyle.image}>
|
|
<Image
|
|
src={
|
|
"https://api.qrserver.com/v1/create-qr-code/?data=" +
|
|
location +
|
|
"/" +
|
|
pageKeys[1].key +
|
|
"&size=100x100"
|
|
}
|
|
/>
|
|
</View>
|
|
<View style={pdfStyle.text}>
|
|
<Text>{pageKeys[1].name}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
)}
|
|
</View>
|
|
<View style={{ height: "50%", flexDirection: "row" }}>
|
|
{pageKeys[2] && (
|
|
<View style={pdfStyle.quadrant}>
|
|
<View style={pdfStyle.code}>
|
|
<View style={pdfStyle.image}>
|
|
<Image
|
|
src={
|
|
"https://api.qrserver.com/v1/create-qr-code/?data=" +
|
|
location +
|
|
"/" +
|
|
pageKeys[2].key +
|
|
"&size=100x100"
|
|
}
|
|
/>
|
|
</View>
|
|
<View style={pdfStyle.text}>
|
|
<Text>{pageKeys[2].name}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
)}
|
|
{pageKeys[3] && (
|
|
<View style={pdfStyle.quadrant}>
|
|
<View style={pdfStyle.code}>
|
|
<View style={pdfStyle.image}>
|
|
<Image
|
|
src={
|
|
"https://api.qrserver.com/v1/create-qr-code/?data=" +
|
|
location +
|
|
"/" +
|
|
pageKeys[3].key +
|
|
"&size=100x100"
|
|
}
|
|
/>
|
|
</View>
|
|
<View style={pdfStyle.text}>
|
|
<Text>{pageKeys[3].name}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
)}
|
|
</View>
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Document>
|
|
<Page style={pdfStyle.page}>{pages}</Page>
|
|
</Document>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<ResponsiveDialog open={open} onClose={close}>
|
|
<DialogTitle>Generate QR Codes</DialogTitle>
|
|
<DialogContent>
|
|
{selectionTable()}
|
|
<Box marginTop={5}>
|
|
<PDFViewer style={isMobile ? pdfStyle.viewerMobile : pdfStyle.viewerDesktop}>
|
|
{generatedCodes()}
|
|
</PDFViewer>
|
|
</Box>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button variant="contained" color="primary" onClick={close}>
|
|
Close
|
|
</Button>
|
|
</DialogActions>
|
|
</ResponsiveDialog>
|
|
);
|
|
}
|