Code Monkey home page Code Monkey logo

copilot-and-sons-clinic's Introduction

Typing SVG

Copilot & Sons: El7a2ny Clinic

Table of Contents

  1. ๐Ÿš€ Motivation
  2. ๐Ÿงฑ Build Status
  3. ๐ŸŽจ Code Style
  4. โš’๏ธ Tech and Frameworks used
  5. ๐Ÿ”ฅ Features & Screenshots
  6. ๐Ÿ’ป Code Examples
  7. โš™๏ธ Installation
  8. ๐Ÿ“š API Reference
  9. ๐Ÿงช Tests
  10. ๐Ÿง‘๐Ÿปโ€๐Ÿซ How to Use
  11. ๐Ÿค Contribute
  12. ยฉ๏ธ Credits
  13. ๐Ÿ“œ License

๐Ÿš€ Motivation

Welcome to Copilot & Sons El7a2ny Clinic, a cutting-edge virtual clinic management software. This project is driven by the vision to enhance the healthcare experience for clinics, doctors, and patients by introducing a comprehensive platform that simplifies and automates key interactions within the healthcare ecosystem.

๐Ÿงฑ Build Status

example workflow

  • This project is under development and should not be used in a production settings
  • Check Issues for a list of all the reported issues
  • More automated tests should be added in the future
  • More documentation should be added

๐ŸŽจ Code Style

We use Prettier and ESLint to enforce a consistent code style. We use an edited version of the default ESLint TypeScript config. You can check the config in the .eslintrc.js file.

Useful Commands

Useful Commands

  • Check formatting using Prettier
npm run format
  • And then fix formatting using Prettier
npm run format:fix
  • Check linting using ESLint
npm run lint
  • And then fix linting using ESLint
npm run lint:fix
  • Check compilation of all subpackages using TypeScript
npm run compile:all

โš’๏ธ Tech and Frameworks used

๐Ÿ”ฅ Features & Screenshots

User Registration ๐Ÿ“
  • Register as a patient with essential details.
  • Upload/remove medical documents (PDF, JPEG, JPG, PNG).
  • Submit a request to register as a doctor with professional details.
  • Upload required documents for doctor registration. image
User Authentication ๐Ÿ” - Login and logout securely.

image

Administrator Functions ๐Ÿ‘ฉโ€๐Ÿ’ผ - Add/remove another administrator. - Manage doctors and patients. - Accept or reject doctor registration requests. - View information uploaded by doctors.

image

Health Packages ๐Ÿ’ผ - Administrators can add/update/delete health packages with different price ranges.

image

Account Management ๐Ÿ”„ - Change password. - Reset forgotten password via email. - Edit/update email, hourly rate, or affiliation.

image

Doctor Functions ๐Ÿฉบ - Accept employment contract. - Add available time slots for appointments. - View information and health records of registered patients. - View a list of all patients.

image

Patient Functions ๐Ÿค’ - Add family members and link accounts. - Pay for appointments using wallet or credit card. - Subscribe to health packages for self and family. - View subscribed health packages and subscription status. - Cancel a subscription.

image

Appointment Management ๐Ÿ“… - Filter appointments by date/status. - View upcoming/past appointments. - Patient can reschedule or cancel appointments. - Doctor can reschedule appointments for patients.

image

Prescription Management ๐Ÿ’Š - Doctor can add/delete medicine to/from prescriptions. - Doctor can add/update dosage for each medicine. - Patients can view and filter prescriptions based on various criteria.

image

Wallet Management ๐Ÿ’ฐ - Receive a refund in the wallet for canceled appointments. - View the amount in the wallet.

image

Communication ๐Ÿ“ฌ - Patients and doctors can chat with each other. - Doctors and Patients can start/end video calls.

image

๐Ÿ’ป Code Examples

BE Routes Example
router.use('/auth', authRouter)
router.use('/doctors', doctorsRouter)

router.use('/debug', debugRouter)

router.use('/prescriptions', prescriptionsRouter)
router.use('/family-members', familyMemberRouter)
router.use('/health-packages', healthPackagesRouter)
router.use('/patients', patientRouter)
router.use('/appointment', appointmentsRouter)
router.use('/admins', asyncWrapper(allowAdmins), adminRouter)
BE Add Health Package Controller Example
export const healthPackagesRouter = Router()

healthPackagesRouter.post(
  '/',
  asyncWrapper(allowAdmins),
  validate(CreateHealthPackageRequestValidator),
  asyncWrapper<createHealthPackageRequest>(async (req, res) => {
    const healthPackage = await addHealthPackages(req.body)

    res.send({
      name: healthPackage.name,
      id: healthPackage.id,
      pricePerYear: healthPackage.pricePerYear,
      sessionDiscount: healthPackage.sessionDiscount,
      medicineDiscount: healthPackage.medicineDiscount,
      familyMemberSubscribtionDiscount:
        'healthPackage'.familyMemberSubscribtionDiscount,
    } satisfies AddHealthPackageResponse)
  })
)
BE Add Health Package Service Example
export async function addHealthPackages(
  request: createHealthPackageRequest
): Promise<HydratedDocument<HealthPackageDocument>> {
  const healthPackage = await HealthPackageModel.create({
    name: request.name,
    pricePerYear: request.pricePerYear,
    sessionDiscount: request.sessionDiscount,
    medicineDiscount: request.medicineDiscount,
    familyMemberSubscribtionDiscount: request.familyMemberSubscribtionDiscount,
  })

  return healthPackage
}
BE Health Package Model Example
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const healthPackageSchema = new Schema(
  {
    name: { type: String, required: true, unique: true },
    pricePerYear: { type: Number, required: true },
    sessionDiscount: { type: Number, required: true },
    medicineDiscount: { type: Number, required: true },
    familyMemberSubscribtionDiscount: {
      type: Number,
      required: true,
    },
  },
  { timestamps: true }
)

export type HealthPackageDocument = mongoose.InferSchemaType<
  typeof healthPackageSchema
>

export const HealthPackageModel = mongoose.model(
  'HealthPackage',
  healthPackageSchema
)
Add Health Package Validator Example
import * as zod from 'zod'

export const CreateHealthPackageRequestValidator = zod.object({
  name: zod.string().min(1),
  pricePerYear: zod.number(),
  sessionDiscount: zod.number(),
  medicineDiscount: zod.number(),
  familyMemberSubscribtionDiscount: zod.number(),
})
Health Package TypeScript Types Example
export type createHealthPackageRequest = z.infer<
  typeof CreateHealthPackageRequestValidator
>

export type UpdateHealthPackageRequest = z.infer<
  typeof UpdateHealthPackageRequestValidator
>

export interface HealthPackageResponseBase {
  name: string
  id: string
  pricePerYear: number
  sessionDiscount: number
  medicineDiscount: number
  familyMemberSubscribtionDiscount: number
}

export interface UpdateHealthPackageResponse
  extends HealthPackageResponseBase {}

export interface AddHealthPackageResponse extends HealthPackageResponseBase {}
FE Admin Dashboard Routes Example
export const adminDashboardRoutes: RouteObject[] = [
  {
    element: <AdminDashboardLayout />,
    children: [
      {
        path: '',
        element: <AdminDashboardHome />,
      },
      {
        path: 'change-password',
        element: <ChangePassword />,
      },

      {
        path: 'pending-doctors',
        element: <PendingDoctors />,
      },
      {
        path: 'pending-doctors/:username',
        element: <PendingDoctorDetails />,
      },
      {
        path: 'health-packages',
        element: <HealthPackages />,
      },
      {
        path: 'add-health-package',
        element: <AddHealthPackage />,
      },
      {
        path: 'update-health-package/:id',
        element: <UpdateHealthPackage />,
      },
      {
        path: 'add-admin',
        element: <AddAdmin />,
      },
      {
        path: 'add-admin',
        element: <AddAdmin />,
      },
      {
        path: 'users',
        element: <Users />,
      },
    ],
  },
]
FE Add Health Package Page Example
export function AddHealthPackage() {
  const navigate = useNavigate()

  return (
    <ApiForm<createHealthPackageRequest>
      fields={[
        { label: 'Name', property: 'name' },
        {
          label: 'Price Per Year',
          property: 'pricePerYear',
          valueAsNumber: true,
        },
        {
          label: 'Session Discount Percentage',
          property: 'sessionDiscount',
          valueAsNumber: true,
        },
        {
          label: 'Medicine Discount Percentage',
          property: 'medicineDiscount',
          valueAsNumber: true,
        },
        {
          label: 'Family Member Subscribtion Discount Percentage',
          property: 'familyMemberSubscribtionDiscount',
          valueAsNumber: true,
        },
      ]}
      validator={CreateHealthPackageRequestValidator}
      successMessage="Added health package successfully"
      action={(data) => addHealthPackage(data)}
      onSuccess={() => {
        navigate('/admin-dashboard/health-packages')
      }}
    />
  )
}

โš™๏ธ Installation

  • Make sure you have Node and Git installed

  • Make a new folder for the sub system of Clinic & Pharmacy

mkdir Copilot-and-Sons
cd Copilot-and-Sons
  • Clone this repo + pharmacy repo
git clone https://github.com/advanced-computer-lab-2023/Copilot-and-Sons-Clinic
git clone https://github.com/advanced-computer-lab-2023/Copilot-and-Sons-Pharmacy
  • Install dependencies for clinic
cd Copilot-and-Sons-Clinic
npm install
  • Install dependencies for pharmacy
cd ../Copilot-and-Sons-Pharmacy
npm install

๐Ÿ“š API Reference

Admin Endpoints
  • POST /admins - Add a new admin
    • Request body
      • username: string
      • password: string
      • email: string
    • Response: The created admin
  • GET /admins/get-users - Get all users
    • Response: A list of all users
    [
        {
            username: string,
            type: string
        }
    ]
    
  • DELETE /admins/username/:id - Delete a user by username
Appointment Endpoints
  • GET /appointment/filter - Returns a list of all appointments
    • Response Body
    [
        {
            'id': string,
            'patientID': string,
            'doctorID': string,
            'doctorName': string,
            'doctorTimes': string[],
            'date': string,
            'familyID': string,
            'reservedFor': string
            'status': AppointmentStatus
        }
    ]
    
  • POST /appointment/makeappointment - Reserve an appointment
    • Request Body
    {
        'doctorid': string,
        'date': Date | null,
        'familyID': string,
        'reservedFor': string,
        'toPayUsingWallet': number,
        'sessionPrice': number
    }
    
    • Response Body
    {
        'id': string,
        'patientID': string,
        'doctorID': string,
        'doctorName': string,
        'doctorTimes': string[],
        'date': string,
        'familyID': string,
        'reservedFor': string
        'status': AppointmentStatus
    }
    
  • POST /appointment/delete/:id - Delete an appointment
    • Request Body
    {
        'appointmentId': string,
        'cancelledByDoctor': boolean
    }
    
  • POST /appointment/reschedule - Reschedule an appointment - Request Body { appointment: string, rescheduleDate: string } - Response Body { 'id': string, 'patientID': string, 'doctorID': string, 'doctorName': string, 'doctorTimes': string[], 'date': string, 'familyID': string, 'reservedFor': string 'status': AppointmentStatus }
Auth Endpoints
  • POST /auth/login - Authenticate a user and retrieve an access token.

    • Request Body:
    {
      "username": "string",
      "password": "string"
    }
    • Response Body:
    {
      "token": "string"
    }
  • POST /auth/register-patient - Register a patient and obtain an access token.

    • Request Body:
    {
      "username": "string",
      "name": "string",
      "email": "string",
      "password": "string",
      "dateOfBirth": "string",
      "gender": "string",
      "mobileNumber": "string",
      "emergencyContact": {
        "fullName": "string",
        "mobileNumber": "string"
      }
    }
    • Response Body:
    {
      "token": "string"
    }
  • GET /auth/me - Retrieve information about the currently authenticated user.

  • Response Body:

    {
      "id": "string",
      "username": "string",
      "name": "string",
      "email": "string",
      "dateOfBirth": "string",
      "gender": "string",
      "mobileNumber": "string",
      "emergencyContact": {
        "fullName": "string",
        "mobileNumber": "string"
      }
    }
  • POST /patient/requestOtp - Request to send OTP for forgetting password

    • Request Body:
    {
        email: string
    }
    
    • Response Body:: N/A
  • POST /patient/verifyOtp - Verify OTP for forgetting password

    • Request Body:
    {
        email: string,
        otp: string,
    }
    
    • Response Body:: N/A
  • POST /patient/updatePassword - Update patient password after forgetting password

    - **Request Body:**
    ```
    {
        email: string,
        newPassword: string
    }
    ```
    
    - **Response Body:**: N/A
    
Chat Endpoints
  • `POST '/chats/get-all' - Get all chats for a user

    • Request Body:
    {
        'username': string // Could be username of a patient, doctor, or admin
    }
    
    • Response Body
    {
        'id': string
        'users': Array<{
            'id': string
            'username': string
            'name': string
            'email': string
            'type': UserType
        }>
        'createdAt': string
        'lastMessage': string
        'hasUnreadMessages': boolean
    }
    
  • POST /chats/create-or-get - Creates a new chat or gets one if it already exists between the users

    • Request Body
      {
          'initiator': string
          'receiver': string
      }
      
    • Reponse Body: string -> ID of the created chat
  • POST /chats/get-by-id - Gets a chat by its id

    • Request Body
      {
          'chatId': string
          'readerUsername': string
      }
      
    • Reponse Body
      {
          'id': string
          users: Array<{
              'id': string
              'username': string
              'name': string
              'email': string
              'type': UserType
          }>
          'messages': Array<{
              'id': string
              'sender': string
              'senderType': UserType
              'senderDetails': {
                  'name': string
                  'email': string
              }
              'content': string
              'createdAt': string
          }>
          'createdAt': string
          'lastMessage': string
          'hasUnreadMessages': boolean
      }
      
  • POST /chats/send-message - Sends a message

    • Request Body
      {
          'chatId': string
          'senderUsername': string
          'content': string
      }
      
    • Reponse Body: N/A
  • POST '/chats/mark-as-read' - Marks a chat as being read

    • Request Body
      {
          'chatId': string
          'username': string
      }
      
    • Reponse Body: N/A
Doctors Endpoints
  • PATCH '/doctors/updateDoctor/:username' - Updates a doctor information

    • Request Body
      {
          'name': string,
          'email': string,
          'dateOfBirth': string,
          'hourlyRate': number,
          'affiliation': string,
          'educationalBackground': string,
      }
      
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
      }
      
  • GET /doctors/:username - Gets doctor information by username

    • Request Body: N/A
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
          'contractStatus': ContractStatus
          'availableTimes': [Date]
          'employmentContract': [string]
          'documents': [string]
          'wallet': number
      }
      
  • GET /doctors/pending - Gets pending doctors requests

    • Request Body: N/A
    • Reponse Body:
      {
          'doctors': Array<{
              'id': string
              'username': string
              'name': string
              'email': string
              'dateOfBirth': Date
              'hourlyRate': number
              'affiliation': string
              'educationalBackground': string
              'speciality': string
              'requestStatus': DoctorStatus
          }>
      }
      
  • GET /doctors/approved - Gets approved doctors

    • Request Body: N/A
    • Reponse Body:
      {
          'doctors': Array<{
              'id': string
              'username': string
              'name': string
              'email': string
              'dateOfBirth': Date
              'hourlyRate': number
              'affiliation': string
              'educationalBackground': string
              'speciality': string
              'requestStatus': DoctorStatus
          }>
      }
      
  • GET /doctors/approved/:id - Gets approved doctor by id

    • Request Body: N/A
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
          'availableTimes': [Date]
          'sessionRate': number
          'hasDiscount': boolean
          'hourlyRateWithMarkup': number
      }
      
  • PATCH /doctors/acceptDoctorRequest/:id - Accept a doctor by id

    • Request Body: N/A
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
          'availableTimes': [Date]
          'sessionRate': number
          'hasDiscount': boolean
          'hourlyRateWithMarkup': number
      }
      
  • PATCH /doctors/rejectDoctorRequest/:id - Reject a doctor by id

    • Request Body: N/A
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
          'availableTimes': [Date]
          'sessionRate': number
          'hasDiscount': boolean
          'hourlyRateWithMarkup': number
      }
      
  • PATCH /doctors/addAvailableTimeSlots - Add available time slots for doctor

    • Request Body:
      {
          'time': Date,
      }
      
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
          'availableTimes': [Date]
      }
      
  • PATCH /doctors/acceptEmploymentContract - Accept employment contract

    • Request Body: N/A
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
          'contractStatus': ContractStatus
          'availableTimes': [Date]
          'employmentContract': [string]
          'documents': [string]
      }
      
  • PATCH /doctors/rejectEmploymentContract - Reject employment contract

    • Request Body: N/A
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
          'contractStatus': ContractStatus
          'availableTimes': [Date]
          'employmentContract': [string]
          'documents': [string]
      }
      
  • GET /doctors/wallet/:username - Get doctor's wallet money

    • Request Body: N/A
    • Reponse Body:
      {
          'money': number
      }
      
  • POST /doctors/for-patient - Get doctor for patient

    • Request Body:
      {
         'patientUsername': string
      }
      
    • Reponse Body:
      [
          {
              'id': string
              'username': string
              'name': string
          }
      ]
      
  • POST /auth/request-doctor' - Request to register as a doctor

    • Request Body:
      {
          'name': string
          'email': string
          'username': string
          'password': string
          'dateOfBirth': string
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'documents': File[]
      }
      
    • Reponse Body:
      {
          'id': string
          'username': string
          'name': string
          'email': string
          'dateOfBirth': Date
          'hourlyRate': number
          'affiliation': string
          'educationalBackground': string
          'speciality': string
          'requestStatus': DoctorStatus
      }
      
  • POST /patients/uploadHealthRecords/:id' - Upload health record for a patient

    • Request Body:
      {
          HealthRecord: File[]
      }
      
    • Reponse Body:
      {
          'id': string,
          'username': string,
          'name': string,
          'email': string,
          'mobileNumber': string,
          'dateOfBirth': Date,
          'gender': Gender,
          'emergencyContact': {
              'name': string
              'mobileNumber': string
          },
          'notes': string[]
      }
      
  • POST /patients/deleteHealthRecord/:id' - Delete health record for a patient

    • Request Body:
      {
          url: string // URL to delete
      }
      
    • Reponse Body: N/A
  • GET /patients/getMedicalHistory/:id - Get medical history of patient

    • Request Body: N/A
    • Reponse Body: [string]
  • PATCH /doctors/acceptFollowupRequest/:id - Accept a followup request by id of the request

    • Request Body: N/A
    • Reponse Body: N/A
  • PATCH /doctors/rejectFollowupRequest/:id - Reject a followup request by id of the request - Request Body: N/A - Reponse Body: N/A

Family Members Endpoints
  • GET /family-members/mine - Get family members of currently logged in user

    • Request Body: N/A
    • Reponse Body:
      {
          'id': string
          'name': string
          'nationalId': string
          'age': number
          'gender': Gender
          'relation': Relation
          'healthPackage': {
              'name'?: string
              'renewalDate'?: string
              'id'?: string
          }
          'healthPackageHistory': [
              { package: string; date: Date }
           ] //has the name not id
      }
      
  • GET /family-members/linking-me - Get names of users linking me as family member

    • Request Body: N/A
    • Reponse Body: [string]
  • GET /family-members/:id - Get family member details by id

    • Request Body: N/A
    • Reponse Body:
      {
          'familyMember': {
              'id': string
              'name': string
              'nationalId': string
              'age': number
              'gender': Gender
              'relation': Relation
              'healthPackage': {
                  'name'?: string
                  'renewalDate'?: string
                  'id'?: string
              }
              'healthPackageHistory': [
                  { package: string; date: Date }
              ] //has the name not id
          }
          'patient': {
              'id': string,
              'username': string,
              'name': string,
              'email': string,
              'mobileNumber': string,
              'dateOfBirth': Date,
              'gender': Gender,
              'emergencyContact': {
                  'name': string
                  'mobileNumber': string
              },
              'notes': string[]
          }
      }
      
  • POST /family-members/:username: - Add a family member to patient that has certain username

    • Request Body:
      {
          name: string,
          nationalId: string,
          age: number,
          gender: string,
          relation: string,
      }
      
    • Reponse Body: N/A
  • POST /family-members/link - Link a family member

    • Request Body:
      {
          'email'?: string,
          'phonenumber'?: string,
          'relation': string,
      }
      
    • Reponse Body:
      {
          'id': string
          'name': string
          'nationalId': string
          'age': number
          'gender': Gender
          'relation': Relation
          'healthPackage': {
              'name'?: string
              'renewalDate'?: string
              'id'?: string
          }
          'healthPackageHistory': [
              { package: string; date: Date }
          ] //has the name not id
      }
      
  • GET /family-members/mine/linked - Get linked family members of current user - Request Body: N/A - Reponse Body: { 'id': string 'patientId': string 'username': string 'mobileNumber': string 'email': string 'dateOfBirth': string 'name': string 'gender': string 'relation': Relation 'healthPackage': { 'name': string 'id': string } }

Health Packages Endpoints
  • POST /health-packages/for-patient - Get health packages for patient

    • Request Body:
      {
          'patientId': string,
          'isFamilyMember': boolean, // Whether the patient is a family member or an actual patient
      }
      
    • Reponse Body:
      [
          {
              'name': string
              'id': string
              'pricePerYear': number
              'sessionDiscount': number
              'medicineDiscount': number
              'familyMemberSubscribtionDiscount': number
              'discountedPricePerYear': number
          }
      ]
      
  • GET /health-packages - Get all health packages

    • Request Body: N/A
    • Reponse Body:
      [
          {
              'name': string
              'id': string
              'pricePerYear': number
              'sessionDiscount': number
              'medicineDiscount': number
              'familyMemberSubscribtionDiscount': number
          }
      ]
      
  • GET /health-packages/:id - Get a health package by id

    • Request Body: N/A
    • Reponse Body:
      {
          'name': string
          'id': string
          'pricePerYear': number
          'sessionDiscount': number
          'medicineDiscount': number
          'familyMemberSubscribtionDiscount': number
      }
      
  • PATCH /health-packages/:id - Update a health package by id

    • Request Body:
      {
          name: string,
          pricePerYear: number,
          sessionDiscount: number,
          medicineDiscount: number,
          familyMemberSubscribtionDiscount: number,
      }
      
    • Reponse Body: string -> ID of the updated health package
  • POST /health-packages - Create a health package

    • Request Body:
      {
          name: string,
          pricePerYear: number,
          sessionDiscount: number,
          medicineDiscount: number,
          familyMemberSubscribtionDiscount: number,
      }
      
    • Reponse Body:
      {
          'name': string
          'id': string
          'pricePerYear': number
          'sessionDiscount': number
          'medicineDiscount': number
          'familyMemberSubscribtionDiscount': number
      }
      
  • DELETE /health-packages/:id - Delete a health package

    • Request Body: N/A
    • Reponse Body: string -> ID of the deleted health package
  • GET /health-packages/isPackageHasSubscribers/:id - Check if a health package has subscribers

    • Request Body: N/A
    • Reponse Body: boolean
  • PATCH /health-packages/wallet/subscriptions - Subscribe to a health package using wallet

    • Request Body:

      {
          // patientId or familyMemberId for the person that should be subscribed to the health package
          'subscriberId': string
      
          // The person that is paying for the subscription
          'payerUsername': string
      
          // Indicates whether the subscribee is a the id for FamilyMember or Patient
          'isFamilyMember': boolean
          'healthPackageId': string
      }
      
    • Reponse Body: N/A

  • PATCH /health-packages/credit-card/subscriptions - Subscribe to a health package using credit card

    • Request Body:

      {
          // patientId or familyMemberId for the person that should be subscribed to the health package
          'subscriberId': string
      
          // The person that is paying for the subscription
          'payerUsername': string
      
          // Indicates whether the subscribee is a the id for FamilyMember or Patient
          'isFamilyMember': boolean
          'healthPackageId': string
      }
      
    • Reponse Body: N/A

  • POST /health-packages/unsubscribe - Unsubscribe to a health package using credit card

    • Request Body:
      {
          'subscriberId': string
          'payerUsername': string
          'isFamilyMember': boolean
      }
      
    • Reponse Body: N/A
  • POST /health-packages/subscribed - Get health package of user

    • Request Body:
      {
          'patientId': string // patientId or familyMemberId
          'isFamilyMember': boolean
      }
      
    • Reponse Body:
      {
          healthPackage: {
              'name': string
              'id': string
              'pricePerYear': number
              'sessionDiscount': number
              'medicineDiscount': number
              'familyMemberSubscribtionDiscount': number
              'renewalDate': string
              'remainingMonths': number
          },
      }
      
  • POST /health-packages/patient-cancelled - Get cancelled health packages of user

    • Request Body:
      {
          'id': string // patientId or familyMemberId
          'isFamilyMember': boolean
      }
      
    • Reponse Body:
      {
          // Maps ID of cancelled healthPackage to Date of cancellation
          [id: string]: string
      }
      
  • POST /health-packages/cancellation-date/:healthPackageId - Get cancellation date for health package of user - Request Body: { id: string; isFamilyMember: boolean } - Reponse Body: string -> Date of cancellation

Notifications Endpoints
  • POST /notifications/all' - Get all notifications for a user

    • Request Body:
      {
          'username': string,
      }
      
    • Reponse Body:
      {
          notifications: [
              {
                  _id: string
                  title: string
                  description?: string
              }
          ]
      }
      
  • DELETE /notifications' - Delete a notification

    • Request Body:
    {
      username: string,
      notificationId: string,
    }
    
    • Reponse Body: N/A
Patient Endpoints
  • GET /patients/myPatients' - Get all patients for a user

    • Request Body: N/A
    • Reponse Body:
      [
          {
              id: string
              name: string
              username: string
              email: string
              mobileNumber: string
              dateOfBirth: string
              gender: Gender
              emergencyContact: {
                  name: string
                  mobileNumber: string
              }
              familyMembers: string[]
          }
      ]
      
  • GET /patients/search?name={name} - Search for patient by name

    • Request Body: N/A
    • Reponse Body:
    [
        {
            id: string
            name: string
            username: string
            email: string
            mobileNumber: string
            dateOfBirth: string
            gender: Gender
            emergencyContact: {
                name: string
                mobileNumber: string
            }
            familyMembers: string[]
        }
    ]
    
  • GET /patients/filter - Filter patients

    • Request Body: N/A
    • Reponse Body:
    [
        {
            id: string
            name: string
            username: string
            email: string
            mobileNumber: string
            dateOfBirth: string
            gender: Gender
            emergencyContact: {
                name: string
                mobileNumber: string
            }
            familyMembers: string[]
        }
    ]
    
  • GET /patients/:id - Get patient by id

    • Request Body: N/A
    • Reponse Body:
    {
        id: string
        name: string
        username: string
        email: string
        mobileNumber: string
        dateOfBirth: string
        gender: Gender
        emergencyContact: {
            name: string
            mobileNumber: string
        }
        familyMembers: string[]
    }
    
  • GET /patients/username/:username - Get patient by username

    • Request Body: N/A
    • Reponse Body:
    {
        id: string
        name: string
        username: string
        email: string
        mobileNumber: string
        dateOfBirth: string
        gender: Gender
        emergencyContact: {
            name: string
            mobileNumber: string
        }
        familyMembers: string[]
        documents: string[],
        appointments: [
            {
                'id': string,
                'patientID': string,
                'doctorID': string,
                'doctorName': string,
                'doctorTimes': string[],
                'date': string,
                'familyID': string,
                'reservedFor': string
                'status': AppointmentStatus
            }
        ],
        prescriptions: any[],
        notes: string[],
        walletMoney: number
    }
    
  • GET /patients/wallet/:id - Get wallet money for a patient

    • Request Body: N/A
    • Reponse Body:
    {
        money: number
    }
    
  • GET /patients/viewHealthRecords/me - Get health notes for current user

    • Request Body: N/A
    • Reponse Body: [string] -> The notes
  • GET /patients/viewMedicalHistory - Get Medical History for current user

    • Request Body: N/A
    • Reponse Body: [string] -> The url of the documents
  • GET /patients/viewHealthRecords/Files/:id - Get health notes for user by id

    • Request Body: N/A
    • Reponse Body: [string] -> The notes
  • POST /appointment/createFollowUp - Create a follow up for a user

    • Request Body:
      {
          doctorID: string,
          patientID: string,
          followUpDate: Date,
          appointmentID: string
      }
      
    • Reponse Body: N/A
  • POST /patients/deleteMedicalHistory/mine' - Delete a file from the medical history

    • Request Body:
      {
          url: string, // Url to delete
      }
      
    • Reponse Body: N/A
  • POST /patients/uploadMedicalHistory/mine - Upload medical history

    • Request Body:
      {
          medicalHistory: File,
      }
      
    • Reponse Body: N/A
  • POST /appointment/requestFollowUp` - Request a follow up

    • Request Body:
      {
        appointmentID: string,
        date: string
      }
      
    • Reponse Body: N/A
  • POST /appointment/checkFollowUp/:appointmentID`- Checks if a follow up exists

    • Request Body:
      {
        appointmentID: string,
        date: string
      }
      
    • Reponse Body:boolean -> Whether the follow up exists or not
Prescriptions Endpoints
  • GET /prescriptions/mine' - Get all prescriptions of current patient

    • Request Body: N/A
    • Reponse Body:
      [
          {
              'id': string,
              'doctor': string,
              'patient': string,
              'date': Date,
              'isFilled': boolean,
              'medicine': [
                  {
                      'name': string
                      'dosage': string
                      'quantity': number
                  }
              ]
          }
      ]
      
  • GET prescriptions/mine/:id - Get a single prescription by id

    • Request Body: N/A
    • Reponse Body:
    {
        id: string
        name: string
        username: string
        email: string
        mobileNumber: string
        dateOfBirth: string
        gender: Gender
        emergencyContact: {
            name: string
            mobileNumber: string
        }
        familyMembers: string[]
    }
    
  • GET /prescriptions/:username - Get prescriptions for patient

    • Request Body: N/A
    • Reponse Body:
      [
          {
              'id': string,
              'doctor': string,
              'patient': string,
              'date': Date,
              'isFilled': boolean,
              'medicine': [
                  {
                      'name': string
                      'dosage': string
                      'quantity': number
                  }
              ]
          }
      ]
      
  • POST /prescriptions - Add a prescription to a patient

    • Request Body:
      {
          patient: string,
          medicine: string,
          date: string,
      }
      
      • Reponse Body:
          {
            'id': string,
            'doctor': string,
            'patient': string,
            'date': Date,
            'isFilled': boolean,
            'medicine': [
                {
                    'name': string
                    'dosage': string
                    'quantity': number
                }
            ]
        }
        
  • PUT /prescriptions/edit/:id - Edit a prescription by id

    • Request Body:
      {
        medicine: [
          {
            name: string,
            dosage: string,
            quantity: number,
          }
        ],
        date: Date,
        patient: string // Id of patient
      }
      
      • Reponse Body: N/A

๐Ÿงช Tests

We use jest to automatically test parts of our code. To run the tests, run the following command

> cd backend && npm run test

image

We also use Postman to manually test all our api references by making sure the response is as expected. We use it as some kind of sanity-check.

Here is an example of testing one of our endpoints using Postman:

image

๐Ÿง‘๐Ÿปโ€๐Ÿซ How to Use

  • Make sure to follow the Installation steps first

  • Add a .env in the backend of both repos Copilot-and-Sons-Clinic and Copilot-and-Sons-Pharmacy with the following variables (replace the values with your own)

MONGO_URI="<Your Mongo Connection String>"
PORT=3000
BCRYPT_SALT="<A secret string to use for encrypting passwords>"
JWT_TOKEN="<A secret string to use for hashing JWT tokens>"
  • Start clinic
cd Copilot-and-Sons-Clinic
npm start
  • Start pharmacy in a different terminal
cd Copilot-and-Sons-Pharmacy
npm start

NOTE

If you want to use Docker Compose to start to project, you can replace the last step with docker compose up

๐Ÿค Contribute

We welcome contributions to Copilot & Sons El7a2ny Clinic. If you want to contribute, it's as easy as:

  1. Fork the repo
  2. Create a new branch (git checkout -b my-new-feature)
  3. Make changes
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request
  7. Wait for your PR to be reviewed and merged

NOTE

We welcome all contributions, but please make sure to follow our code style and linting rules. You can check the Code Style section for more details.

๐Ÿซก Credits

Docs

YouTube Videos

๐Ÿ“œ License

The software is open source under the Apache 2.0 License.

Apache 2.0

copilot-and-sons-clinic's People

Contributors

saraalajmy avatar mathewhany avatar nairuzy avatar faridaabdelghaffar avatar marwaawd avatar zahra-saadawy avatar youssof-kandil avatar ramezlahzy avatar dareenfadel avatar youssef1shawky avatar nada-abdelfattah avatar

Stargazers

 avatar Youssef Ahmed avatar Ibrahim Abou Elenein avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

copilot-and-sons-clinic's Issues

notification text

change is accepted to is scheduled (for both follow-up and appointment so it's the same but not misleading) and change the date format

chat during video call

either move the chat box to the side so it wont block the view of person u're talking to or remove it completely

appointments

unify all appointment card sizes (regardless of how many buttons there are)

phone number length

phone number length is required to be 11 in the clinic system but 10 in the pharmacy system

Wallet

remove wallet from dashboard, balance in homepage is enough

My profile

Add profile info somewhere in family members tab for patient

Available times

remove available times from doctor where ugly and redundant

Chat with doctor

Remove chat from it's own tab and let it be an option available when viewing one of your doctors (chat button could be presented using an if condition (if the doctor's mine) otherwise it could just not be there or be grayed out)

logo

not necessary but will give us a chance if we want the bonus

IMP/Patient Reschedule Selecting Time Problem

When selecting the time to reschedule the time reflects in the other field of the other appointment

Recreation Steps:
Reserved for self from a doctor
Then reserved for a family member from the same doctor
tried to reschedule for self and it reflected in the time field of the Family Member

image

Ps. I didn't test for linked family members.

Password strength

A weak password is allowed upon registration (whether registering as a patient, requesting to join as a doctor or adding an admin). However, it's not allowed upon changing the password

add admin

add admin page is too empty - maybe squeeze it somewhere with other stuff on homepage?

Outdated times

Available times of a doctor should filter out/ delete the old timings.
issue-with-timings

Document Titles

documents are titled file 1, file 2, etc. change that to name of the uploaded document or allow adding more descriptive titles.

new admin

error messages arent very helpful + creates user even if registration not successful

phone number length

phone number length is required to be 11 in the clinic system but 10 in the pharmacy system

unsubscribe alert

Alert patient that s/he will not get a refund when unsubscribing to a health package

Doctor's docs

Admin should be able to view the documents uploaded by a doctor in order to accept/reject a request

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.