Skip to content

Commit

Permalink
currently working admin dashboard completed hospitals , doctors and p…
Browse files Browse the repository at this point in the history
…atient crud with their validation
  • Loading branch information
miirshe committed Dec 23, 2023
1 parent 158192e commit 3b7b4f3
Show file tree
Hide file tree
Showing 18 changed files with 1,034 additions and 118 deletions.
255 changes: 194 additions & 61 deletions client/package-lock.json

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.19",
"@mui/material": "^5.14.20",
"@mui/x-data-grid": "^6.18.4",
"@mui/icons-material": "^5.15.1",
"@mui/material": "^5.15.1",
"@mui/styled-engine-sc": "^6.0.0-alpha.9",
"@mui/x-data-grid": "^6.18.6",
"@reduxjs/toolkit": "^2.0.1",
"axios": "^1.6.2",
"formik": "^2.4.5",
"moment": "^2.29.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-icons": "^4.12.0",
"react-multi-carousel": "^2.8.4",
"react-redux": "^9.0.3",
"react-router-dom": "^6.20.1",
"styled-components": "^6.1.3",
"yup": "^1.3.2"
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions client/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body{
background-color: #F8F9FA;
}
17 changes: 13 additions & 4 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Route, Routes } from "react-router-dom"
import { Toaster } from 'react-hot-toast';
import {
About, Contact, Dashboard,
About, AddDoctor, AddHospital, AddPatients, Contact, Dashboard,
DashboardLayout, DoctorLogin,
DoctorRegister, Home, PageLayouts,
PatientLogin, PatientRegister
DoctorRegister, Doctors, Home, HospitalList, PageLayouts,
PatientLogin, PatientRegister, Patients
} from "./ExportFiles";
const App = () => {
return (
Expand All @@ -23,7 +23,16 @@ const App = () => {

<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<Dashboard />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="hospitals" element={<HospitalList />} />
<Route path="add-hospital" element={<AddHospital />} />
<Route path="add-hospital/:id" element={<AddHospital />} />
<Route path="doctors" element={<Doctors />} />
<Route path="add-doctor" element={<AddDoctor />} />
<Route path="add-doctor/:id" element={<AddDoctor />} />
<Route path="patients" element={<Patients />} />
<Route path="add-patient" element={<AddPatients />} />
<Route path="add-patient/:id" element={<AddPatients />} />
</Route>
</Routes>
<Toaster />
Expand Down
8 changes: 7 additions & 1 deletion client/src/ExportFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ export { default as PatientRegister } from './auth/PatientRegister'
export { default as DashboardLayout } from './dashboard/DashboardLayout'
export { default as Dashboard } from './dashboard/Dashboard'
export { default as DashboardSideBar } from './dashboard/DashboardSideBar'
export { default as DashboardHeader } from './dashboard/DashboardHeader'
export { default as DashboardHeader } from './dashboard/DashboardHeader'
export { default as HospitalList } from './dashboard/HospitalList'
export { default as AddHospital } from './dashboard/AddHospital'
export { default as Doctors } from './dashboard/Doctors'
export { default as AddDoctor } from './dashboard/AddDoctor'
export { default as Patients } from './dashboard/Patients'
export { default as AddPatients } from './dashboard/AddPatients'
2 changes: 1 addition & 1 deletion client/src/auth/DoctorRegister.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const DoctorRegister = () => {
const { name, email, password, address, phone, description, hos_name } = values;
registerDoctor({
name: name, email: email, password: password, address: address, phone: phone,
description: description, hos_id: hos_name, image: image
description: description, hos_id: hos_name, image: image , status: 'unverified'
}).then((res) => {
const status = res?.data?.status;
const message = res?.data?.data;
Expand Down
2 changes: 1 addition & 1 deletion client/src/auth/PatientRegister.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const PatientRegister = () => {
const status = res.data.status;
if(status){
toast.success(res?.data?.data);
navigate('/dashboard')
navigate('/')
}else{
toast.error(res?.data?.data);
}
Expand Down
196 changes: 196 additions & 0 deletions client/src/dashboard/AddDoctor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import { ErrorMessage, Field, Formik, Form } from "formik"
import { useEffect, useRef, useState } from "react"
import { Link, useLocation } from "react-router-dom"
import * as Yup from 'yup'
import { IoCloudUploadOutline } from 'react-icons/io5';
import { useGetHospitalsQuery } from "../redux/slices/HospitalSlices"
import { useRegisterDoctorMutation, useUpdateDoctorMutation } from "../redux/slices/DoctorSlices"
import toast from "react-hot-toast"
import { MdArrowBack } from "react-icons/md";
const AddDoctor = () => {
const doctorsData = useLocation().state;
const [registerDoctor] = useRegisterDoctorMutation();
const [updateDoctor] = useUpdateDoctorMutation();
const { data: hospitals = [] } = useGetHospitalsQuery();
console.log('hospitals', hospitals);
const getHospitalNames = hospitals?.data || [];
console.log(getHospitalNames);
const initialRegister = {
name: doctorsData?.name || '',
email: doctorsData?.email || '',
phone: doctorsData?.phone || '',
address: doctorsData?.address || '',
description: doctorsData?.description || '',
hos_name: '',
status : doctorsData?.status || '',
}
const validationSchema = Yup.object({
name: Yup.string().required('name field is required'),
email: Yup.string().required('email field is required'),
phone: Yup.number().required('phone field is required'),
address: Yup.string().required('address field is required'),
password: !doctorsData?.id && Yup.string().required('password field is required'),
description: Yup.string().required('description field is required'),
hos_name: Yup.string().required('hos_name field is required'),
})

const [images, setImages] = useState(null);
const cloudinaryRef = useRef();
const widgetRef = useRef();
console.log('my images', images);
const setupCloudinaryWidget = () => {
if (window.cloudinary) {
cloudinaryRef.current = window.cloudinary;
widgetRef.current = cloudinaryRef.current.createUploadWidget(
{
cloudName: import.meta.env.VITE_APP_CLOUD_NAME,
uploadPreset: import.meta.env.VITE_APP_UPLOAD_PRESET,
maxFiles: 1,
},
(err, result) => {
if (err) {
console.error(err);
} else if (result.event === "success") {
// setImages((prevImages) => [...prevImages, result.info.secure_url]);
setImages(result.info.secure_url);
}
}
);
}
};

useEffect(() => {
setupCloudinaryWidget();
}, []);


const handleImageUpload = () => {
widgetRef.current?.open();
};

const handleSubmit = (values) => {
const image = images;
const { name, email, password, address, phone, description, hos_name, status } = values;
if (!doctorsData?.id) {
registerDoctor({
name: name, email: email, password: password, address: address, phone: phone,
description: description, hos_id: hos_name, status: status ,image: image
}).then((res) => {
const status = res?.data?.status;
const message = res?.data?.data;
if (status) {
toast.success(message);
} else {
toast.error(message);
}
}).catch((err) => {
console.log(err?.message);
});
} else {
updateDoctor({
id: doctorsData?.id,
updateDoctor: {
name: name, email: email, password: password, address: address, phone: phone,
description: description, hos_id: hos_name, image: image,status: status
}
}).then((res) => {
const status = res?.data?.status;
const message = res?.data?.data;
if (status) {
toast.success(message);
} else {
toast.error(message);
}
}).catch((err) => {
console.log(err);
});
}
}
return (
<div className="w-full lg:w-[85%] p-2 mt-10 mx-auto">
<div className="w-full flex flex-col md:flex-row justify-start items-start md:justify-between md:items-center gap-5">
<div className="flex flex-row justify-start items-center gap-3 text-xs font-light lg:text-base">
<Link to='/'> <span className="text-blue-600">Home</span> / </Link>
<Link className="hover:text-blue-600" to='/dashboard'> Dashboard </Link>
<span> / Doctors </span>
</div>
<Link className="px-3 py-2 rounded shadow bg-blue-600 text-white" to='/dashboard/doctors'><MdArrowBack className="inline" size={20} /> <span> Back </span></Link>
</div>
<div className="w-full md:w-[30%] mx-auto p-3 rounded">
<button onClick={handleImageUpload}>
<IoCloudUploadOutline size={100} />
</button>
<p className="w-full text-center text-2xl"> Upload Image</p>
</div>
<Formik enableReinitialize onSubmit={handleSubmit} validationSchema={validationSchema} initialValues={initialRegister}>
<Form className="w-full space-y-3 p-3 rounded shadow mt-5 bg-[#FFFFFF]">
<div className="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
<div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Name</label>
<Field type="text" className="w-full px-3 py-2 rounded border outline-blue-600" name='name' placeholder="Enter Name" />
<ErrorMessage name="name" component="div" className="text-red-500" />
</div>
<div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Email</label>
<Field type="text" className="w-full px-3 py-2 rounded border outline-blue-600" name='email' placeholder="Enter Email" />
<ErrorMessage name="email" component="div" className="text-red-500" />
</div>
<div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Phone</label>
<Field type="number" className="w-full px-3 py-2 rounded border outline-blue-600" name='phone' placeholder="Enter Phone" />
<ErrorMessage name="phone" component="div" className="text-red-500" />
</div>
</div>
<div className={`w-full grid grid-cols-1 gap-3 ${!doctorsData?.id ? 'md:grid-cols-2' : 'grid-cols-1'}`}>
<div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Address</label>
<Field type="text" className="w-full px-3 py-2 rounded border outline-blue-600" name='address' placeholder="Enter Address" />
<ErrorMessage name="address" component="div" className="text-red-500" />
</div>
{
!doctorsData?.id && <div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Password</label>
<Field type="password" className="w-full px-3 py-2 rounded border outline-blue-600" name='password' placeholder="Enter Password" />
<ErrorMessage name='password' component="div" className="text-red-500" />
</div>
}

</div>

<div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Description</label>
<Field as="textarea" rows="4" className="w-full px-3 py-2 rounded border outline-blue-600" name='description' placeholder="Enter Description" />
<ErrorMessage name="description" component="div" className="text-red-500" />
</div>
<div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Hospital Name</label>
<Field as="select" rows="4" className="w-full px-3 py-2 rounded border outline-blue-600" name='hos_name'>
<option value="">-select hospital name--</option>
{
getHospitalNames?.map(hospitals => {
return (
<option value={hospitals?.id} key={hospitals?.id}>{hospitals?.name}</option>
)
})
}
</Field>
<ErrorMessage name="hos_name" component="div" className="text-red-500" />
</div>
<div className="w-full space-y-3">
<label htmlFor="" className="text-base font-medium ml-1">Status</label>
<Field as="select" rows="4" className="w-full px-3 py-2 rounded border outline-blue-600" name='status'>
<option value="">-select Status--</option>
<option value="verified">Verified</option>
<option value="unverified">Unverified</option>
</Field>
<ErrorMessage name="status" component="div" className="text-red-500" />
</div>
<button className="w-full md:w-fit px-3 py-2 bg-blue-600 text-white rounded hover:bg-white hover:text-blue-600
transition-all ease-in-out" type="submit">{ !doctorsData?.id ? 'Register Now ': 'Update Now'}</button>
</Form>
</Formik>
</div>
)
}

export default AddDoctor
Loading

0 comments on commit 3b7b4f3

Please sign in to comment.