Adding Images To Users
Reading
Adding Images To Users
When adding a user account, we can allow the upload of an avatar/profile image.
Remove the "Must be logged in" restriction in the UploadsController
Remove the line
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
from the UploadsController
.
Of course, this means anyone who wishes to can upload content and store it on our Cloudinary. For now, this is ok. However, before deploying this to the public, we should increase the security of this code.
Adding the photo URL to the User model
Now we can update the User.cs
model to store a URL to the uploaded image.
public string PhotoURL { get; set; }
dotnet ef migrations add AddPhotoURLToUser
dotnet ef database update
Update our types.ts
Add photoURL
to our types
export type NewUserType = {fullName: stringemail: stringpassword: stringphotoURL: string}export type LoginUserType = {email: stringpassword: stringphotoURL: string}export type LoginSuccess = {token: stringuser: {id: numberfullName: stringemail: stringphotoURL: string}}
Clean up any warnings/errors this causes.
Updating the SignUp page
Then we will import this component on our SignUp.tsx
page:
import { useDropzone } from 'react-dropzone'
Add the use of dropzone:
const { getRootProps, getInputProps, isDragActive } = useDropzone({onDrop: onDropFile,})
We'll add a state to track if we are uploading:
const [isUploading, setIsUploading] = useState(false)
Also copy over the uploadFile
code from NewRestaurant.tsx
- Copying the code
is ok for now. We can clean this up later.
Also add a mutation:
const uploadFileMutation = useMutation(uploadFile, {onSuccess: function (apiResponse: UploadResponse) {const url = apiResponse.urlsetNewUser({ ...newUser, photoURL: url })},onError: function (error: string) {setErrorMessage(error)},onSettled: function () {setIsUploading(false)},})
The dropzone component is expecting a method to call when a file is dropped onto a visible target in the UI. Let's add the method for that:
async function onDropFile(acceptedFiles: File[]) {// Do something with the filesconst fileToUpload = acceptedFiles[0]setIsUploading(true)uploadFileMutation.mutate(fileToUpload)}
Then create a variable to hold the drop zone message:
let dropZoneMessage = 'Drag a picture of the user here to upload!'if (isUploading) {dropZoneMessage = 'Uploading...'}if (isDragActive) {dropZoneMessage = 'Drop the files here ...'}
Then we can add an interface for showing a drop target for the photo upload.
<div className="file-drop-zone"><div {...getRootProps()}><input {...getInputProps()} />{dropZoneMessage}</div></div>
Add an image preview
Add a preview of the image so the user can see the current upload.
Add this code just above the drop zone:
{newUser.photoURL ? (<p><img alt="User Photo" width={200} src={newUser.photoURL} /></p>) : null}
Update the avatar image in the App
Change the avatar code to this, and remove the static avatar import.
{isLoggedIn() && user.photoURL ? (<li className="avatar"><imgsrc={user.photoURL}alt={`${user.fullName}'s Avatar`}height="64"width="64"/></li>) : null}