Instructor: In app.js, on the profile page, we can add a file and put component that accepts images, which is the easiest way to add an image upload to a PWA. Let's make the changeImage function. For now, we'll just have a bit of state called image, which we'll start as null.
We'll make an object URL from the inputs file that was uploaded. That will allow us to display it directly as a user's profile image. When we build and start that in a browser, we can go to the profile page and upload a new image to be displayed as the profile image.
When the PWA is installed on a mobile device, that will also allow the user to upload from the camera roll. If we want it to default to the camera instead of to photos, we can add a capture prop to the file input. Since this is for a user profile image, we can even specify that we want to default to the front-facing camera and specify user as the capture prop.
That's the easiest way to get an image upload into our app. To interact more directly with the camera, first, we have to check that the browser supports the camera, by checking that media devices is in navigator. Then we can change the file upload to just a button, and make a new onClick function.
Let's make a new onClick function called startChangeImage. In that function, we'll set some state to turn on the camera, and when that state gets set, we can render a new video component. That's where we'll show the live camera feed.
When that video mounts, we need to save the ref. We'll also immediately ask for access to the user's camera. On navigator.media-devices, call that getUserMedia function, and tell it that we want video. Then we can set the source of a new video tag to the stream that's coming from the user's media device.
This will show a popup which will ask for permission to access the camera. Make sure you only do this step when you're really ready to show the video feed, or else the user will just close your app.
Now, we can display a button that will actually take an image. To get the image out of the video stream, we'll also need a blank canvas element. Let's put an invisible one here as well, and save the ref.
Now, in the takeImageOnClick function, first, we'll set the height and the width of the canvas to the current video size. Then we can draw the image into the canvas directly from the video. Next, we'll tell the video to stop recording, and that will shut the user's camera off.
Finally, we can set the image in our state to the canvas-context-image as a data URL, and turn off the video in our app by turning off the enableCamera bit and state. Now, let's build that and serve it to test it out.
In a browser, we can click to toggle the camera, and we see a video feed. Then, when we click to take a picture, the picture is rendered to the canvas, and transferred to our state, and shown on the screen.
The same process works for mobile devices as well, but it will only work over HTTPS. If we just serve this on our local computer over a local network, then it will never ask for camera access. Keep that in mind during development.