How to Create Update User Profile API and Implement in React JS

How to implement Update User Profile Page API Functionality in React JS

Here are the Steps: –

  1. Add route – router.put(‘/update/:userId’, verifyToken, updateUser);
  2. Install a package – npm i cookie-parser
  3. Import cookie parser in index.js – import cookieParser from ‘cookie-parser’
  4. Use cookie parser  – app.use(cookieParser());
  5. Create a file inside utils “verifyUser.js”
import jwt from ‘jsonwebtoken’
import { errorHandler } from ‘./error.js’;

 

export const verifyToken=(req, res, next)=>{
    const token=req.cookies.access_token;
    if(!token){
        return next(errorHandler(401, “Unauthorized”))
    }
    jwt.verify(token, process.env.JWT_SECRET_KEY, (err, user)=>{
        if(err){
            return next(errorHandler(401, ‘Unauthorized’))
        }
        req.user=user;
        next();
    })
}
6. Create user.controller.js –
import bcryptjs from ‘bcryptjs’;
import { errorHandler } from ‘../utils/error.js’;
import User from ‘../models/user.model.js’;

 

export const test=(req, res)=>{
    res.json({message:“API is working”})
}

 

export const updateUser=async(req, res, next)=>{
    if(req.user.id !== req.params.userId){
        return next(errorHandler(403, ‘You are not allowed to update this user’))
    }
    if(req.body.password){
        if(req.body.password.length<6){
            return next(errorHandler(400, ‘Password must be at least 6 characters’))
        }
        req.body.password=bcryptjs.hashSync(req.body.password, 10);
    }

 

    if(req.body.username){
        if(req.body.username.length<7 || req.body.username.length>20){
            return next(errorHandler(400, ‘Username must be between 7 and 20 characters’))
        }
        if(req.body.username.includes(‘ ‘)){
            return next(errorHandler(400, ‘Username cannot contain space’))
        }
        if(req.body.username !==req.body.username.toLowerCase()){
            return next(errorHandler(400, ‘Username must be in lower case’))
        }
        if(!req.body.username.match(/^[a-zA-Z0-9]+$/)){
            return next(errorHandler(400, “Username can only contain charcters and numbers”))
        }
    }
        try {
            const updatedUser=await User.findByIdAndUpdate(req.params.userId,{
                $set:{
                    username:req.body.username,
                    email:req.body.email,
                    profilePicture:req.body.profilePicture,
                    password:req.body.password
                }
            }, {new:true})
            const {password, …rest}=updatedUser._doc;
            res.status(200).json(rest);
        } catch (error) {
            next(error)
        }
}

 

Implement Update User Profile Page API –

DashProfile.jsx:-
 
import React, { useEffect, useRef, useState } from ‘react’
import { Alert, Button, TextInput } from ‘flowbite-react’
import {useSelector} from ‘react-redux’
import {app} from ‘../firebase’
import {getDownloadURL, getStorage, ref, uploadBytesResumable} from ‘firebase/storage’
import { CircularProgressbar } from ‘react-circular-progressbar’;
import ‘react-circular-progressbar/dist/styles.css’;
import {updateStart, updateSuccess, updateFailure} from ‘../redux/user/userSlice.js’
import {useDispatch} from ‘react-redux’

 

const DashProfile = () => {
  const {currentUser}=useSelector(state=>state.user)
  const [imageFile, setImageFile]=useState(null)
  const [imageFileUrl, setImageFileUrl]=useState(null);
  const [imageFileUploadProgress, setImageFileUploadProgress]=useState(null);
  const [imageFileUploadError, setImageFileUploadError]=useState(null);
  const [imageFileUploading, setImageFileUploading]=useState(false)
  const [updateUserSuccess, setUpdateUserSuccess]=useState(null)
  const [updateUserError, setUpdateUserError]=useState(null)
  const [formData, setFormData]=useState({});
  const dispatch=useDispatch();
  console.log(imageFileUploadProgress, imageFileUploadError);
  const filePickerRef=useRef();
  const handleImageChange=(e)=>{
    const file=e.target.files[0];
    if(file){
     setImageFile(file);
    setImageFileUrl(URL.createObjectURL(file));
    }
  };
  useEffect(()=>{
    if(imageFile){
      uploadImage();
    }
  }, [imageFile])
  const uploadImage=async()=>{
    // service firebase.storage {
    //   match /b/{bucket}/o {
    //     match /{allPaths=**} {
    //       allow read;
    //       allow write: if
    //       request.resource.size<2*1024*1024 &&
    //       request.resource.contentType.matches(‘image/.*’);
    //     }
    //   }
    // }
    setImageFileUploading(true)
    setImageFileUploadError(null)
    const storage=getStorage(app);
    const fileName=new Date().getTime()+imageFile.name;
    const storageRef=ref(storage, fileName);
    const uploadTask=uploadBytesResumable(storageRef, imageFile);
    uploadTask.on(
      ‘state_changed’,
      (snapshot)=>{
        const progress=(snapshot.bytesTransferred/snapshot.totalBytes)*100;
        setImageFileUploadProgress(progress.toFixed(0));
      },
      (error)=>{
        setImageFileUploadError(‘Could Not Upload Image (File must be less than 2MB)’)

 

        setImageFileUploadProgress(null)
        setImageFile(null);
        setImageFileUrl(null)
        setImageFileUploading(false)
      },
      ()=>{
        getDownloadURL(uploadTask.snapshot.ref).then((downloadURL)=>{
          setImageFileUrl(downloadURL);
          setFormData({…formData, profilePicture:downloadURL});
          setImageFileUploading(false)
        })
      }
    )
    console.log(“Uploading Image…”)
  }
  console.log(imageFile, imageFileUrl)
  const handleChange=(e)=>{
    setFormData({…formData, [e.target.id]:e.target.value})
  }
  console.log(formData)
  const handleSubmit=async(e)=>{
    e.preventDefault();
    setUpdateUserError(null);
    setUpdateUserSuccess(null)
    if(Object.keys(formData).length===0){
      setUpdateUserError(“No Changes made”)
      return;
    }
    if(imageFileUploading){
      setUpdateUserError(‘Please wait for image to upload’)
      return;
    }
    try {
      dispatch(updateStart());
      const res=await fetch(`/api/user/update/${currentUser._id}`, {
        method:‘PUT’,
        headers:{
          ‘Content-Type’:‘application/json’
        },
        body:JSON.stringify(formData)
      })
      const data=await res.json();
      if(!res.ok){
        dispatch(updateFailure(data.message))
        setUpdateUserError(data.message)
      }else{
        dispatch(updateSuccess(data))
        setUpdateUserSuccess(“User’s Profile Updated Successfully”)
      }
    } catch (error) {
      dispatch(updateFailure(error.message))
      setUpdateUserError(error.message)
    }

 

  }
  return (
    <div className=‘ max-w-lg mx-auto p-3 w-full’>
      <h1 className=‘my-7 text-center font-semibold text-3xl’>Profile</h1>
      <form className=‘flex flex-col gap-4’ onSubmit={handleSubmit}>
        <input type=‘file’ accept=‘image/*’ onChange={handleImageChange} ref={filePickerRef}/>
        <div className=‘ relative w-32 h-32 self-center cursor-pointer rounded-full shadow-md overflow-hidden’ onClick={()=>filePickerRef.current.click()}>
          {
            imageFileUploadProgress && (
              <CircularProgressbar value={imageFileUploadProgress || 0} text={`${imageFileUploadProgress}%`} strokeWidth={5} styles={{
                root:{
                  width:‘100%’,
                  height:‘100%’,
                  position:‘absolute’,
                  top:0,
                  left:0
                },
                path:{
                  stroke:`rgba(62, 152, 199, ${imageFileUploadProgress/100})`
                }
              }}/>
            )
          }

 

          <img src={imageFileUrl || currentUser.profilePicture} alt=‘user’ className={` rounded-full w-full h-full object-cover border-8 border-[lightgray] ${imageFileUploadProgress && imageFileUploadProgress<100 && ‘opacity-60’}`}/>
        </div>
        {
          imageFileUploadError && <Alert color=‘failure’>{imageFileUploadError}</Alert>
        }

 

        <TextInput type=‘text’ id=‘username’ placeholder=‘username’ defaultValue={currentUser.username} onChange={handleChange}/>
        <TextInput type=’email’ id=’email’ placeholder=’email’ defaultValue={currentUser.email} onChange={handleChange}/>
        <TextInput type=‘password’ id=‘password’ placeholder=‘password’ onChange={handleChange}/>

 

        <Button type=‘submit’ gradientDuoTone=‘purpleToBlue’ outline>Update</Button>
      </form>
      <div className=‘ text-red-500 flex justify-between gap-5’>
        <span className=‘ cursor-pointer’>Delete Account</span>
        <span className=‘ cursor-pointer’>Sign Out</span>
      </div>
      {
        updateUserSuccess && (
          <Alert color=‘success’ className=‘mt-5’>
            {updateUserSuccess}
          </Alert>
        )
      }
      {
        updateUserError && (
          <Alert color=‘failure’ className=‘mt-5’>
            {updateUserError}
          </Alert>
        )
      }
    </div>
  )
}

 

export default DashProfile
 

UserSlice.jsx:

import {createSlice} from ‘@reduxjs/toolkit’
const initialState={
    currentUser:null,
    error:null,
    loading:false
}
const userSlice=createSlice({
    name:‘user’,
    initialState,
    reducers:{
        signInStart:(state)=>{
            state.loading=true,
            state.error=null
        },
        signInSuccess:(state, action)=>{
            state.currentUser=action.payload,
            state.loading=false,
            state.error=null
        },
        signInFailure:(state, action)=>{
            state.loading=false,
            state.error=action.payload
        },
        updateStart:(state)=>{
            state.loading=true;
            state.error=null
        },
        updateSuccess:(state, action)=>{
            state.currentUser=action.payload;
            state.loading=false;
            state.error=null
        },
        updateFailure:(state, action)=>{
            state.loading=false;
            state.error=action.payload;
        }
    }
})
export const {signInStart, signInSuccess, signInFailure, updateStart, updateSuccess, updateFailure} =userSlice.actions;
export default userSlice.reducer;

Video Tutorial –  Create Update User API Route in React JS



Video Tutorial – implement Update User Profile Page API