Doctor Booking System (27 Files Merged) (4 Files Merged)
Doctor Booking System (27 Files Merged) (4 Files Merged)
logs JWT_SECRET="greatstack" import { assets } from '../assets/assets' import { assets } from '../assets/assets'
*.log import { NavLink, useNavigate } from 'react-router-dom'
npm-debug.log* # Admin Panel Credentials const Header = () => { import { AppContext } from '../context/AppContext'
yarn-debug.log* ADMIN_EMAIL = "[email protected]" return (
yarn-error.log* ADMIN_PASSWORD = "greatstack123" <div className='flex flex-col md:flex-row flex-wrap bg-primary const Navbar = () => {
pnpm-debug.log* rounded-lg px-6 md:px-10 lg:px-20 '>
lerna-debug.log* # MongoDB Setup ( required ) const navigate = useNavigate()
MONGODB_URI = {/* --------- Header Left --------- */}
node_modules "mongodb+srv://deepakhannyson:[email protected]/?retr <div className='md:w-1/2 flex flex-col items-start justify- const [showMenu, setShowMenu] = useState(false)
dist yWrites=true&w=majority&appName=Cluster0" center gap-4 py-10 m-auto md:py-[10vw] md:mb-[-30px]'> const { token, setToken, userData } = useContext(AppContext)
dist-ssr <p className='text-3xl md:text-4xl lg:text-5xl text-white
*.local # Cloudinary Setup ( required ) font-semibold leading-tight md:leading-tight lg:leading-tight'> const logout = () => {
CLOUDINARY_NAME = dfzvtwurw Book Appointment <br /> With Trusted Doctors localStorage.removeItem('token')
# Editor directories and files CLOUDINARY_API_KEY =149617587369565 </p> setToken(false)
.vscode/* CLOUDINARY_SECRET_KEY =bx6_MPviZCGsImabi5Uwy0NAdmo <div className='flex flex-col md:flex-row items-center navigate('/login')
!.vscode/extensions.json # Razorpay Payment Integration gap-3 text-white text-sm font-light'> }
.idea RAZORPAY_KEY_ID = "------ Razorpay Key Id here ------" <img className='w-28' src={assets.group_profiles}
.DS_Store RAZORPAY_KEY_SECRET = "------ Razorpay Key Secret here ------" alt="" /> return (
*.suo <p>Simply browse through our extensive list of <div className='flex items-center justify-between text-sm py-4 mb-5
*.ntvs* # Stripe Payment Integration trusted doctors, <br className='hidden sm:block' /> schedule your border-b border-b-[#ADADAD]'>
*.njsproj STRIPE_SECRET_KEY="------ Stripe Secret Key here ------" appointment hassle-free.</p> <img onClick={() => navigate('/')} className='w-44 cursor-pointer'
*.sln </div> src={assets.logo} alt="" />
*.sw? <a href='#speciality' className='flex items-center gap-2 <ul className='md:flex items-start gap-5 font-medium hidden'>
bg-white px-8 py-3 rounded-full text-[#595959] text-sm m-auto md:m-0 <NavLink to='/' >
hover:scale-105 transition-all duration-300'> <li className='py-1'>HOME</li>
Book appointment <img className='w-3' <hr className='border-none outline-none h-0.5 bg-primary w-3/5
src={assets.arrow_icon} alt="" /> m-auto hidden' />
</a> </NavLink>
</div> <NavLink to='/doctors' >
<li className='py-1'>ALL DOCTORS</li>
{/* --------- Header Right --------- */} <hr className='border-none outline-none h-0.5 bg-primary w-3/5
<div className='md:w-1/2 relative'> m-auto hidden' />
<img className='w-full md:absolute bottom-0 h-auto </NavLink>
rounded-lg' src={assets.header_img} alt="" /> <NavLink to='/about' >
</div> <li className='py-1'>ABOUT</li>
</div> <hr className='border-none outline-none h-0.5 bg-primary w-3/5
) m-auto hidden' />
} </NavLink>
<NavLink to='/contact' >
export default Header <li className='py-1'>CONTACT</li>
<hr className='border-none outline-none h-0.5 bg-primary w-3/5
m-auto hidden' />
</NavLink>
</ul>
import React from 'react' import React from 'react' <p onClick={() => navigate('/my-appointments')} import React, { useContext, useEffect, useState } from 'react'
import { assets } from '../assets/assets' import { assets } from '../assets/assets' className='hover:text-black cursor-pointer'>My Appointments</p> import { useNavigate } from 'react-router-dom'
import { useNavigate } from 'react-router-dom' <p onClick={logout} className='hover:text-black cursor- import { AppContext } from '../context/AppContext'
const Footer = () => { pointer'>Logout</p> const RelatedDoctors = ({ speciality, docId }) => {
const Banner = () => { return ( </div>
<div className='md:mx-10'> </div> const navigate = useNavigate()
const navigate = useNavigate() <div className='flex flex-col sm:grid grid-cols-[3fr_1fr_1fr] gap- </div> const { doctors } = useContext(AppContext)
14 my-10 mt-40 text-sm'> : <button onClick={() => navigate('/login')} className='bg-
return ( primary text-white px-8 py-3 rounded-full font-light hidden const [relDoc, setRelDoc] = useState([])
<div className='flex bg-primary rounded-lg px-6 sm:px-10 md:px- <div> md:block'>Create account</button>
14 lg:px-12 my-20 md:mx-10'> <img className='mb-5 w-40' src={assets.logo} alt="" /> } useEffect(() => {
<p className='w-full md:w-2/3 text-gray-600 leading-6'>Lorem <img onClick={() => setShowMenu(true)} className='w-6 md:hidden' if (doctors.length > 0 && speciality) {
{/* ------- Left Side ------- */} Ipsum is simply dummy text of the printing and typesetting industry. src={assets.menu_icon} alt="" /> const doctorsData = doctors.filter((doc) => doc.speciality
<div className='flex-1 py-8 sm:py-10 md:py-16 lg:py-24 lg:pl- Lorem Ipsum has been the industry's standard dummy text ever since the === speciality && doc._id !== docId)
5'> 1500s, when an unknown printer took a galley of type and scrambled it to {/* ---- Mobile Menu ---- */} setRelDoc(doctorsData)
<div className='text-xl sm:text-2xl md:text-3xl lg:text- make a type specimen book.</p> <div className={`md:hidden ${showMenu ? 'fixed w-full' : 'h-0 w- }
5xl font-semibold text-white'> </div> 0'} right-0 top-0 bottom-0 z-20 overflow-hidden bg-white transition- }, [doctors, speciality, docId])
<p>Book Appointment</p> all`}>
<p className='mt-4'>With 100+ Trusted Doctors</p> <div> <div className='flex items-center justify-between px-5 py-6'> return (
</div> <p className='text-xl font-medium mb-5'>COMPANY</p> <img src={assets.logo} className='w-36' alt="" /> <div className='flex flex-col items-center gap-4 my-16 text-
<button onClick={() => { navigate('/login'); scrollTo(0, <ul className='flex flex-col gap-2 text-gray-600'> <img onClick={() => setShowMenu(false)} [#262626]'>
0) }} className='bg-white text-sm sm:text-base text-[#595959] px-8 py-3 <li>Home</li> src={assets.cross_icon} className='w-7' alt="" /> <h1 className='text-3xl font-medium'>Related Doctors</h1>
rounded-full mt-6 hover:scale-105 transition-all '>Create <li>About us</li> </div> <p className='sm:w-1/3 text-center text-sm'>Simply browse
account</button> <li>Delivery</li> <ul className='flex flex-col items-center gap-2 mt-5 px-5 text- through our extensive list of trusted doctors.</p>
</div> <li>Privacy policy</li> lg font-medium'> <div className='w-full grid grid-cols-auto gap-4 pt-5 gap-y-6
</ul> <NavLink onClick={() => setShowMenu(false)} to='/'><p px-3 sm:px-0'>
{/* ------- Right Side ------- */} </div> className='px-4 py-2 rounded full inline-block'>HOME</p></NavLink> {relDoc.map((item, index) => (
<div className='hidden md:block md:w-1/2 lg:w-[370px] <NavLink onClick={() => setShowMenu(false)} to='/doctors' ><p <div onClick={() => {
relative'> <div> className='px-4 py-2 rounded full inline-block'>ALL DOCTORS</p></NavLink> navigate(`/appointment/${item._id}`); scrollTo(0, 0) }} className='border
<img className='w-full absolute bottom-0 right-0 max-w- <p className='text-xl font-medium mb-5'>GET IN TOUCH</p> <NavLink onClick={() => setShowMenu(false)} to='/about' ><p border-[#C9D8FF] rounded-xl overflow-hidden cursor-pointer
md' src={assets.appointment_img} alt="" /> <ul className='flex flex-col gap-2 text-gray-600'> className='px-4 py-2 rounded full inline-block'>ABOUT</p></NavLink> hover:translate-y-[-10px] transition-all duration-500' key={index}>
</div> <li>212-456-7890</li> <NavLink onClick={() => setShowMenu(false)} to='/contact' ><p <img className='bg-[#EAEFFF]' src={item.image}
</div> <li>[email protected]</li> className='px-4 py-2 rounded full inline-block'>CONTACT</p></NavLink> alt="" />
) </ul> </ul> <div className='p-4'>
} </div> </div> <div className={`flex items-center gap-2
</div> text-sm text-center ${item.available ? 'text-green-500' : "text-gray-
export default Banner </div> </div> 500"}`}>
) <p className={`w-2 h-2 rounded-full
<div> } ${item.available ? 'bg-green-500' : "bg-gray-
<hr /> 500"}`}></p><p>{item.available ? 'Available' : "Not Available"}</p>
<p className='py-5 text-sm text-center'>Copyright 2024 @ export default Navbar </div>
Prescripto.com - All Right Reserved.</p> <p className='text-[#262626] text-lg font-
</div> medium'>{item.name}</p>
<p className='text-[#5C5C5C] text-
</div> sm'>{item.speciality}</p>
) </div>
} </div>
))}
export default Footer </div>
{/* <button className='bg-[#EAEFFF] text-gray-600 px-12 py-3
rounded-full mt-10'>more</button> */}
</div>
)
}
import React, { useContext, useEffect, useState } from 'react' import React from 'react' import React from 'react'
import { useNavigate } from 'react-router-dom' import { specialityData } from '../assets/assets' useEffect(() => { import { assets } from '../assets/assets'
import { AppContext } from '../context/AppContext' import { Link } from 'react-router-dom' if (token) {
const RelatedDoctors = ({ speciality, docId }) => { loadUserProfileData() const About = () => {
const SpecialityMenu = () => { } return (
const navigate = useNavigate() return ( }, [token]) <div>
const { doctors } = useContext(AppContext) <div id='speciality' className='flex flex-col items-center gap-4
py-16 text-[#262626]'> const value = { <div className='text-center text-2xl pt-10 text-[#707070]'>
const [relDoc, setRelDoc] = useState([]) <h1 className='text-3xl font-medium'>Find by Speciality</h1> doctors, getDoctosData, <p>ABOUT <span className='text-gray-700 font-
<p className='sm:w-1/3 text-center text-sm'>Simply browse currencySymbol, semibold'>US</span></p>
useEffect(() => { through our extensive list of trusted doctors, schedule your appointment backendUrl, </div>
if (doctors.length > 0 && speciality) { hassle-free.</p> token, setToken,
const doctorsData = doctors.filter((doc) => doc.speciality <div className='flex sm:justify-center gap-4 pt-5 w-full userData, setUserData, loadUserProfileData <div className='my-10 flex flex-col md:flex-row gap-12'>
=== speciality && doc._id !== docId) overflow-scroll '> } <img className='w-full md:max-w-[360px]' src={assets.about_image}
setRelDoc(doctorsData) {specialityData.map((item, index) => ( alt="" />
} <Link to={`/doctors/${item.speciality}`} onClick={() return ( <div className='flex flex-col justify-center gap-6 md:w-2/4 text-
}, [doctors, speciality, docId]) => scrollTo(0, 0)} className='flex flex-col items-center text-xs cursor- <AppContext.Provider value={value}> sm text-gray-600'>
pointer flex-shrink-0 hover:translate-y-[-10px] transition-all duration- {props.children} <p>Welcome to Prescripto, your trusted partner in managing your
return ( 500' key={index}> </AppContext.Provider> healthcare needs conveniently and efficiently. At Prescripto, we
<div className='flex flex-col items-center gap-4 my-16 text- <img className='w-16 sm:w-24 mb-2 ' ) understand the challenges individuals face when it comes to scheduling
[#262626]'> src={item.image} alt="" /> doctor appointments and managing their health records.</p>
<h1 className='text-3xl font-medium'>Related Doctors</h1> <p>{item.speciality}</p> } <p>Prescripto is committed to excellence in healthcare
<p className='sm:w-1/3 text-center text-sm'>Simply browse </Link> technology. We continuously strive to enhance our platform, integrating
through our extensive list of trusted doctors.</p> ))} export default AppContextProvider the latest advancements to improve user experience and deliver superior
<div className='w-full grid grid-cols-auto gap-4 pt-5 gap-y-6 </div> service. Whether you're booking your first appointment or managing
px-3 sm:px-0'> </div> ongoing care, Prescripto is here to support you every step of the
{relDoc.map((item, index) => ( ) way.</p>
<div onClick={() => { } <b className='text-gray-800'>Our Vision</b>
navigate(`/appointment/${item._id}`); scrollTo(0, 0) }} className='border <p>Our vision at Prescripto is to create a seamless healthcare
border-[#C9D8FF] rounded-xl overflow-hidden cursor-pointer export default SpecialityMenu experience for every user. We aim to bridge the gap between patients and
hover:translate-y-[-10px] transition-all duration-500' key={index}> healthcare providers, making it easier for you to access the care you
<img className='bg-[#EAEFFF]' src={item.image} need, when you need it.</p>
alt="" /> </div>
<div className='p-4'> </div>
<div className={`flex items-center gap-2
text-sm text-center ${item.available ? 'text-green-500' : "text-gray- <div className='text-xl my-4'>
500"}`}> <p>WHY <span className='text-gray-700 font-semibold'>CHOOSE
<p className={`w-2 h-2 rounded-full US</span></p>
${item.available ? 'bg-green-500' : "bg-gray- </div>
500"}`}></p><p>{item.available ? 'Available' : "Not Available"}</p>
</div> <div className='flex flex-col md:flex-row mb-20'>
<p className='text-[#262626] text-lg font- <div className='border px-10 md:px-16 py-8 sm:py-16 flex flex-col
medium'>{item.name}</p> gap-5 text-[15px] hover:bg-primary hover:text-white transition-all
<p className='text-[#5C5C5C] text- duration-300 text-gray-600 cursor-pointer'>
sm'>{item.speciality}</p> <b>EFFICIENCY:</b>
</div> <p>Streamlined appointment scheduling that fits into your busy
</div> lifestyle.</p>
))} </div>
</div> <div className='border px-10 md:px-16 py-8 sm:py-16 flex flex-col
{/* <button className='bg-[#EAEFFF] text-gray-600 px-12 py-3 gap-5 text-[15px] hover:bg-primary hover:text-white transition-all
rounded-full mt-10'>more</button> */} duration-300 text-gray-600 cursor-pointer'>
</div> <b>CONVENIENCE: </b>
) <p>Access to a network of trusted healthcare professionals in
} your area.</p>
</div>
export default RelatedDoctors <div className='border px-10 md:px-16 py-8 sm:py-16 flex flex-col
gap-5 text-[15px] hover:bg-primary hover:text-white transition-all
duration-300 text-gray-600 cursor-pointer'>
<b>PERSONALIZATION:</b>
import React, { useContext } from 'react' import { createContext, useEffect, useState } from "react"; <p >Tailored recommendations and reminders to help you stay on import React, { useContext, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { toast } from "react-toastify"; top of your health.</p> import { useNavigate, useParams } from 'react-router-dom'
import { AppContext } from '../context/AppContext' import axios from 'axios' </div> import { AppContext } from '../context/AppContext'
const TopDoctors = () => { </div> import { assets } from '../assets/assets'
export const AppContext = createContext() import RelatedDoctors from '../components/RelatedDoctors'
const navigate = useNavigate() </div> import axios from 'axios'
const AppContextProvider = (props) => { ) import { toast } from 'react-toastify'
const { doctors } = useContext(AppContext) }
const currencySymbol = '₹' const Appointment = () => {
return ( const backendUrl = import.meta.env.VITE_BACKEND_URL export default About
<div className='flex flex-col items-center gap-4 my-16 text- const { docId } = useParams()
[#262626] md:mx-10'> const [doctors, setDoctors] = useState([]) const { doctors, currencySymbol, backendUrl, token, getDoctosData } =
<h1 className='text-3xl font-medium'>Top Doctors to Book</h1> const [token, setToken] = useState(localStorage.getItem('token') ? useContext(AppContext)
<p className='sm:w-1/3 text-center text-sm'>Simply browse localStorage.getItem('token') : '') const daysOfWeek = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']
through our extensive list of trusted doctors.</p> const [userData, setUserData] = useState(false)
<div className='w-full grid grid-cols-auto gap-4 pt-5 gap-y-6 const [docInfo, setDocInfo] = useState(false)
px-3 sm:px-0'> // Getting Doctors using API const [docSlots, setDocSlots] = useState([])
{doctors.slice(0, 10).map((item, index) => ( const getDoctosData = async () => { const [slotIndex, setSlotIndex] = useState(0)
<div onClick={() => { const [slotTime, setSlotTime] = useState('')
navigate(`/appointment/${item._id}`); scrollTo(0, 0) }} className='border try {
border-[#C9D8FF] rounded-xl overflow-hidden cursor-pointer const navigate = useNavigate()
hover:translate-y-[-10px] transition-all duration-500' key={index}> const { data } = await axios.get(backendUrl +
<img className='bg-[#EAEFFF]' src={item.image} '/api/doctor/list') const fetchDocInfo = async () => {
alt="" /> if (data.success) { const docInfo = doctors.find((doc) => doc._id === docId)
<div className='p-4'> setDoctors(data.doctors) setDocInfo(docInfo)
<div className={`flex items-center gap-2 } else { }
text-sm text-center ${item.available ? 'text-green-500' : "text-gray- toast.error(data.message)
500"}`}> } const getAvailableSolts = async () => {
<p className={`w-2 h-2 rounded-full
${item.available ? 'bg-green-500' : "bg-gray- } catch (error) { setDocSlots([])
500"}`}></p><p>{item.available ? 'Available' : "Not Available"}</p> console.log(error)
</div> toast.error(error.message) // getting current date
<p className='text-[#262626] text-lg font- } let today = new Date()
medium'>{item.name}</p>
<p className='text-[#5C5C5C] text- } for (let i = 0; i < 7; i++) {
sm'>{item.speciality}</p>
</div> // Getting User Profile using API // getting date with index
</div> const loadUserProfileData = async () => { let currentDate = new Date(today)
))} currentDate.setDate(today.getDate() + i)
</div> try {
<button onClick={() => { navigate('/doctors'); scrollTo(0, 0) // setting end time of the date with index
}} className='bg-[#EAEFFF] text-gray-600 px-12 py-3 rounded-full mt- const { data } = await axios.get(backendUrl + '/api/user/get- let endTime = new Date()
10'>more</button> profile', { headers: { token } }) endTime.setDate(today.getDate() + i)
</div> endTime.setHours(21, 0, 0, 0)
if (data.success) {
) setUserData(data.userData) // setting hours
} } else { if (today.getDate() === currentDate.getDate()) {
toast.error(data.message) currentDate.setHours(currentDate.getHours() > 10 ?
export default TopDoctors } currentDate.getHours() + 1 : 10)
currentDate.setMinutes(currentDate.getMinutes() > 30 ? 30
} catch (error) { : 0)
console.log(error) } else {
toast.error(error.message) currentDate.setHours(10)
} currentDate.setMinutes(0)
}
}
let timeSlots = [];
useEffect(() => {
getDoctosData()
}, []) while (currentDate < endTime) {
let formattedTime = currentDate.toLocaleTimeString([], { } catch (error) { import React, { useContext, useEffect, useState } from 'react' transition-all cursor-pointer ${speciality === 'Neurologist' ? 'bg-
hour: '2-digit', minute: '2-digit' }); console.log(error) import { AppContext } from '../context/AppContext' [#E2E5FF] text-black ' : ''}`}>Neurologist</p>
toast.error(error.message) import { useNavigate, useParams } from 'react-router-dom' <p onClick={() => speciality === 'Gastroenterologist' ?
let day = currentDate.getDate() } navigate('/doctors') : navigate('/doctors/Gastroenterologist')}
let month = currentDate.getMonth() + 1 const Doctors = () => { className={`w-[94vw] sm:w-auto pl-3 py-1.5 pr-16 border border-gray-300
let year = currentDate.getFullYear() } rounded transition-all cursor-pointer ${speciality ===
const { speciality } = useParams() 'Gastroenterologist' ? 'bg-[#E2E5FF] text-black ' :
const slotDate = day + "_" + month + "_" + year useEffect(() => { ''}`}>Gastroenterologist</p>
const slotTime = formattedTime if (doctors.length > 0) { const [filterDoc, setFilterDoc] = useState([]) </div>
fetchDocInfo() const [showFilter, setShowFilter] = useState(false) <div className='w-full grid grid-cols-auto gap-4 gap-y-6'>
const isSlotAvailable = docInfo.slots_booked[slotDate] && } const navigate = useNavigate(); {filterDoc.map((item, index) => (
docInfo.slots_booked[slotDate].includes(slotTime) ? false : true }, [doctors, docId]) <div onClick={() => { navigate(`/appointment/${item._id}`);
const { doctors } = useContext(AppContext) scrollTo(0, 0) }} className='border border-[#C9D8FF] rounded-xl overflow-
if (isSlotAvailable) { useEffect(() => { hidden cursor-pointer hover:translate-y-[-10px] transition-all duration-
if (docInfo) { const applyFilter = () => { 500' key={index}>
// Add slot to array getAvailableSolts() if (speciality) { <img className='bg-[#EAEFFF]' src={item.image} alt="" />
timeSlots.push({ } setFilterDoc(doctors.filter(doc => doc.speciality === speciality)) <div className='p-4'>
datetime: new Date(currentDate), }, [docInfo]) } else { <div className={`flex items-center gap-2 text-sm text-
time: formattedTime setFilterDoc(doctors) center ${item.available ? 'text-green-500' : "text-gray-500"}`}>
}) return docInfo ? ( } <p className={`w-2 h-2 rounded-full ${item.available ?
} <div> } 'bg-green-500' : "bg-gray-500"}`}></p><p>{item.available ? 'Available' :
"Not Available"}</p>
// Increment current time by 30 minutes {/* ---------- Doctor Details ----------- */} useEffect(() => { </div>
currentDate.setMinutes(currentDate.getMinutes() + 30); <div className='flex flex-col sm:flex-row gap-4'> applyFilter() <p className='text-[#262626] text-lg font-
} <div> }, [doctors, speciality]) medium'>{item.name}</p>
<img className='bg-primary w-full sm:max-w-72 <p className='text-[#5C5C5C] text-
setDocSlots(prev => ([...prev, timeSlots])) rounded-lg' src={docInfo.image} alt="" /> return ( sm'>{item.speciality}</p>
</div> <div> </div>
} <p className='text-gray-600'>Browse through the doctors </div>
<div className='flex-1 border border-[#ADADAD] rounded-lg specialist.</p> ))}
} p-8 py-7 bg-white mx-2 sm:mx-0 mt-[-80px] sm:mt-0'> <div className='flex flex-col sm:flex-row items-start gap-5 mt-5'> </div>
<button onClick={() => setShowFilter(!showFilter)} </div>
const bookAppointment = async () => { {/* ----- Doc Info : name, degree, experience ----- className={`py-1 px-3 border rounded text-sm transition-all sm:hidden </div>
*/} ${showFilter ? 'bg-primary text-white' : ''}`}>Filters</button> )
if (!token) { <div className={`flex-col gap-4 text-sm text-gray-600 }
toast.warning('Login to book appointment') <p className='flex items-center gap-2 text-3xl font- ${showFilter ? 'flex' : 'hidden sm:flex'}`}>
return navigate('/login') medium text-gray-700'>{docInfo.name} <img className='w-5' <p onClick={() => speciality === 'General physician' ? export default Doctors
} src={assets.verified_icon} alt="" /></p> navigate('/doctors') : navigate('/doctors/General physician')}
<div className='flex items-center gap-2 mt-1 text- className={`w-[94vw] sm:w-auto pl-3 py-1.5 pr-16 border border-gray-300
const date = docSlots[slotIndex][0].datetime gray-600'> rounded transition-all cursor-pointer ${speciality === 'General
<p>{docInfo.degree} - {docInfo.speciality}</p> physician' ? 'bg-[#E2E5FF] text-black ' : ''}`}>General physician</p>
let day = date.getDate() <button className='py-0.5 px-2 border text-xs <p onClick={() => speciality === 'Gynecologist' ?
let month = date.getMonth() + 1 rounded-full'>{docInfo.experience}</button> navigate('/doctors') : navigate('/doctors/Gynecologist')} className={`w-
let year = date.getFullYear() </div> [94vw] sm:w-auto pl-3 py-1.5 pr-16 border border-gray-300 rounded
transition-all cursor-pointer ${speciality === 'Gynecologist' ? 'bg-
const slotDate = day + "_" + month + "_" + year {/* ----- Doc About ----- */} [#E2E5FF] text-black ' : ''}`}>Gynecologist</p>
<div> <p onClick={() => speciality === 'Dermatologist' ?
try { <p className='flex items-center gap-1 text-sm navigate('/doctors') : navigate('/doctors/Dermatologist')} className={`w-
font-medium text-[#262626] mt-3'>About <img className='w-3' [94vw] sm:w-auto pl-3 py-1.5 pr-16 border border-gray-300 rounded
const { data } = await axios.post(backendUrl + src={assets.info_icon} alt="" /></p> transition-all cursor-pointer ${speciality === 'Dermatologist' ? 'bg-
'/api/user/book-appointment', { docId, slotDate, slotTime }, { headers: { <p className='text-sm text-gray-600 max-w-[700px] [#E2E5FF] text-black ' : ''}`}>Dermatologist</p>
token } }) mt-1'>{docInfo.about}</p> <p onClick={() => speciality === 'Pediatricians' ?
if (data.success) { </div> navigate('/doctors') : navigate('/doctors/Pediatricians')} className={`w-
toast.success(data.message) [94vw] sm:w-auto pl-3 py-1.5 pr-16 border border-gray-300 rounded
getDoctosData() <p className='text-gray-600 font-medium mt- transition-all cursor-pointer ${speciality === 'Pediatricians' ? 'bg-
navigate('/my-appointments') 4'>Appointment fee: <span className='text-gray- [#E2E5FF] text-black ' : ''}`}>Pediatricians</p>
} else { 800'>{currencySymbol}{docInfo.fees}</span> </p> <p onClick={() => speciality === 'Neurologist' ?
toast.error(data.message) </div> navigate('/doctors') : navigate('/doctors/Neurologist')} className={`w-
} </div> [94vw] sm:w-auto pl-3 py-1.5 pr-16 border border-gray-300 rounded
{/* Booking slots */} import React from 'react' import React from 'react' import React, { useContext, useEffect, useState } from 'react'
<div className='sm:ml-72 sm:pl-4 mt-8 font-medium text- import { assets } from '../assets/assets' import Header from '../components/Header' import { AppContext } from '../context/AppContext'
[#565656]'> import SpecialityMenu from '../components/SpecialityMenu' import axios from 'axios'
<p >Booking slots</p> const Contact = () => { import TopDoctors from '../components/TopDoctors' import { toast } from 'react-toastify'
<div className='flex gap-3 items-center w-full overflow- return ( import Banner from '../components/Banner' import { useNavigate } from 'react-router-dom'
x-scroll mt-4'> <div>
{docSlots.length && docSlots.map((item, index) => ( const Home = () => { const Login = () => {
<div onClick={() => setSlotIndex(index)} <div className='text-center text-2xl pt-10 text-[#707070]'> return (
key={index} className={`text-center py-6 min-w-16 rounded-full cursor- <p>CONTACT <span className='text-gray-700 font- <div> const [state, setState] = useState('Sign Up')
pointer ${slotIndex === index ? 'bg-primary text-white' : 'border border- semibold'>US</span></p> <Header />
[#DDDDDD]'}`}> </div> <SpecialityMenu /> const [name, setName] = useState('')
<p>{item[0] && <TopDoctors /> const [email, setEmail] = useState('')
daysOfWeek[item[0].datetime.getDay()]}</p> <div className='my-10 flex flex-col justify-center md:flex-row gap- <Banner /> const [password, setPassword] = useState('')
<p>{item[0] && 10 mb-28 text-sm'> </div>
item[0].datetime.getDate()}</p> <img className='w-full md:max-w-[360px]' ) const navigate = useNavigate()
</div> src={assets.contact_image} alt="" /> } const { backendUrl, token, setToken } = useContext(AppContext)
))} <div className='flex flex-col justify-center items-start gap-6'>
</div> <p className=' font-semibold text-lg text-gray-600'>OUR export default Home const onSubmitHandler = async (event) => {
OFFICE</p> event.preventDefault();
<div className='flex items-center gap-3 w-full overflow- <p className=' text-gray-500'>54709 Willms Station <br /> Suite
x-scroll mt-4'> 350, Washington, USA</p> if (state === 'Sign Up') {
{docSlots.length && docSlots[slotIndex].map((item, <p className=' text-gray-500'>Tel: (415) 555-0132 <br /> Email:
index) => ( [email protected]</p> const { data } = await axios.post(backendUrl +
<p onClick={() => setSlotTime(item.time)} <p className=' font-semibold text-lg text-gray-600'>CAREERS AT '/api/user/register', { name, email, password })
key={index} className={`text-sm font-light flex-shrink-0 px-5 py-2 PRESCRIPTO</p>
rounded-full cursor-pointer ${item.time === slotTime ? 'bg-primary text- <p className=' text-gray-500'>Learn more about our teams and if (data.success) {
white' : 'text-[#949494] border border- job openings.</p> localStorage.setItem('token', data.token)
[#B4B4B4]'}`}>{item.time.toLowerCase()}</p> <button className='border border-black px-8 py-4 text-sm setToken(data.token)
))} hover:bg-black hover:text-white transition-all duration-500'>Explore } else {
</div> Jobs</button> toast.error(data.message)
</div> }
<button onClick={bookAppointment} className='bg-primary </div>
text-white text-sm font-light px-20 py-3 rounded-full my-6'>Book an } else {
appointment</button> </div>
</div> ) const { data } = await axios.post(backendUrl + '/api/user/login', {
} email, password })
{/* Listing Releated Doctors */}
<RelatedDoctors speciality={docInfo.speciality} docId={docId} export default Contact if (data.success) {
/> localStorage.setItem('token', data.token)
</div> setToken(data.token)
) : null } else {
} toast.error(data.message)
}
export default Appointment
}
useEffect(() => {
if (token) {
navigate('/')
}
}, [token])
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'>{state === 'Sign Up' ? import React, { useContext, useEffect, useState } from 'react' {!item.cancelled && item.payment && import React, { useContext, useEffect, useState } from 'react'
'Create Account' : 'Login'}</p> import { useNavigate } from 'react-router-dom' !item.isCompleted && <button className='sm:min-w-48 py-2 border rounded import { AppContext } from '../context/AppContext'
<p>Please {state === 'Sign Up' ? 'sign up' : 'log in'} to book import { AppContext } from '../context/AppContext' text-[#696969] bg-[#EAEFFF]'>Paid</button>} import axios from 'axios'
appointment</p> import axios from 'axios' import { toast } from 'react-toastify'
{state === 'Sign Up' import { toast } from 'react-toastify' {item.isCompleted && <button import { assets } from '../assets/assets'
? <div className='w-full '> import { assets } from '../assets/assets' className='sm:min-w-48 py-2 border border-green-500 rounded text-green-
<p>Full Name</p> 500'>Completed</button>} const MyProfile = () => {
<input onChange={(e) => setName(e.target.value)} value={name} const MyAppointments = () => {
className='border border-[#DADADA] rounded w-full p-2 mt-1' type="text" {!item.cancelled && !item.isCompleted && const [isEdit, setIsEdit] = useState(false)
required /> const { backendUrl, token } = useContext(AppContext) <button onClick={() => cancelAppointment(item._id)} className='text-
</div> const navigate = useNavigate() [#696969] sm:min-w-48 py-2 border rounded hover:bg-red-600 hover:text- const [image, setImage] = useState(false)
: null white transition-all duration-300'>Cancel appointment</button>}
} const [appointments, setAppointments] = useState([]) {item.cancelled && !item.isCompleted && const { token, backendUrl, userData, setUserData, loadUserProfileData
<div className='w-full '> const [payment, setPayment] = useState('') <button className='sm:min-w-48 py-2 border border-red-500 rounded text- } = useContext(AppContext)
<p>Email</p> red-500'>Appointment cancelled</button>}
<input onChange={(e) => setEmail(e.target.value)} value={email} const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", </div> // Function to update user profile data using API
className='border border-[#DADADA] rounded w-full p-2 mt-1' type="email" "Aug", "Sep", "Oct", "Nov", "Dec"]; </div> const updateUserProfileData = async () => {
required /> ))}
</div> // Function to format the date eg. ( 20_01_2000 => 20 Jan 2000 ) </div> try {
<div className='w-full '> const slotDateFormat = (slotDate) => { </div>
<p>Password</p> const dateArray = slotDate.split('_') ) const formData = new FormData();
<input onChange={(e) => setPassword(e.target.value)} return dateArray[0] + " " + months[Number(dateArray[1])] + " " + }
value={password} className='border border-[#DADADA] rounded w-full p-2 dateArray[2] formData.append('name', userData.name)
mt-1' type="password" required /> } export default MyAppointments formData.append('phone', userData.phone)
</div> formData.append('address', JSON.stringify(userData.address))
<button className='bg-primary text-white w-full py-2 my-2 // Getting User Appointments Data Using API formData.append('gender', userData.gender)
rounded-md text-base'>{state === 'Sign Up' ? 'Create account' : const getUserAppointments = async () => { formData.append('dob', userData.dob)
'Login'}</button> try {
{state === 'Sign Up' image && formData.append('image', image)
? <p>Already have an account? <span onClick={() => const { data } = await axios.get(backendUrl +
setState('Login')} className='text-primary underline cursor- '/api/user/appointments', { headers: { token } }) const { data } = await axios.post(backendUrl +
pointer'>Login here</span></p> setAppointments(data.appointments.reverse()) '/api/user/update-profile', formData, { headers: { token } })
: <p>Create an new account? <span onClick={() => setState('Sign
Up')} className='text-primary underline cursor-pointer'>Click } catch (error) { if (data.success) {
here</span></p> console.log(error) toast.success(data.message)
} toast.error(error.message) await loadUserProfileData()
</div> } setIsEdit(false)
</form> } setImage(false)
) } else {
} // Function to cancel appointment Using API toast.error(data.message)
const cancelAppointment = async (appointmentId) => { }
export default Login
try { } catch (error) {
console.log(error)
const { data } = await axios.post(backendUrl + toast.error(error.message)
'/api/user/cancel-appointment', { appointmentId }, { headers: { token } }
})
}
if (data.success) {
toast.success(data.message) return userData ? (
getUserAppointments() <div className='max-w-lg flex flex-col gap-2 text-sm pt-5'>
} else {
toast.error(data.message) {isEdit
} ? <label htmlFor='image' >
<div className='inline-block relative cursor-
} catch (error) { pointer'>
console.log(error) <img className='w-36 rounded opacity-75'
toast.error(error.message) src={image ? URL.createObjectURL(image) : userData.image} alt="" />
} <img className='w-10 absolute bottom-12 right-12'
src={image ? '' : assets.upload_icon} alt="" />
} console.log(error) </div>
toast.error(error.message) <input onChange={(e) => setImage(e.target.files[0])} {isEdit
const initPay = (order) => { } type="file" id="image" hidden /> ? <select className='max-w-20 bg-gray-50'
const options = { } </label> onChange={(e) => setUserData(prev => ({ ...prev, gender: e.target.value
key: import.meta.env.VITE_RAZORPAY_KEY_ID, : <img className='w-36 rounded' src={userData.image} }))} value={userData.gender} >
amount: order.amount, alt="" /> <option value="Not Selected">Not
currency: order.currency, } Selected</option>
name: 'Appointment Payment', useEffect(() => { <option value="Male">Male</option>
description: "Appointment Payment", if (token) { {isEdit <option value="Female">Female</option>
order_id: order.id, getUserAppointments() ? <input className='bg-gray-50 text-3xl font-medium max- </select>
receipt: order.receipt, } w-60' type="text" onChange={(e) => setUserData(prev => ({ ...prev, name: : <p className='text-gray-
handler: async (response) => { }, [token]) e.target.value }))} value={userData.name} /> 500'>{userData.gender}</p>
: <p className='font-medium text-3xl text-[#262626] mt- }
console.log(response) return ( 4'>{userData.name}</p>
<div> } <p className='font-medium'>Birthday:</p>
try { <p className='pb-3 mt-12 text-lg font-medium text-gray-600
const { data } = await axios.post(backendUrl + border-b'>My appointments</p> <hr className='bg-[#ADADAD] h-[1px] border-none' /> {isEdit
"/api/user/verifyRazorpay", response, { headers: { token } }); <div className=''> ? <input className='max-w-28 bg-gray-50'
if (data.success) { {appointments.map((item, index) => ( <div> type='date' onChange={(e) => setUserData(prev => ({ ...prev, dob:
navigate('/my-appointments') <div key={index} className='grid grid-cols-[1fr_2fr] <p className='text-gray-600 underline mt-3'>CONTACT e.target.value }))} value={userData.dob} />
getUserAppointments() gap-4 sm:flex sm:gap-6 py-4 border-b'> INFORMATION</p> : <p className='text-gray-500'>{userData.dob}</p>
} <div> <div className='grid grid-cols-[1fr_3fr] gap-y-2.5 mt-3 }
} catch (error) { <img className='w-36 bg-[#EAEFFF]' text-[#363636]'>
console.log(error) src={item.docData.image} alt="" /> <p className='font-medium'>Email id:</p> </div>
toast.error(error.message) </div> <p className='text-blue-500'>{userData.email}</p> </div>
} <div className='flex-1 text-sm text-[#5E5E5E]'> <p className='font-medium'>Phone:</p> <div className='mt-10'>
} <p className='text-[#262626] text-base font-
}; semibold'>{item.docData.name}</p> {isEdit {isEdit
const rzp = new window.Razorpay(options); <p>{item.docData.speciality}</p> ? <input className='bg-gray-50 max-w-52' ? <button onClick={updateUserProfileData}
rzp.open(); <p className='text-[#464646] font-medium mt- type="text" onChange={(e) => setUserData(prev => ({ ...prev, phone: className='border border-primary px-8 py-2 rounded-full hover:bg-primary
}; 1'>Address:</p> e.target.value }))} value={userData.phone} /> hover:text-white transition-all'>Save information</button>
<p : <p className='text-blue- : <button onClick={() => setIsEdit(true)}
// Function to make payment using razorpay className=''>{item.docData.address.line1}</p> 500'>{userData.phone}</p> className='border border-primary px-8 py-2 rounded-full hover:bg-primary
const appointmentRazorpay = async (appointmentId) => { <p } hover:text-white transition-all'>Edit</button>
try { className=''>{item.docData.address.line2}</p> }
const { data } = await axios.post(backendUrl + <p className=' mt-1'><span className='text-sm <p className='font-medium'>Address:</p>
'/api/user/payment-razorpay', { appointmentId }, { headers: { token } }) text-[#3C3C3C] font-medium'>Date & Time:</span> </div>
if (data.success) { {slotDateFormat(item.slotDate)} | {item.slotTime}</p> {isEdit </div>
initPay(data.order) </div> ? <p> ) : null
}else{ <div></div> <input className='bg-gray-50' type="text" }
toast.error(data.message) <div className='flex flex-col gap-2 justify-end onChange={(e) => setUserData(prev => ({ ...prev, address: {
} text-sm text-center'> ...prev.address, line1: e.target.value } }))} export default MyProfile
} catch (error) { {!item.cancelled && !item.payment && value={userData.address.line1} />
console.log(error) !item.isCompleted && payment !== item._id && <button onClick={() => <br />
toast.error(error.message) setPayment(item._id)} className='text-[#696969] sm:min-w-48 py-2 border <input className='bg-gray-50' type="text"
} rounded hover:bg-primary hover:text-white transition-all duration- onChange={(e) => setUserData(prev => ({ ...prev, address: {
} 300'>Pay Online</button>} ...prev.address, line2: e.target.value } }))}
{!item.cancelled && !item.payment && value={userData.address.line2} /></p>
// Function to make payment using stripe !item.isCompleted && payment === item._id && <button onClick={() => : <p className='text-gray-
const appointmentStripe = async (appointmentId) => { appointmentStripe(item._id)} className='text-[#696969] sm:min-w-48 py-2 500'>{userData.address.line1} <br /> {userData.address.line2}</p>
try { border rounded hover:bg-gray-100 hover:text-white transition-all }
const { data } = await axios.post(backendUrl + duration-300 flex items-center justify-center'><img className='max-w-20
'/api/user/payment-stripe', { appointmentId }, { headers: { token } }) max-h-5' src={assets.stripe_logo} alt="" /></button>} </div>
if (data.success) { {!item.cancelled && !item.payment && </div>
const { session_url } = data !item.isCompleted && payment === item._id && <button onClick={() => <div>
window.location.replace(session_url) appointmentRazorpay(item._id)} className='text-[#696969] sm:min-w-48 py-2 <p className='text-[#797979] underline mt-3'>BASIC
}else{ border rounded hover:bg-gray-100 hover:text-white transition-all INFORMATION</p>
toast.error(data.message) duration-300 flex items-center justify-center'><img className='max-w-20 <div className='grid grid-cols-[1fr_3fr] gap-y-2.5 mt-3
} max-h-5' src={assets.razorpay_logo} alt="" /></button>} text-gray-600'>
} catch (error) { <p className='font-medium'>Gender:</p>
import axios from 'axios'; import React from 'react' import React, { useContext } from 'react' import React, { useContext } from 'react'
import React, { useContext, useEffect } from 'react' import ReactDOM from 'react-dom/client' import { assets } from '../assets/assets' import { assets } from '../assets/assets'
import { useNavigate, useSearchParams } from 'react-router-dom' import App from './App.jsx' import { DoctorContext } from '../context/DoctorContext' import { NavLink } from 'react-router-dom'
import { AppContext } from '../context/AppContext'; import './index.css' import { AdminContext } from '../context/AdminContext' import { DoctorContext } from '../context/DoctorContext'
import { toast } from 'react-toastify'; import { BrowserRouter } from 'react-router-dom' import { useNavigate } from 'react-router-dom' import { AdminContext } from '../context/AdminContext'
import AppContextProvider from './context/AppContext.jsx'
const Verify = () => { const Navbar = () => { const Sidebar = () => {
ReactDOM.createRoot(document.getElementById('root')).render(
const [searchParams, setSearchParams] = useSearchParams() <BrowserRouter> const { dToken, setDToken } = useContext(DoctorContext) const { dToken } = useContext(DoctorContext)
<AppContextProvider> const { aToken, setAToken } = useContext(AdminContext) const { aToken } = useContext(AdminContext)
const success = searchParams.get("success") <App />
const appointmentId = searchParams.get("appointmentId") </AppContextProvider> const navigate = useNavigate() return (
</BrowserRouter>, <div className='min-h-screen bg-white border-r'>
const { backendUrl, token } = useContext(AppContext) ) const logout = () => { {aToken && <ul className='text-[#515151] mt-5'>
navigate('/')
const navigate = useNavigate() dToken && setDToken('') <NavLink to={'/admin-dashboard'} className={({ isActive }) =>
dToken && localStorage.removeItem('dToken') `flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
// Function to verify stripe payment aToken && setAToken('') ${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
const verifyStripe = async () => { aToken && localStorage.removeItem('aToken') <img className='min-w-5' src={assets.home_icon} alt='' />
} <p className='hidden md:block'>Dashboard</p>
try { </NavLink>
return ( <NavLink to={'/all-appointments'} className={({ isActive }) =>
const { data } = await axios.post(backendUrl + <div className='flex justify-between items-center px-4 sm:px-10 py-3 `flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
"/api/user/verifyStripe", { success, appointmentId }, { headers: { token border-b bg-white'> ${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
} }) <div className='flex items-center gap-2 text-xs'> <img className='min-w-5' src={assets.appointment_icon} alt=''
<img onClick={() => navigate('/')} className='w-36 sm:w-40 />
if (data.success) { cursor-pointer' src={assets.admin_logo} alt="" /> <p className='hidden md:block'>Appointments</p>
toast.success(data.message) <p className='border px-2.5 py-0.5 rounded-full border-gray-500 </NavLink>
} else { text-gray-600'>{aToken ? 'Admin' : 'Doctor'}</p> <NavLink to={'/add-doctor'} className={({ isActive }) => `flex
toast.error(data.message) </div> items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
} <button onClick={() => logout()} className='bg-primary text-white ${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
text-sm px-10 py-2 rounded-full'>Logout</button> <img className='min-w-5' src={assets.add_icon} alt='' />
navigate("/my-appointments") </div> <p className='hidden md:block'>Add Doctor</p>
) </NavLink>
} catch (error) { } <NavLink to={'/doctor-list'} className={({ isActive }) => `flex
toast.error(error.message) items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
console.log(error) export default Navbar ${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>}
useEffect(() => {
if (token, appointmentId, success) { {dToken && <ul className='text-[#515151] mt-5'>
verifyStripe() <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
}, [token]) ${isActive ? 'bg-[#F2F3FF] border-r-4 border-primary' : ''}`}>
<img className='min-w-5' src={assets.home_icon} alt='' />
return ( <p className='hidden md:block'>Dashboard</p>
<div className='min-h-[60vh] flex items-center justify-center'> </NavLink>
<div className="w-20 h-20 border-4 border-gray-300 border-t-4 <NavLink to={'/doctor-appointments'} className={({ isActive }) =>
border-t-primary rounded-full animate-spin"></div> `flex items-center gap-3 py-3.5 px-3 md:px-9 md:min-w-72 cursor-pointer
</div> ${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>
export default Verify </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='' />
import React from 'react' VITE_BACKEND_URL = 'http://localhost:4000' <p className='hidden md:block'>Profile</p> import axios from "axios";
import Navbar from './components/Navbar' VITE_RAZORPAY_KEY_ID = '------ Razorpay Key Id here ------' </NavLink> import { createContext, useState } from "react";
import { Routes, Route } from 'react-router-dom' </ul>} import { toast } from "react-toastify";
import Home from './pages/Home' </div>
import Doctors from './pages/Doctors' )
import Login from './pages/Login' } export const AdminContext = createContext()
import About from './pages/About'
import Contact from './pages/Contact' export default Sidebar const AdminContextProvider = (props) => {
import Appointment from './pages/Appointment'
import MyAppointments from './pages/MyAppointments' const backendUrl = import.meta.env.VITE_BACKEND_URL
import MyProfile from './pages/MyProfile'
import Footer from './components/Footer' const [aToken, setAToken] = useState(localStorage.getItem('aToken') ?
import { ToastContainer } from 'react-toastify'; localStorage.getItem('aToken') : '')
import 'react-toastify/dist/ReactToastify.css';
import Verify from './pages/Verify' const [appointments, setAppointments] = useState([])
const [doctors, setDoctors] = useState([])
const App = () => { const [dashData, setDashData] = useState(false)
return (
<div className='mx-4 sm:mx-[10%]'> // Getting all Doctors data from Database using API
<ToastContainer /> const getAllDoctors = async () => {
<Navbar />
<Routes> try {
<Route path='/' element={<Home />} />
<Route path='/doctors' element={<Doctors />} /> const { data } = await axios.get(backendUrl +
<Route path='/doctors/:speciality' element={<Doctors />} /> '/api/admin/all-doctors', { headers: { aToken } })
<Route path='/login' element={<Login />} /> if (data.success) {
<Route path='/about' element={<About />} /> setDoctors(data.doctors)
<Route path='/contact' element={<Contact />} /> } else {
<Route path='/appointment/:docId' element={<Appointment />} /> toast.error(data.message)
<Route path='/my-appointments' element={<MyAppointments />} /> }
<Route path='/my-profile' element={<MyProfile />} />
<Route path='/verify' element={<Verify />} /> } catch (error) {
</Routes> toast.error(error.message)
<Footer /> }
</div>
) }
}
// Function to change doctor availablity using API
export default App const changeAvailability = async (docId) => {
try {
} catch (error) {
console.log(error)
toast.error(error.message)
}
}
if (data.success) {
toast.success(data.message)
getAllAppointments()
} else {
toast.error(data.message) const logout = () => {
}
} catch (error) {
navigate('/')
toast.error(error.message)
console.log(error) dToken && setDToken('')
dToken && localStorage.removeItem('dToken')
}
return (
setDashData(data.dashData)
} else {
toast.error(data.message)
}
<div className='flex justify-between items-center px-4 sm:px-10 py-3
} catch (error) {
console.log(error) border-b bg-white'>
toast.error(error.message)
} <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>
import { createContext } from "react"; )
export const AppContext = createContext()
}
const AppContextProvider = (props) => {
const value = {
backendUrl,
currency,
slotDateFormat,
calculateAge,
}
return (
<AppContext.Provider value={value}>
{props.children}
</AppContext.Provider>
)
return (
<div className='min-h-screen bg-white border-r'>
{aToken && <ul className='text-[#515151] mt-5'>
export default AdminContextProvider // 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>
)
try {
if (!docImg) {
return toast.error('Image Not Selected')
}
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 }))
useEffect(() => {
if (aToken) {
getDashData()
}
}, [aToken])
<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>
return (
<div className='w-full max-w-6xl m-5 '>
<div className='bg-white'>
<div className='flex items-center gap-2.5 px-4 py-4 mt-10
rounded-t border'>
} else {
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>
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<AdminContextProvider>
<DoctorContextProvider>
<AppContextProvider>
<App />
</AppContextProvider>
</DoctorContextProvider>
</AdminContextProvider>
</BrowserRouter>,
)
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
rules: {
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}