import   React, { useContext } from 'react'
import   { assets } from '../assets/assets'
import   { DoctorContext } from '../context/DoctorContext'
import   { AdminContext } from '../context/AdminContext'
import   { useNavigate } from 'react-router-dom'
const Navbar = () => {
  const { dToken, setDToken } = useContext(DoctorContext)
  const { aToken, setAToken } = useContext(AdminContext)
  const navigate = useNavigate()
  const logout = () => {
    navigate('/')
    dToken && setDToken('')
    dToken && localStorage.removeItem('dToken')
    aToken && setAToken('')
    aToken && localStorage.removeItem('aToken')
  }
  return (
    <div className='flex justify-between items-center px-4 sm:px-10 py-3
border-b bg-white'>
      <div className='flex items-center gap-2 text-xs'>
        <img onClick={() => navigate('/')} className='w-36 sm:w-40
cursor-pointer' src={assets.admin_logo} alt="" />
        <p className='border px-2.5 py-0.5 rounded-full border-gray-500
text-gray-600'>{aToken ? 'Admin' : 'Doctor'}</p>
      </div>
      <button onClick={() => logout()} className='bg-primary text-white
text-sm px-10 py-2 rounded-full'>Logout</button>
    </div>
  )
}
export default Navbar
import   React, { useContext } from 'react'
import   { assets } from '../assets/assets'
import   { NavLink } from 'react-router-dom'
import   { DoctorContext } from '../context/DoctorContext'
import   { AdminContext } from '../context/AdminContext'
const Sidebar = () => {
  const { dToken } = useContext(DoctorContext)
  const { aToken } = useContext(AdminContext)
  return (
    <div className='min-h-screen bg-white border-r'>
      {aToken && <ul className='text-[#515151] mt-5'>
        <NavLink to={'/admin-dashboard'} className={({ isActive }) =>
`flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
          <img className='min-w-5' src={assets.home_icon} alt='' />
          <p className='hidden md:block'>Dashboard</p>
        </NavLink>
        <NavLink to={'/all-appointments'} className={({ isActive }) =>
`flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
          <img className='min-w-5' src={assets.appointment_icon} alt=''
/>
          <p className='hidden md:block'>Appointments</p>
        </NavLink>
        <NavLink to={'/add-doctor'} className={({ isActive }) => `flex
items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
          <img className='min-w-5' src={assets.add_icon} alt='' />
          <p className='hidden md:block'>Add Doctor</p>
        </NavLink>
        <NavLink to={'/doctor-list'} className={({ isActive }) => `flex
items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
          <img className='min-w-5' src={assets.people_icon} alt='' />
          <p className='hidden md:block'>Doctors List</p>
        </NavLink>
      </ul>}
      {dToken && <ul className='text-[#515151] mt-5'>
        <NavLink to={'/doctor-dashboard'} className={({ isActive }) =>
`flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
          <img className='min-w-5' src={assets.home_icon} alt='' />
          <p className='hidden md:block'>Dashboard</p>
        </NavLink>
        <NavLink to={'/doctor-appointments'} className={({ isActive }) =>
`flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
          <img className='min-w-5' src={assets.appointment_icon} alt=''
/>
          <p className='hidden md:block'>Appointments</p>
        </NavLink>
        <NavLink to={'/doctor-profile'} className={({ isActive }) =>
`flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
          <img className='min-w-5' src={assets.people_icon} alt='' />
               <p className='hidden md:block'>Profile</p>
            </NavLink>
          </ul>}
        </div>
    )
}
export default Sidebar
import axios from "axios";
import { createContext, useState } from "react";
import { toast } from "react-toastify";
export const AdminContext = createContext()
const AdminContextProvider = (props) => {
    const backendUrl = import.meta.env.VITE_BACKEND_URL
    const [aToken, setAToken] = useState(localStorage.getItem('aToken') ?
localStorage.getItem('aToken') : '')
    const [appointments, setAppointments] = useState([])
    const [doctors, setDoctors] = useState([])
    const [dashData, setDashData] = useState(false)
    // Getting all Doctors data from Database using API
    const getAllDoctors = async () => {
        try {
            const { data } = await axios.get(backendUrl +
'/api/admin/all-doctors', { headers: { aToken } })
            if (data.success) {
                setDoctors(data.doctors)
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            toast.error(error.message)
        }
    // Function to change doctor availablity using API
    const changeAvailability = async (docId) => {
        try {
            const { data } = await axios.post(backendUrl +
'/api/admin/change-availability', { docId }, { headers: { aToken } })
            if (data.success) {
                toast.success(data.message)
                getAllDoctors()
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            console.log(error)
            toast.error(error.message)
        }
    }
    // Getting all appointment data from Database using API
    const getAllAppointments = async () => {
        try {
            const { data } = await axios.get(backendUrl +
'/api/admin/appointments', { headers: { aToken } })
            if (data.success) {
                setAppointments(data.appointments.reverse())
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            toast.error(error.message)
            console.log(error)
        }
    // Function to cancel appointment using API
    const cancelAppointment = async (appointmentId) => {
        try {
            const { data } = await axios.post(backendUrl +
'/api/admin/cancel-appointment', { appointmentId }, { headers: { aToken }
})
            if (data.success) {
                toast.success(data.message)
                getAllAppointments()
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            toast.error(error.message)
            console.log(error)
        }
    // Getting Admin Dashboard data from Database using API
    const getDashData = async () => {
        try {
            const { data } = await axios.get(backendUrl +
'/api/admin/dashboard', { headers: { aToken } })
            if (data.success) {
                setDashData(data.dashData)
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            console.log(error)
            toast.error(error.message)
        }
    }
    const value = {
        aToken, setAToken,
        doctors,
        getAllDoctors,
        changeAvailability,
        appointments,
        getAllAppointments,
        getDashData,
        cancelAppointment,
        dashData
    }
    return (
        <AdminContext.Provider value={value}>
             {props.children}
        </AdminContext.Provider>
    )
export default AdminContextProvider
import { createContext } from "react";
export const AppContext = createContext()
const AppContextProvider = (props) => {
    const currency = import.meta.env.VITE_CURRENCY
    const backendUrl = import.meta.env.VITE_BACKEND_URL
    const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec"]
    // Function to format the date eg. ( 20_01_2000 => 20 Jan 2000 )
    const slotDateFormat = (slotDate) => {
        const dateArray = slotDate.split('_')
        return dateArray[0] + " " + months[Number(dateArray[1])] + " " +
dateArray[2]
    }
    // Function to calculate the age eg. ( 20_01_2000 => 24 )
    const calculateAge = (dob) => {
        const today = new Date()
        const birthDate = new Date(dob)
        let age = today.getFullYear() - birthDate.getFullYear()
        return age
    }
    const value = {
        backendUrl,
        currency,
        slotDateFormat,
        calculateAge,
    }
    return (
        <AppContext.Provider value={value}>
             {props.children}
        </AppContext.Provider>
    )
export default AppContextProvider
import { createContext, useState } from "react";
import axios from 'axios'
import { toast } from 'react-toastify'
export const DoctorContext = createContext()
const DoctorContextProvider = (props) => {
    const backendUrl = import.meta.env.VITE_BACKEND_URL
    const [dToken, setDToken] = useState(localStorage.getItem('dToken') ?
localStorage.getItem('dToken') : '')
    const [appointments, setAppointments] = useState([])
    const [dashData, setDashData] = useState(false)
    const [profileData, setProfileData] = useState(false)
    // Getting Doctor appointment data from Database using API
    const getAppointments = async () => {
        try {
            const { data } = await axios.get(backendUrl +
'/api/doctor/appointments', { headers: { dToken } })
            if (data.success) {
                setAppointments(data.appointments.reverse())
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            console.log(error)
            toast.error(error.message)
        }
    }
    // Getting Doctor profile data from Database using API
    const getProfileData = async () => {
        try {
            const { data } = await axios.get(backendUrl +
'/api/doctor/profile', { headers: { dToken } })
            console.log(data.profileData)
            setProfileData(data.profileData)
        } catch (error) {
            console.log(error)
            toast.error(error.message)
        }
    }
    // Function to cancel doctor appointment using API
    const cancelAppointment = async (appointmentId) => {
        try {
            const { data } = await axios.post(backendUrl +
'/api/doctor/cancel-appointment', { appointmentId }, { headers: { dToken
} })
            if (data.success) {
                toast.success(data.message)
                getAppointments()
                // after creating dashboard
                getDashData()
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            toast.error(error.message)
            console.log(error)
        }
    // Function to Mark appointment completed using API
    const completeAppointment = async (appointmentId) => {
        try {
            const { data } = await axios.post(backendUrl +
'/api/doctor/complete-appointment', { appointmentId }, { headers: {
dToken } })
            if (data.success) {
                toast.success(data.message)
                getAppointments()
                // Later after creating getDashData Function
                getDashData()
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            toast.error(error.message)
            console.log(error)
        }
    // Getting Doctor dashboard data using API
    const getDashData = async () => {
        try {
            const { data } = await axios.get(backendUrl +
'/api/doctor/dashboard', { headers: { dToken } })
            if (data.success) {
                setDashData(data.dashData)
            } else {
                toast.error(data.message)
            }
        } catch (error) {
            console.log(error)
            toast.error(error.message)
        }
    }
    const value = {
        dToken, setDToken, backendUrl,
        appointments,
        getAppointments,
        cancelAppointment,
        completeAppointment,
        dashData, getDashData,
        profileData, setProfileData,
        getProfileData,
    }
    return (
        <DoctorContext.Provider value={value}>
             {props.children}
        </DoctorContext.Provider>
    )
export default DoctorContextProvider
import   React, { useContext, useState } from 'react'
import   { assets } from '../../assets/assets'
import   { toast } from 'react-toastify'
import   axios from 'axios'
import   { AdminContext } from '../../context/AdminContext'
import   { AppContext } from '../../context/AppContext'
const AddDoctor = () => {
    const   [docImg, setDocImg] = useState(false)
    const   [name, setName] = useState('')
    const   [email, setEmail] = useState('')
    const   [password, setPassword] = useState('')
    const   [experience, setExperience] = useState('1 Year')
    const   [fees, setFees] = useState('')
    const   [about, setAbout] = useState('')
    const   [speciality, setSpeciality] = useState('General physician')
    const   [degree, setDegree] = useState('')
    const   [address1, setAddress1] = useState('')
    const   [address2, setAddress2] = useState('')
    const { backendUrl } = useContext(AppContext)
    const { aToken } = useContext(AdminContext)
    const onSubmitHandler = async (event) => {
        event.preventDefault()
          try {
              if (!docImg) {
                  return toast.error('Image Not Selected')
              }
              const formData = new FormData();
            formData.append('image', docImg)
            formData.append('name', name)
            formData.append('email', email)
            formData.append('password', password)
            formData.append('experience', experience)
            formData.append('fees', Number(fees))
            formData.append('about', about)
            formData.append('speciality', speciality)
            formData.append('degree', degree)
            formData.append('address', JSON.stringify({ line1: address1,
line2: address2 }))
              // console log formdata
              formData.forEach((value, key) => {
                  console.log(`${key}: ${value}`);
              });
            const { data } = await axios.post(backendUrl +
'/api/admin/add-doctor', formData, { headers: { aToken } })
            if (data.success) {
                toast.success(data.message)
                setDocImg(false)
                setName('')
                setPassword('')
                setEmail('')
                 setAddress1('')
                 setAddress2('')
                 setDegree('')
                 setAbout('')
                 setFees('')
             } else {
                 toast.error(data.message)
             }
          } catch (error) {
              toast.error(error.message)
              console.log(error)
          }
      return (
          <form onSubmit={onSubmitHandler} className='m-5 w-full'>
             <p className='mb-3 text-lg font-medium'>Add Doctor</p>
            <div className='bg-white px-8 py-8 border rounded w-full max-
w-4xl max-h-[80vh] overflow-y-scroll'>
                <div className='flex items-center gap-4 mb-8 text-gray-
500'>
                    <label htmlFor="doc-img">
                        <img className='w-16 bg-gray-100 rounded-full
cursor-pointer' src={docImg ? URL.createObjectURL(docImg) :
assets.upload_area} alt="" />
                    </label>
                    <input onChange={(e) => setDocImg(e.target.files[0])}
type="file" name="" id="doc-img" hidden />
                    <p>Upload doctor <br /> picture</p>
                </div>
                <div className='flex flex-col lg:flex-row items-start
gap-10 text-gray-600'>
                      <div className='w-full lg:flex-1 flex flex-col gap-
4'>
                        <div className='flex-1 flex flex-col gap-1'>
                            <p>Your name</p>
                            <input onChange={e =>
setName(e.target.value)} value={name} className='border rounded px-3 py-
2' type="text" placeholder='Name' required />
                        </div>
                        <div className='flex-1 flex flex-col gap-1'>
                            <p>Doctor Email</p>
                            <input onChange={e =>
setEmail(e.target.value)} value={email} className='border rounded px-3
py-2' type="email" placeholder='Email' required />
                        </div>
                          <div className='flex-1 flex flex-col gap-1'>
                              <p>Set Password</p>
                            <input onChange={e =>
setPassword(e.target.value)} value={password} className='border rounded
px-3 py-2' type="password" placeholder='Password' required />
                        </div>
                        <div className='flex-1 flex flex-col gap-1'>
                            <p>Experience</p>
                            <select onChange={e =>
setExperience(e.target.value)} value={experience} className='border
rounded px-2 py-2' >
                                <option value="1 Year">1 Year</option>
                                <option value="2 Year">2 Years</option>
                                <option value="3 Year">3 Years</option>
                                <option value="4 Year">4 Years</option>
                                <option value="5 Year">5 Years</option>
                                <option value="6 Year">6 Years</option>
                                <option value="8 Year">8 Years</option>
                                <option value="9 Year">9 Years</option>
                                <option value="10 Year">10 Years</option>
                            </select>
                        </div>
                        <div className='flex-1 flex flex-col gap-1'>
                            <p>Fees</p>
                            <input onChange={e =>
setFees(e.target.value)} value={fees} className='border rounded px-3 py-
2' type="number" placeholder='Doctor fees' required />
                        </div>
                    </div>
                    <div className='w-full lg:flex-1 flex flex-col gap-
4'>
                        <div className='flex-1 flex flex-col gap-1'>
                            <p>Speciality</p>
                            <select onChange={e =>
setSpeciality(e.target.value)} value={speciality} className='border
rounded px-2 py-2'>
                                <option value="General physician">General
physician</option>
                                <option
value="Gynecologist">Gynecologist</option>
                                <option
value="Dermatologist">Dermatologist</option>
                                <option
value="Pediatricians">Pediatricians</option>
                                <option
value="Neurologist">Neurologist</option>
                                <option
value="Gastroenterologist">Gastroenterologist</option>
                            </select>
                        </div>
                        <div className='flex-1 flex flex-col gap-1'>
                            <p>Degree</p>
                            <input onChange={e =>
setDegree(e.target.value)} value={degree} className='border rounded px-3
py-2' type="text" placeholder='Degree' required />
                           </div>
                        <div className='flex-1 flex flex-col gap-1'>
                            <p>Address</p>
                            <input onChange={e =>
setAddress1(e.target.value)} value={address1} className='border rounded
px-3 py-2' type="text" placeholder='Address 1' required />
                            <input onChange={e =>
setAddress2(e.target.value)} value={address2} className='border rounded
px-3 py-2' type="text" placeholder='Address 2' required />
                        </div>
                     </div>
                  </div>
                <div>
                    <p className='mt-4 mb-2'>About Doctor</p>
                    <textarea onChange={e => setAbout(e.target.value)}
value={about} className='w-full px-4 pt-2 border rounded' rows={5}
placeholder='write about doctor'></textarea>
                </div>
                <button type='submit' className='bg-primary px-10 py-3
mt-4 text-white rounded-full'>Add doctor</button>
            </div>
        </form>
    )
}
export default AddDoctor
import   React, { useEffect } from 'react'
import   { assets } from '../../assets/assets'
import   { useContext } from 'react'
import   { AdminContext } from '../../context/AdminContext'
import   { AppContext } from '../../context/AppContext'
const AllAppointments = () => {
  const { aToken, appointments, cancelAppointment, getAllAppointments } =
useContext(AdminContext)
  const { slotDateFormat, calculateAge, currency } =
useContext(AppContext)
  useEffect(() => {
    if (aToken) {
      getAllAppointments()
    }
  }, [aToken])
  return (
    <div className='w-full max-w-6xl m-5 '>
         <p className='mb-3 text-lg font-medium'>All Appointments</p>
      <div className='bg-white border rounded text-sm max-h-[80vh]
overflow-y-scroll'>
        <div className='hidden sm:grid grid-cols-
[0.5fr_3fr_1fr_3fr_3fr_1fr_1fr] grid-flow-col py-3 px-6 border-b'>
          <p>#</p>
          <p>Patient</p>
          <p>Age</p>
          <p>Date & Time</p>
          <p>Doctor</p>
          <p>Fees</p>
          <p>Action</p>
        </div>
        {appointments.map((item, index) => (
          <div className='flex flex-wrap justify-between max-sm:gap-2
sm:grid sm:grid-cols-[0.5fr_3fr_1fr_3fr_3fr_1fr_1fr] items-center text-
gray-500 py-3 px-6 border-b hover:bg-gray-50' key={index}>
            <p className='max-sm:hidden'>{index+1}</p>
            <div className='flex items-center gap-2'>
               <img src={item.userData.image} className='w-8 rounded-full'
alt="" /> <p>{item.userData.name}</p>
            </div>
            <p className='max-
sm:hidden'>{calculateAge(item.userData.dob)}</p>
            <p>{slotDateFormat(item.slotDate)}, {item.slotTime}</p>
            <div className='flex items-center gap-2'>
               <img src={item.docData.image} className='w-8 rounded-full
bg-gray-200' alt="" /> <p>{item.docData.name}</p>
            </div>
            <p>{currency}{item.amount}</p>
            {item.cancelled ? <p className='text-red-400 text-xs font-
medium'>Cancelled</p> : item.isCompleted ? <p className='text-green-500
text-xs font-medium'>Completed</p> : <img onClick={() =>
cancelAppointment(item._id)} className='w-10 cursor-pointer'
src={assets.cancel_icon} alt="" />}
          </div>
        ))}
          </div>
        </div>
    )
}
export default AllAppointments
import   React, { useContext, useEffect } from 'react'
import   { assets } from '../../assets/assets'
import   { AdminContext } from '../../context/AdminContext'
import   { AppContext } from '../../context/AppContext'
const Dashboard = () => {
  const { aToken, getDashData, cancelAppointment, dashData } =
useContext(AdminContext)
  const { slotDateFormat } = useContext(AppContext)
  useEffect(() => {
    if (aToken) {
      getDashData()
    }
  }, [aToken])
  return dashData && (
    <div className='m-5'>
      <div className='flex flex-wrap gap-3'>
        <div className='flex items-center gap-2 bg-white p-4 min-w-52
rounded border-2 border-gray-100 cursor-pointer hover:scale-105
transition-all'>
          <img className='w-14' src={assets.doctor_icon} alt="" />
          <div>
             <p className='text-xl font-semibold text-gray-
600'>{dashData.doctors}</p>
             <p className='text-gray-400'>Doctors</p>
          </div>
        </div>
        <div className='flex items-center gap-2 bg-white p-4 min-w-52
rounded border-2 border-gray-100 cursor-pointer hover:scale-105
transition-all'>
          <img className='w-14' src={assets.appointments_icon} alt="" />
          <div>
             <p className='text-xl font-semibold text-gray-
600'>{dashData.appointments}</p>
             <p className='text-gray-400'>Appointments</p>
          </div>
        </div>
        <div className='flex items-center gap-2 bg-white p-4 min-w-52
rounded border-2 border-gray-100 cursor-pointer hover:scale-105
transition-all'>
          <img className='w-14' src={assets.patients_icon} alt="" />
          <div>
             <p className='text-xl font-semibold text-gray-
600'>{dashData.patients}</p>
             <p className='text-gray-400'>Patients</p></div>
        </div>
      </div>
      <div className='bg-white'>
        <div className='flex items-center gap-2.5 px-4 py-4 mt-10
rounded-t border'>
          <img src={assets.list_icon} alt="" />
          <p className='font-semibold'>Latest Bookings</p>
        </div>
          <div className='pt-4 border border-t-0'>
          {dashData.latestAppointments.slice(0, 5).map((item, index) => (
             <div className='flex items-center px-6 py-3 gap-3 hover:bg-
gray-100' key={index}>
               <img className='rounded-full w-10' src={item.docData.image}
alt="" />
               <div className='flex-1 text-sm'>
                 <p className='text-gray-800 font-
medium'>{item.docData.name}</p>
                 <p className='text-gray-600 '>Booking on
{slotDateFormat(item.slotDate)}</p>
               </div>
               {item.cancelled ? <p className='text-red-400 text-xs font-
medium'>Cancelled</p> : item.isCompleted ? <p className='text-green-500
text-xs font-medium'>Completed</p> : <img onClick={() =>
cancelAppointment(item._id)} className='w-10 cursor-pointer'
src={assets.cancel_icon} alt="" />}
             </div>
          ))}
        </div>
      </div>
        </div>
    )
}
export default Dashboard
import React, { useContext, useEffect } from 'react'
import { AdminContext } from '../../context/AdminContext'
const DoctorsList = () => {
  const { doctors, changeAvailability , aToken , getAllDoctors} =
useContext(AdminContext)
  useEffect(() => {
    if (aToken) {
        getAllDoctors()
    }
}, [aToken])
  return (
    <div className='m-5 max-h-[90vh] overflow-y-scroll'>
      <h1 className='text-lg font-medium'>All Doctors</h1>
      <div className='w-full flex flex-wrap gap-4 pt-5 gap-y-6'>
        {doctors.map((item, index) => (
           <div className='border border-[#C9D8FF] rounded-xl max-w-56
overflow-hidden cursor-pointer group' key={index}>
             <img className='bg-[#EAEFFF] group-hover:bg-primary
transition-all duration-500' src={item.image} alt="" />
             <div className='p-4'>
               <p className='text-[#262626] text-lg font-
medium'>{item.name}</p>
               <p className='text-[#5C5C5C] text-sm'>{item.speciality}</p>
               <div className='mt-2 flex items-center gap-1 text-sm'>
                  <input onChange={()=>changeAvailability(item._id)}
type="checkbox" checked={item.available} />
                  <p>Available</p>
               </div>
             </div>
           </div>
        ))}
      </div>
    </div>
  )
}
export default DoctorsList
import   React from 'react'
import   { useContext, useEffect } from 'react'
import   { DoctorContext } from '../../context/DoctorContext'
import   { AppContext } from '../../context/AppContext'
import   { assets } from '../../assets/assets'
const DoctorAppointments = () => {
  const { dToken, appointments, getAppointments, cancelAppointment,
completeAppointment } = useContext(DoctorContext)
  const { slotDateFormat, calculateAge, currency } =
useContext(AppContext)
  useEffect(() => {
    if (dToken) {
      getAppointments()
    }
  }, [dToken])
  return (
    <div className='w-full max-w-6xl m-5 '>
         <p className='mb-3 text-lg font-medium'>All Appointments</p>
      <div className='bg-white border rounded text-sm max-h-[80vh]
overflow-y-scroll'>
        <div className='max-sm:hidden grid grid-cols-
[0.5fr_2fr_1fr_1fr_3fr_1fr_1fr] gap-1 py-3 px-6 border-b'>
          <p>#</p>
          <p>Patient</p>
          <p>Payment</p>
          <p>Age</p>
          <p>Date & Time</p>
          <p>Fees</p>
          <p>Action</p>
        </div>
        {appointments.map((item, index) => (
          <div className='flex flex-wrap justify-between max-sm:gap-5
max-sm:text-base sm:grid grid-cols-[0.5fr_2fr_1fr_1fr_3fr_1fr_1fr] gap-1
items-center text-gray-500 py-3 px-6 border-b hover:bg-gray-50'
key={index}>
             <p className='max-sm:hidden'>{index}</p>
             <div className='flex items-center gap-2'>
               <img src={item.userData.image} className='w-8 rounded-full'
alt="" /> <p>{item.userData.name}</p>
             </div>
             <div>
               <p className='text-xs inline border border-primary px-2
rounded-full'>
                 {item.payment?'Online':'CASH'}
               </p>
             </div>
             <p className='max-
sm:hidden'>{calculateAge(item.userData.dob)}</p>
             <p>{slotDateFormat(item.slotDate)}, {item.slotTime}</p>
             <p>{currency}{item.amount}</p>
             {item.cancelled
               ? <p className='text-red-400 text-xs font-
medium'>Cancelled</p>
               : item.isCompleted
                 ? <p className='text-green-500 text-xs font-
medium'>Completed</p>
                 : <div className='flex'>
                   <img onClick={() => cancelAppointment(item._id)}
className='w-10 cursor-pointer' src={assets.cancel_icon} alt="" />
                   <img onClick={() => completeAppointment(item._id)}
className='w-10 cursor-pointer' src={assets.tick_icon} alt="" />
                 </div>
             }
          </div>
        ))}
      </div>
        </div>
    )
}
export default DoctorAppointments
import   React from 'react'
import   { useContext } from 'react'
import   { useEffect } from 'react'
import   { DoctorContext } from '../../context/DoctorContext'
import   { assets } from '../../assets/assets'
import   { AppContext } from '../../context/AppContext'
const DoctorDashboard = () => {
  const { dToken, dashData, getDashData, cancelAppointment,
completeAppointment } = useContext(DoctorContext)
  const { slotDateFormat, currency } = useContext(AppContext)
  useEffect(() => {
    if (dToken) {
      getDashData()
    }
  }, [dToken])
  return dashData && (
    <div className='m-5'>
      <div className='flex flex-wrap gap-3'>
        <div className='flex items-center gap-2 bg-white p-4 min-w-52
rounded border-2 border-gray-100 cursor-pointer hover:scale-105
transition-all'>
          <img className='w-14' src={assets.earning_icon} alt="" />
          <div>
             <p className='text-xl font-semibold text-gray-600'>{currency}
{dashData.earnings}</p>
             <p className='text-gray-400'>Earnings</p>
          </div>
        </div>
        <div className='flex items-center gap-2 bg-white p-4 min-w-52
rounded border-2 border-gray-100 cursor-pointer hover:scale-105
transition-all'>
          <img className='w-14' src={assets.appointments_icon} alt="" />
          <div>
             <p className='text-xl font-semibold text-gray-
600'>{dashData.appointments}</p>
             <p className='text-gray-400'>Appointments</p>
          </div>
        </div>
        <div className='flex items-center gap-2 bg-white p-4 min-w-52
rounded border-2 border-gray-100 cursor-pointer hover:scale-105
transition-all'>
          <img className='w-14' src={assets.patients_icon} alt="" />
          <div>
             <p className='text-xl font-semibold text-gray-
600'>{dashData.patients}</p>
             <p className='text-gray-400'>Patients</p></div>
        </div>
      </div>
      <div className='bg-white'>
        <div className='flex items-center gap-2.5 px-4 py-4 mt-10
rounded-t border'>
              <img src={assets.list_icon} alt="" />
              <p className='font-semibold'>Latest Bookings</p>
            </div>
        <div className='pt-4 border border-t-0'>
          {dashData.latestAppointments.slice(0, 5).map((item, index) => (
             <div className='flex items-center px-6 py-3 gap-3 hover:bg-
gray-100' key={index}>
               <img className='rounded-full w-10'
src={item.userData.image} alt="" />
               <div className='flex-1 text-sm'>
                 <p className='text-gray-800 font-
medium'>{item.userData.name}</p>
                 <p className='text-gray-600 '>Booking on
{slotDateFormat(item.slotDate)}</p>
               </div>
               {item.cancelled
                 ? <p className='text-red-400 text-xs font-
medium'>Cancelled</p>
                 : item.isCompleted
                    ? <p className='text-green-500 text-xs font-
medium'>Completed</p>
                    : <div className='flex'>
                      <img onClick={() => cancelAppointment(item._id)}
className='w-10 cursor-pointer' src={assets.cancel_icon} alt="" />
                      <img onClick={() => completeAppointment(item._id)}
className='w-10 cursor-pointer' src={assets.tick_icon} alt="" />
                    </div>
               }
             </div>
          ))}
        </div>
      </div>
        </div>
    )
}
export default DoctorDashboard
import   React, { useContext, useEffect, useState } from 'react'
import   { DoctorContext } from '../../context/DoctorContext'
import   { AppContext } from '../../context/AppContext'
import   { toast } from 'react-toastify'
import   axios from 'axios'
const DoctorProfile = () => {
    const { dToken, profileData, setProfileData, getProfileData } =
useContext(DoctorContext)
    const { currency, backendUrl } = useContext(AppContext)
    const [isEdit, setIsEdit] = useState(false)
    const updateProfile = async () => {
          try {
              const updateData = {
                  address: profileData.address,
                  fees: profileData.fees,
                  about: profileData.about,
                  available: profileData.available
              }
            const { data } = await axios.post(backendUrl +
'/api/doctor/update-profile', updateData, { headers: { dToken } })
              if (data.success) {
                  toast.success(data.message)
                  setIsEdit(false)
                  getProfileData()
              } else {
                  toast.error(data.message)
              }
              setIsEdit(false)
          } catch (error) {
              toast.error(error.message)
              console.log(error)
          }
    useEffect(() => {
        if (dToken) {
            getProfileData()
        }
    }, [dToken])
    return profileData && (
        <div>
            <div className='flex flex-col gap-4 m-5'>
                <div>
                    <img className='bg-primary/80 w-full sm:max-w-64
rounded-lg' src={profileData.image} alt="" />
                </div>
                <div className='flex-1 border border-stone-100 rounded-lg
p-8 py-7 bg-white'>
                    {/* ----- Doc Info : name, degree, experience -----
*/}
                    <p className='flex items-center gap-2 text-3xl font-
medium text-gray-700'>{profileData.name}</p>
                    <div className='flex items-center gap-2 mt-1 text-
gray-600'>
                        <p>{profileData.degree} -
{profileData.speciality}</p>
                        <button className='py-0.5 px-2 border text-xs
rounded-full'>{profileData.experience}</button>
                    </div>
                    {/* ----- Doc About ----- */}
                    <div>
                        <p className='flex items-center gap-1 text-sm
font-medium text-[#262626] mt-3'>About :</p>
                        <p className='text-sm text-gray-600 max-w-[700px]
mt-1'>
                            {
                                isEdit
                                    ? <textarea onChange={(e) =>
setProfileData(prev => ({ ...prev, about: e.target.value }))} type='text'
className='w-full outline-primary p-2' rows={8} value={profileData.about}
/>
                                    : profileData.about
                            }
                        </p>
                    </div>
                    <p className='text-gray-600 font-medium mt-4'>
                        Appointment fee: <span className='text-gray-
800'>{currency} {isEdit ? <input type='number' onChange={(e) =>
setProfileData(prev => ({ ...prev, fees: e.target.value }))}
value={profileData.fees} /> : profileData.fees}</span>
                    </p>
                    <div className='flex gap-2 py-2'>
                        <p>Address:</p>
                        <p className='text-sm'>
                            {isEdit ? <input type='text' onChange={(e) =>
setProfileData(prev => ({ ...prev, address: { ...prev.address, line1:
e.target.value } }))} value={profileData.address.line1} /> :
profileData.address.line1}
                            <br />
                            {isEdit ? <input type='text' onChange={(e) =>
setProfileData(prev => ({ ...prev, address: { ...prev.address, line2:
e.target.value } }))} value={profileData.address.line2} /> :
profileData.address.line2}
                        </p>
                    </div>
                    <div className='flex gap-1 pt-2'>
                        <input type="checkbox" onChange={() => isEdit &&
setProfileData(prev => ({ ...prev, available: !prev.available }))}
checked={profileData.available} />
                        <label htmlFor="">Available</label>
                    </div>
                    {
                        isEdit
                            ? <button onClick={updateProfile}
className='px-4 py-1 border border-primary text-sm rounded-full mt-5
hover:bg-primary hover:text-white transition-all'>Save</button>
                            : <button onClick={() => setIsEdit(prev =>
!prev)} className='px-4 py-1 border border-primary text-sm rounded-full
mt-5 hover:bg-primary hover:text-white transition-all'>Edit</button>
                    }
                </div>
            </div>
        </div>
    )
}
export default DoctorProfile
import    axios from 'axios'
import    React, { useContext, useState } from 'react'
import    { DoctorContext } from '../context/DoctorContext'
import    { AdminContext } from '../context/AdminContext'
import    { toast } from 'react-toastify'
const Login = () => {
  const [state, setState] = useState('Admin')
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const backendUrl = import.meta.env.VITE_BACKEND_URL
  const { setDToken } = useContext(DoctorContext)
  const { setAToken } = useContext(AdminContext)
  const onSubmitHandler = async (event) => {
    event.preventDefault();
      if (state === 'Admin') {
      const { data } = await axios.post(backendUrl + '/api/admin/login',
{ email, password })
      if (data.success) {
        setAToken(data.token)
        localStorage.setItem('aToken', data.token)
      } else {
        toast.error(data.message)
      }
      } else {
      const { data } = await axios.post(backendUrl + '/api/doctor/login',
{ email, password })
      if (data.success) {
        setDToken(data.token)
        localStorage.setItem('dToken', data.token)
      } else {
        toast.error(data.message)
      }
  return (
    <form onSubmit={onSubmitHandler} className='min-h-[80vh] flex items-
center'>
      <div className='flex flex-col gap-3 m-auto items-start p-8 min-w-
[340px] sm:min-w-96 border rounded-xl text-[#5E5E5E] text-sm shadow-lg'>
         <p className='text-2xl font-semibold m-auto'><span
className='text-primary'>{state}</span> Login</p>
         <div className='w-full '>
           <p>Email</p>
           <input onChange={(e) => setEmail(e.target.value)} value={email}
className='border border-[#DADADA] rounded w-full p-2 mt-1' type="email"
required />
         </div>
        <div className='w-full '>
          <p>Password</p>
          <input onChange={(e) => setPassword(e.target.value)}
value={password} className='border border-[#DADADA] rounded w-full p-2
mt-1' type="password" required />
        </div>
        <button className='bg-primary text-white w-full py-2 rounded-md
text-base'>Login</button>
        {
          state === 'Admin'
             ? <p>Doctor Login? <span onClick={() => setState('Doctor')}
className='text-primary underline cursor-pointer'>Click here</span></p>
             : <p>Admin Login? <span onClick={() => setState('Admin')}
className='text-primary underline cursor-pointer'>Click here</span></p>
        }
      </div>
    </form>
  )
}
export default Login
import    React, { useContext } from 'react'
import    { DoctorContext } from './context/DoctorContext';
import    { AdminContext } from './context/AdminContext';
import    { Route, Routes } from 'react-router-dom'
import    { ToastContainer } from 'react-toastify';
import    'react-toastify/dist/ReactToastify.css';
import    Navbar from './components/Navbar'
import    Sidebar from './components/Sidebar'
import    Dashboard from './pages/Admin/Dashboard';
import    AllAppointments from './pages/Admin/AllAppointments';
import    AddDoctor from './pages/Admin/AddDoctor';
import    DoctorsList from './pages/Admin/DoctorsList';
import    Login from './pages/Login';
import    DoctorAppointments from './pages/Doctor/DoctorAppointments';
import    DoctorDashboard from './pages/Doctor/DoctorDashboard';
import    DoctorProfile from './pages/Doctor/DoctorProfile';
const App = () => {
     const { dToken } = useContext(DoctorContext)
     const { aToken } = useContext(AdminContext)
     return dToken || aToken ? (
       <div className='bg-[#F8F9FD]'>
         <ToastContainer />
         <Navbar />
         <div className='flex items-start'>
           <Sidebar />
           <Routes>
             <Route path='/' element={<></>} />
             <Route path='/admin-dashboard' element={<Dashboard />} />
             <Route path='/all-appointments' element={<AllAppointments />}
/>
             <Route path='/add-doctor' element={<AddDoctor />} />
             <Route path='/doctor-list' element={<DoctorsList />} />
             <Route path='/doctor-dashboard' element={<DoctorDashboard />}
/>
             <Route path='/doctor-appointments' element={<DoctorAppointments
/>} />
              <Route path='/doctor-profile' element={<DoctorProfile />} />
            </Routes>
          </div>
       </div>
     ) : (
       <>
          <ToastContainer />
          <Login />
       </>
     )
}
export default App
import   React from 'react'
import   ReactDOM from 'react-dom/client'
import   App from './App.jsx'
import   './index.css'
import   { BrowserRouter } from 'react-router-dom'
import   AdminContextProvider from './context/AdminContext.jsx'
import   DoctorContextProvider from './context/DoctorContext.jsx'
import   AppContextProvider from './context/AppContext.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
  <BrowserRouter>
    <AdminContextProvider>
      <DoctorContextProvider>
        <AppContextProvider>
          <App />
        </AppContextProvider>
      </DoctorContextProvider>
    </AdminContextProvider>
  </BrowserRouter>,
)