0

I am developing a Certificate Management System where after all the processes have been done, the user may print a certificate.

I am struggling to implement such that upon clicking the print button, a new tab will open containing the ready to print HTML certificate so that the user will only CTRL + P to have the certificate printed.

How do i render my react certificate component in a new window? Such that i would only pass the props which are the data to be put into the certificate e.g., name, date etc.. like <Certificate name={john} />

I have tried implementing the npm react-new-window but it does not work with

<Button onclick={() => { 
<NewWindow>
  <CertificateComponent>
</NewWindow>
}}
>
PRINT BUTTON 
</Button>

I have looked into react portals but most use cases are for Modals, which is where my "PRINT" button is rendered.

Sorry for the bad english/explanation. Thank you!

A S
  • 13
  • 1
  • 8
  • 1
    Have you looked this link: https://stackoverflow.com/questions/47574490/open-a-component-in-new-window-on-a-click-in-react – Majid M. Jul 21 '21 at 06:45
  • Have you tried this solution? https://stackoverflow.com/a/64391469/4831770 – Munei Nengwenani Jul 21 '21 at 06:48
  • 1
    @MajidMohammadi Yes, but this question was asked 3 and a half years ago, i assume that there might be a newer or more efficient way to work around this problem. Thank you still! – A S Jul 21 '21 at 06:51

3 Answers3

2

New Solution based on CreatePortal

import React, { useEffect, useCallback, useMemo, useState } from "react";
import { render, createPortal } from "react-dom";

const App = () => {
  const [isOpen, setOpenState] = useState(false);
  const open = useCallback(() => setOpenState(true));
  const close = useCallback(() => setOpenState(false));

  return (
    <div>
      <h1>Portals in React</h1>
      <button onClick={open}>Open</button>
      <button onClick={close}>Close</button>
      {isOpen && (
        <NewWindow close={close}>
          Example <button onClick={close}>Close</button>
        </NewWindow>
      )}
    </div>
  );
};

const NewWindow = ({ children, close }) => {
  const newWindow = useMemo(() =>
    window.open(
      "about:blank",
      "newWin",
      `width=400,height=300,left=${window.screen.availWidth / 2 -
        200},top=${window.screen.availHeight / 2 - 150}`
    )
  );
  newWindow.onbeforeunload = () => {
    close();
  };
  useEffect(() => () => newWindow.close());
  return createPortal(children, newWindow.document.body);
};

render(<App />, document.getElementById("root"));
Bashid
  • 433
  • 5
  • 15
0

There can be multiple approaches for this.

Approach 1:

Create a new route and map the certificateComponent to it, make sure it doesn't have any authentication or any dependency to it.

Store the required data for certificateComponent either in session storage or local storage.

When the user clicks on print button, redirect the user to this new route using window.open("http://localhost:port/newroute").

In certificateComponent read the values stored in session/local storage and map it accordingly.

Approach 2:

Make the certificate component as an overlay which occupies the entire screen which shows up when the user click on print button. If any UI elements need to be hidden, you can do something as shown below:

printFn = function() {
    // show the certificate component 
    // hide the ui elements not required
    // window.print()
}
M4C4R
  • 356
  • 4
  • 13
0

This worked for me

const myWindow: any = window.open('','', 'height: 500;width:500');
ReactDOM.render(<Yourcomponent prop={propValue} /> , myWindow.document.body);

myWindow.document.close();
myWindow.focus();
myWindow.print();
myWindow.close();
Ahmed Ali
  • 342
  • 6
  • 16