Converting React to PDF (Long PDF) with pagination

60 Views Asked by At

I am trying to generate a long report in react. I used different libraries but there are some limitations like no proper header footer or not able to create layout I am trying to create. I am able to generate report with I am having some issues.

  1. I am getting first page duplicate
  2. Its not responsive for small screen it crop pages
const handleDownloadPdf = async (id) => {
    let element = document.getElementById(id);
    const ft = document.getElementById("report-footer");
    ft.style.display = "flex";

    const pg = document.getElementById("pagination");
    pg.style.display = "none";
    element.style.boxShadow = "none";
    element.classList.remove("shadow");

    const pdf = new jsPDF();

    const loadingIndicator = document.createElement("div");
    loadingIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
    loadingIndicator.style.color = "white";
    loadingIndicator.innerHTML = "Generating Report...";
    loadingIndicator.style.position = "fixed";
    loadingIndicator.style.top = "0";
    loadingIndicator.style.width = "100vw";
    loadingIndicator.style.height = "100vh";
    loadingIndicator.style.left = "0";
    loadingIndicator.style.display = "flex";
    loadingIndicator.style.justifyContent = "center";
    loadingIndicator.style.alignItems = "center";
    document.body.appendChild(loadingIndicator);

    // Async function to add a new page
    const addPageAsync = async (pdf) => {
      return new Promise((resolve) => {
        setTimeout(() => {
          pdf.addPage();
          resolve();
        }, 0);
      });
    };

    // Iterate from 0 to totalPages - 1
    for (let i = 0; i <= totalPages; i++) {
      let element = document.getElementById(id);
      console.log(element);
      let pageCount = pdf.internal.getNumberOfPages(); // Get total number of pages

      if (pageCount > 0 && i === page) continue;
      // Capture a section of the element based on the current offset
      const canvas = await html2canvas(element, {
        useCORS: true,
        proxy: "",
        scrollY: i * pdf.internal.pageSize.getHeight(),
      });

      const data = canvas.toDataURL("image/png");
      const imgProperties = pdf.getImageProperties(data);
      console.log(i);

      const pdfWidth = pdf.internal.pageSize.getWidth();
      const pdfHeight = (imgProperties.height * pdfWidth) / imgProperties.width;

      // Add the captured section to the PDF
      pdf.addImage(data, "PNG", 0, 0, pdfWidth, pdfHeight);

      // If there are more sections to capture, add a new page
      if (i < totalPages) {
        await addPageAsync(pdf).then(() => {
          setPage(i);
        });
      }
    }

    ft.style.display = "none";
    pg.style.display = "block";
    loadingIndicator.remove();

    // if (pageCount > 1) pdf.deletePage(0);

    console.log("PDF");
    console.log(pdf);
    // Save the PDF

    pdf.save(`allottee-report.pdf`);

    // Reset styles
    element.style.boxShadow = `rgba(17, 17, 26, 0.1) 0px 4px 16px, rgba(17, 17, 26, 0.05) 0px 8px 32px`;
    element.classList.add("shadow");
  };
<div id="report" style={{ padding: "5px" }}>
        <Box
          sx={{
            background: "url(/assets/report-bg.svg) no-repeat",
            minHeight: "300px",
          }}
        >
          <Box display={"flex"} pt="3rem" alignItems={"start"}>
            <Box flex={1}>
              <img src="/assets/report-logo.svg" alt="Logo" />
            </Box>
            <Box>
              <Box
                border={"1px solid rgba(97, 89, 252, 1)"}
                borderRadius={"5px"}
              >
                <Box
                  display={"flex"}
                  flexWrap={"wrap"}
                  alignItems={"center"}
                  borderBottom={"1px solid rgba(97,89,252,1)"}
                  p={"10px"}
                >
                  <Box flex={1}>
                    <Typography fontWeight={"bold"}>Building Name: </Typography>
                  </Box>
                  <Box ml={"10px"}>
                    <Typography>
                      {paginatedData[0]?.building_information_id?.building_name}{" "}
                    </Typography>
                  </Box>
                </Box>{" "}
                <Box
                  display={"flex"}
                  flexWrap={"wrap"}
                  alignItems={"center"}
                  borderBottom={"1px solid rgba(97,89,252,1)"}
                  p={"10px"}
                >
                  <Box flex={1}>
                    <Typography fontWeight={"bold"}>Address: </Typography>
                  </Box>
                  <Box ml={"10px"}>
                    <Typography>
                      {paginatedData[0]?.building_information_id?.address_line}
                    </Typography>
                  </Box>
                </Box>{" "}
                <Box
                  display={"flex"}
                  flexWrap={"wrap"}
                  alignItems={"center"}
                  p={"10px"}
                >
                  <Box flex={1}>
                    <Typography fontWeight={"bold"}>City: </Typography>
                  </Box>
                  <Box ml={"10px"}>
                    <Typography>
                      {
                        paginatedData[0]?.building_information_id
                          ?.area_information?.thana_details?.district_details
                          ?.name
                      }
                    </Typography>
                  </Box>
                </Box>
              </Box>
            </Box>
          </Box>
        </Box>
        <Typography fontSize={"32px"}>Allottee List</Typography>
        <Box>
          <TableContainer sx={{ width: "100%" }}>
            <Table sx={{ width: "100%" }}>
              <TableHead sx={{ bgcolor: "rgba(16, 36, 62, 1)", width: "100%" }}>
                <TableRow sx={{ width: "100%" }}>
                  <TableCell sx={{ color: "white" }}>Sl.</TableCell>
                  <TableCell sx={{ color: "white" }}>Name</TableCell>
                  <TableCell sx={{ color: "white" }}>Father Name</TableCell>
                  <TableCell sx={{ color: "white" }}>Flat</TableCell>
                  <TableCell sx={{ color: "white" }}>Family Members</TableCell>
                  <TableCell sx={{ color: "white" }}>Phone</TableCell>
                  <TableCell sx={{ color: "white" }}>Living Status</TableCell>
                </TableRow>
              </TableHead>
              <TableBody>
                {paginatedData?.map((a, i) => (
                  <TableRow
                    key={a?.id}
                    sx={{
                      "&:nth-of-type(even)": {
                        backgroundColor: "rgba(0, 212, 255, 0.1)",
                      },
                    }}
                  >
                    <TableCell>{i + 1 + page * rowsPerPage}</TableCell>
                    <TableCell>{a?.first_name}</TableCell>
                    <TableCell>{a?.father_name}</TableCell>
                    <TableCell>{a?.flat_information?.flat_name}</TableCell>
                    <TableCell>{a?.family_member_no}</TableCell>
                    <TableCell>{a?.phone}</TableCell>
                    <TableCell>{a?.living_building}</TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </TableContainer>
          <TablePagination
            rowsPerPageOptions={[5, 10, 15, 20, 25, 30, 35]}
            component="div"
            id="pagination"
            sx={{
              width: "100%",
              "& .MuiToolbar-root": {
                alignItems: "baseline!important",
              },
            }}
            count={allottee.length}
            rowsPerPage={rowsPerPage}
            page={page}
            onPageChange={handleChangePage}
            onRowsPerPageChange={handleChangeRowsPerPage}
          />
          <Box
            bgcolor={"primary.main"}
            display={"none"}
            p={"5px"}
            height={"52px"}
            alignItems={"center"}
            color={"white"}
            id="report-footer"
            flex={"wrap"}
            justifyContent={"space-between"}
          >
            <Box>
              <Typography>
                Page {page + 1} of {totalPages}
              </Typography>
            </Box>
            <Box>
              <Typography> &copy; Copyright by Smartnir </Typography>
            </Box>
            <Box>
              <Typography>
                Generated Date: {new Date().toLocaleDateString()}
              </Typography>
            </Box>
          </Box>
        </Box>
      </div>

I am trying to generate a long report in react. and I want to generate fully responsive proper report

0

There are 0 best solutions below