Fully working app
This commit is contained in:
@@ -1,17 +1,24 @@
|
||||
package com.project.back_end.DTO;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import com.project.back_end.utils.PasswordUtil;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
public class Login {
|
||||
|
||||
@NotNull
|
||||
@Size(min = 3)
|
||||
@JsonAlias({"email","username"})
|
||||
private String identifier;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 3)
|
||||
private String password;
|
||||
|
||||
public Login(String identifier, String password) {
|
||||
this.identifier = identifier;
|
||||
this.password = hashPassword(password);
|
||||
this.password = PasswordUtil.hashPassword(password);
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
@@ -21,22 +28,4 @@ public class Login {
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
private static String hashPassword(String rawPassword) {
|
||||
try {
|
||||
return new String(MessageDigest.getInstance("SHA-256").digest(rawPassword.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,27 +1,30 @@
|
||||
|
||||
package com.project.back_end.controllers;
|
||||
|
||||
import com.project.back_end.DTO.Login;
|
||||
import com.project.back_end.models.Admin;
|
||||
import com.project.back_end.services.Service;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("${api.path}" + "admin")
|
||||
public class AdminController {
|
||||
|
||||
// 1. Set Up the Controller Class:
|
||||
// - Annotate the class with `@RestController` to indicate that it's a REST controller, used to handle web requests and return JSON responses.
|
||||
// - Use `@RequestMapping("${api.path}admin")` to define a base path for all endpoints in this controller.
|
||||
// - This allows the use of an external property (`api.path`) for flexible configuration of endpoint paths.
|
||||
|
||||
|
||||
// 2. Autowire Service Dependency:
|
||||
// - Use constructor injection to autowire the `Service` class.
|
||||
// - The service handles core logic related to admin validation and token checking.
|
||||
// - This promotes cleaner code and separation of concerns between the controller and business logic layer.
|
||||
|
||||
|
||||
// 3. Define the `adminLogin` Method:
|
||||
// - Handles HTTP POST requests for admin login functionality.
|
||||
// - Accepts an `Admin` object in the request body, which contains login credentials.
|
||||
// - Delegates authentication logic to the `validateAdmin` method in the service layer.
|
||||
// - Returns a `ResponseEntity` with a `Map` containing login status or messages.
|
||||
|
||||
private final Service service;
|
||||
|
||||
public AdminController(Service service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Map<String, String>> adminLogin(@Valid @RequestBody Login login) {
|
||||
return service.validateAdminLogin(login);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +1,78 @@
|
||||
package com.project.back_end.controllers;
|
||||
|
||||
import com.project.back_end.models.Appointment;
|
||||
import com.project.back_end.services.AppointmentService;
|
||||
import com.project.back_end.services.Service;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.http.ResponseEntity.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/appointments")
|
||||
public class AppointmentController {
|
||||
|
||||
// 1. Set Up the Controller Class:
|
||||
// - Annotate the class with `@RestController` to define it as a REST API controller.
|
||||
// - Use `@RequestMapping("/appointments")` to set a base path for all appointment-related endpoints.
|
||||
// - This centralizes all routes that deal with booking, updating, retrieving, and canceling appointments.
|
||||
private final AppointmentService appointmentService;
|
||||
private final Service service;
|
||||
|
||||
public AppointmentController(AppointmentService appointmentService, Service service) {
|
||||
this.appointmentService = appointmentService;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
// 2. Autowire Dependencies:
|
||||
// - Inject `AppointmentService` for handling the business logic specific to appointments.
|
||||
// - Inject the general `Service` class, which provides shared functionality like token validation and appointment checks.
|
||||
@GetMapping("/{date}/{patientName}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> getAppointments(@PathVariable LocalDate date, @PathVariable String patientName, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "doctor");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
return ResponseEntity.ok(appointmentService.getAppointment(patientName.equals("null") ? null : patientName, date, token));
|
||||
}
|
||||
|
||||
@PostMapping("/{token}")
|
||||
public ResponseEntity<Map<String, Object>> bookAppointment(@Valid @RequestBody Appointment appointment, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "patient");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
int validationResult = service.validateAppointment(appointment);
|
||||
return switch (validationResult) {
|
||||
case -1 -> badRequest().body(Map.of("success", false,"message", "Doctor not found"));
|
||||
case 0 -> badRequest().body(Map.of("success", false, "message", "Time has already been reserved"));
|
||||
case 1 -> {
|
||||
int saveResult = appointmentService.bookAppointment(appointment);
|
||||
if (saveResult == 0) {
|
||||
yield internalServerError().body(Map.of("success", false,"message", "Failed to save appointment!"));
|
||||
} else if (saveResult == 1){
|
||||
yield status(HttpStatus.CREATED).body(Map.of("success", true,"message", "Appointment booked!"));
|
||||
} else {
|
||||
yield internalServerError().body(Map.of("success", false,"message", "Internal Server error"));
|
||||
}
|
||||
}
|
||||
default -> internalServerError().body(Map.of("success", false,"message", "Internal Server error"));
|
||||
};
|
||||
}
|
||||
|
||||
// 3. Define the `getAppointments` Method:
|
||||
// - Handles HTTP GET requests to fetch appointments based on date and patient name.
|
||||
// - Takes the appointment date, patient name, and token as path variables.
|
||||
// - First validates the token for role `"doctor"` using the `Service`.
|
||||
// - If the token is valid, returns appointments for the given patient on the specified date.
|
||||
// - If the token is invalid or expired, responds with the appropriate message and status code.
|
||||
|
||||
|
||||
// 4. Define the `bookAppointment` Method:
|
||||
// - Handles HTTP POST requests to create a new appointment.
|
||||
// - Accepts a validated `Appointment` object in the request body and a token as a path variable.
|
||||
// - Validates the token for the `"patient"` role.
|
||||
// - Uses service logic to validate the appointment data (e.g., check for doctor availability and time conflicts).
|
||||
// - Returns success if booked, or appropriate error messages if the doctor ID is invalid or the slot is already taken.
|
||||
|
||||
|
||||
// 5. Define the `updateAppointment` Method:
|
||||
// - Handles HTTP PUT requests to modify an existing appointment.
|
||||
// - Accepts a validated `Appointment` object and a token as input.
|
||||
// - Validates the token for `"patient"` role.
|
||||
// - Delegates the update logic to the `AppointmentService`.
|
||||
// - Returns an appropriate success or failure response based on the update result.
|
||||
|
||||
|
||||
// 6. Define the `cancelAppointment` Method:
|
||||
// - Handles HTTP DELETE requests to cancel a specific appointment.
|
||||
// - Accepts the appointment ID and a token as path variables.
|
||||
// - Validates the token for `"patient"` role to ensure the user is authorized to cancel the appointment.
|
||||
// - Calls `AppointmentService` to handle the cancellation process and returns the result.
|
||||
|
||||
@PutMapping("/{token}")
|
||||
public ResponseEntity<Map<String, Object>> updateAppointment(@Valid @RequestBody Appointment appointment, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "patient");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
return appointmentService.updateAppointment(appointment);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> cancelAppointment(@PathVariable long id, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "patient");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
return appointmentService.cancelAppointment(id, token);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,103 @@
|
||||
package com.project.back_end.controllers;
|
||||
|
||||
|
||||
import com.project.back_end.DTO.Login;
|
||||
import com.project.back_end.models.Doctor;
|
||||
import com.project.back_end.services.DoctorService;
|
||||
import com.project.back_end.services.Service;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("${api.path}doctor")
|
||||
public class DoctorController {
|
||||
|
||||
// 1. Set Up the Controller Class:
|
||||
// - Annotate the class with `@RestController` to define it as a REST controller that serves JSON responses.
|
||||
// - Use `@RequestMapping("${api.path}doctor")` to prefix all endpoints with a configurable API path followed by "doctor".
|
||||
// - This class manages doctor-related functionalities such as registration, login, updates, and availability.
|
||||
private final DoctorService doctorService;
|
||||
private final Service service;
|
||||
|
||||
public DoctorController(DoctorService doctorService, Service service) {
|
||||
this.doctorService = doctorService;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
// 2. Autowire Dependencies:
|
||||
// - Inject `DoctorService` for handling the core logic related to doctors (e.g., CRUD operations, authentication).
|
||||
// - Inject the shared `Service` class for general-purpose features like token validation and filtering.
|
||||
@GetMapping("/availability/{user}/{doctorId}/{date}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> getDoctorAvailability(@PathVariable String user, @PathVariable long doctorId, @PathVariable LocalDate date, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, user);
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
|
||||
List<String> doctorAvailability = doctorService.getDoctorAvailability(doctorId, date);
|
||||
return ResponseEntity.ok(Map.of("availability", doctorAvailability));
|
||||
}
|
||||
|
||||
// 3. Define the `getDoctorAvailability` Method:
|
||||
// - Handles HTTP GET requests to check a specific doctor’s availability on a given date.
|
||||
// - Requires `user` type, `doctorId`, `date`, and `token` as path variables.
|
||||
// - First validates the token against the user type.
|
||||
// - If the token is invalid, returns an error response; otherwise, returns the availability status for the doctor.
|
||||
@GetMapping
|
||||
public ResponseEntity<Map<String, Object>> getDoctor(
|
||||
@RequestParam(required = false) String name,
|
||||
@RequestParam(required = false) String time,
|
||||
@RequestParam(required = false) String specialty) {
|
||||
return ResponseEntity.ok(service.filterDoctor(name, specialty, time));
|
||||
}
|
||||
|
||||
@PostMapping("/{token}")
|
||||
public ResponseEntity<Map<String, Object>> saveDoctor(@Valid @RequestBody Doctor doctor, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "admin");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
int result = doctorService.saveDoctor(doctor);
|
||||
return switch (result) {
|
||||
case -1 -> ResponseEntity.badRequest().body(Map.of("message", "Doctor email already exists"));
|
||||
case 0 -> ResponseEntity.internalServerError().body(Map.of("message", "Failed to save doctor"));
|
||||
case 1 -> ResponseEntity.status(HttpStatus.CREATED).body(Map.of("message", "Doctor saved successfully"));
|
||||
default -> ResponseEntity.internalServerError().build();
|
||||
};
|
||||
}
|
||||
|
||||
// 4. Define the `getDoctor` Method:
|
||||
// - Handles HTTP GET requests to retrieve a list of all doctors.
|
||||
// - Returns the list within a response map under the key `"doctors"` with HTTP 200 OK status.
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<Map<String, Object>> doctorLogin(@Valid @RequestBody Login login) {
|
||||
return doctorService.validateDoctor(login);
|
||||
}
|
||||
|
||||
@PutMapping("/{token}")
|
||||
public ResponseEntity<Map<String, Object>> updateDoctor(@Valid @RequestBody Doctor doctor, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "admin");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
|
||||
// 5. Define the `saveDoctor` Method:
|
||||
// - Handles HTTP POST requests to register a new doctor.
|
||||
// - Accepts a validated `Doctor` object in the request body and a token for authorization.
|
||||
// - Validates the token for the `"admin"` role before proceeding.
|
||||
// - If the doctor already exists, returns a conflict response; otherwise, adds the doctor and returns a success message.
|
||||
|
||||
|
||||
// 6. Define the `doctorLogin` Method:
|
||||
// - Handles HTTP POST requests for doctor login.
|
||||
// - Accepts a validated `Login` DTO containing credentials.
|
||||
// - Delegates authentication to the `DoctorService` and returns login status and token information.
|
||||
|
||||
|
||||
// 7. Define the `updateDoctor` Method:
|
||||
// - Handles HTTP PUT requests to update an existing doctor's information.
|
||||
// - Accepts a validated `Doctor` object and a token for authorization.
|
||||
// - Token must belong to an `"admin"`.
|
||||
// - If the doctor exists, updates the record and returns success; otherwise, returns not found or error messages.
|
||||
|
||||
|
||||
// 8. Define the `deleteDoctor` Method:
|
||||
// - Handles HTTP DELETE requests to remove a doctor by ID.
|
||||
// - Requires both doctor ID and an admin token as path variables.
|
||||
// - If the doctor exists, deletes the record and returns a success message; otherwise, responds with a not found or error message.
|
||||
|
||||
|
||||
// 9. Define the `filter` Method:
|
||||
// - Handles HTTP GET requests to filter doctors based on name, time, and specialty.
|
||||
// - Accepts `name`, `time`, and `speciality` as path variables.
|
||||
// - Calls the shared `Service` to perform filtering logic and returns matching doctors in the response.
|
||||
int result = doctorService.updateDoctor(doctor);
|
||||
return switch (result) {
|
||||
case -1 -> ResponseEntity.badRequest().body(Map.of("message", "Doctor not found"));
|
||||
case 0 -> ResponseEntity.internalServerError().body(Map.of("message", "Failed to save doctor"));
|
||||
case 1 -> ResponseEntity.ok(Map.of("message", "Doctor updated successfully"));
|
||||
default -> ResponseEntity.internalServerError().build();
|
||||
};
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> deleteDoctor(@PathVariable long id, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "admin");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
int result = doctorService.deleteDoctor(id);
|
||||
return switch (result) {
|
||||
case -1 -> ResponseEntity.badRequest().body(Map.of("message", "Doctor not found"));
|
||||
case 0 -> ResponseEntity.internalServerError().body(Map.of("message", "Failed to delete doctor"));
|
||||
case 1 -> ResponseEntity.ok(Map.of("message", "Doctor deleted successfully"));
|
||||
default -> ResponseEntity.internalServerError().build();
|
||||
};
|
||||
}
|
||||
|
||||
@GetMapping("/filter/{name}/{time}/{specialty}")
|
||||
public ResponseEntity<Map<String, Object>> filter(@PathVariable String name, @PathVariable String time, @PathVariable String specialty) {
|
||||
return ResponseEntity.ok(service.filterDoctor(name, specialty, time));
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,80 @@
|
||||
package com.project.back_end.controllers;
|
||||
|
||||
import com.project.back_end.DTO.Login;
|
||||
import com.project.back_end.models.Patient;
|
||||
import com.project.back_end.services.PatientService;
|
||||
import com.project.back_end.services.Service;
|
||||
import com.project.back_end.services.TokenService;
|
||||
import jakarta.validation.Valid;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/patient")
|
||||
public class PatientController {
|
||||
|
||||
// 1. Set Up the Controller Class:
|
||||
// - Annotate the class with `@RestController` to define it as a REST API controller for patient-related operations.
|
||||
// - Use `@RequestMapping("/patient")` to prefix all endpoints with `/patient`, grouping all patient functionalities under a common route.
|
||||
private static final Logger log = LoggerFactory.getLogger(PatientController.class);
|
||||
private final PatientService patientService;
|
||||
private final Service service;
|
||||
private final TokenService tokenService;
|
||||
|
||||
public PatientController(PatientService patientService, Service service, TokenService tokenService) {
|
||||
this.patientService = patientService;
|
||||
this.service = service;
|
||||
this.tokenService = tokenService;
|
||||
}
|
||||
|
||||
// 2. Autowire Dependencies:
|
||||
// - Inject `PatientService` to handle patient-specific logic such as creation, retrieval, and appointments.
|
||||
// - Inject the shared `Service` class for tasks like token validation and login authentication.
|
||||
@GetMapping("/{token}")
|
||||
public ResponseEntity<Map<String, Object>> getPatient(@PathVariable String token) {
|
||||
return patientService.getPatientDetails(token);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Map<String, Object>> createPatient(@Valid @RequestBody Patient patient) {
|
||||
try {
|
||||
boolean validated = service.validatePatient(patient);
|
||||
if (!validated) {
|
||||
return ResponseEntity.ok(Map.of("message", "Patient with email id or phone no already exist"));
|
||||
}
|
||||
int result = patientService.createPatient(patient);
|
||||
return switch (result) {
|
||||
case 0 -> ResponseEntity.internalServerError().body(Map.of("success", false, "message", "Internal server error"));
|
||||
case 1 -> ResponseEntity.status(HttpStatus.CREATED).body(Map.of("success", false, "message", "Signup successful"));
|
||||
default -> ResponseEntity.internalServerError().body(Map.of("success", false, "message", "Unknown result"));
|
||||
};
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to save patient", e);
|
||||
return ResponseEntity.internalServerError().body(Map.of("success", false, "message", "Internal server error"));
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Define the `getPatient` Method:
|
||||
// - Handles HTTP GET requests to retrieve patient details using a token.
|
||||
// - Validates the token for the `"patient"` role using the shared service.
|
||||
// - If the token is valid, returns patient information; otherwise, returns an appropriate error message.
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<Map<String, Object>> login(@Valid @RequestBody Login login) {
|
||||
return service.validatePatientLogin(login);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> getPatientAppointment(@PathVariable long id, @PathVariable String token) {
|
||||
return patientService.getPatientAppointment(id, token);
|
||||
}
|
||||
|
||||
// 4. Define the `createPatient` Method:
|
||||
// - Handles HTTP POST requests for patient registration.
|
||||
// - Accepts a validated `Patient` object in the request body.
|
||||
// - First checks if the patient already exists using the shared service.
|
||||
// - If validation passes, attempts to create the patient and returns success or error messages based on the outcome.
|
||||
|
||||
|
||||
// 5. Define the `login` Method:
|
||||
// - Handles HTTP POST requests for patient login.
|
||||
// - Accepts a `Login` DTO containing email/username and password.
|
||||
// - Delegates authentication to the `validatePatientLogin` method in the shared service.
|
||||
// - Returns a response with a token or an error message depending on login success.
|
||||
|
||||
|
||||
// 6. Define the `getPatientAppointment` Method:
|
||||
// - Handles HTTP GET requests to fetch appointment details for a specific patient.
|
||||
// - Requires the patient ID, token, and user role as path variables.
|
||||
// - Validates the token using the shared service.
|
||||
// - If valid, retrieves the patient's appointment data from `PatientService`; otherwise, returns a validation error.
|
||||
|
||||
|
||||
// 7. Define the `filterPatientAppointment` Method:
|
||||
// - Handles HTTP GET requests to filter a patient's appointments based on specific conditions.
|
||||
// - Accepts filtering parameters: `condition`, `name`, and a token.
|
||||
// - Token must be valid for a `"patient"` role.
|
||||
// - If valid, delegates filtering logic to the shared service and returns the filtered result.
|
||||
|
||||
@GetMapping("/{id}/{user}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> getPatientAppointmentUser(@PathVariable long id, @PathVariable String user, @PathVariable String token) {
|
||||
boolean validated = tokenService.validateToken(token, user);
|
||||
if (!validated) {
|
||||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "Invalid token"));
|
||||
}
|
||||
return patientService.getPatientAppointment(id, token);
|
||||
}
|
||||
|
||||
@GetMapping("/filter/{condition}/{name}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> filterPatientAppointment(@PathVariable String condition, @PathVariable String name, @PathVariable String token) {
|
||||
return service.filterPatient(condition.equals("null") ? null : condition, name.equals("null") ? null : name, token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
package com.project.back_end.controllers;
|
||||
|
||||
import com.project.back_end.models.Prescription;
|
||||
import com.project.back_end.services.PrescriptionService;
|
||||
import com.project.back_end.services.Service;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("${api.path}prescription")
|
||||
public class PrescriptionController {
|
||||
|
||||
// 1. Set Up the Controller Class:
|
||||
// - Annotate the class with `@RestController` to define it as a REST API controller.
|
||||
// - Use `@RequestMapping("${api.path}prescription")` to set the base path for all prescription-related endpoints.
|
||||
// - This controller manages creating and retrieving prescriptions tied to appointments.
|
||||
private final PrescriptionService prescriptionService;
|
||||
private final Service service;
|
||||
|
||||
public PrescriptionController(PrescriptionService prescriptionService, Service service) {
|
||||
this.prescriptionService = prescriptionService;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
// 2. Autowire Dependencies:
|
||||
// - Inject `PrescriptionService` to handle logic related to saving and fetching prescriptions.
|
||||
// - Inject the shared `Service` class for token validation and role-based access control.
|
||||
// - Inject `AppointmentService` to update appointment status after a prescription is issued.
|
||||
|
||||
|
||||
// 3. Define the `savePrescription` Method:
|
||||
// - Handles HTTP POST requests to save a new prescription for a given appointment.
|
||||
// - Accepts a validated `Prescription` object in the request body and a doctor’s token as a path variable.
|
||||
// - Validates the token for the `"doctor"` role.
|
||||
// - If the token is valid, updates the status of the corresponding appointment to reflect that a prescription has been added.
|
||||
// - Delegates the saving logic to `PrescriptionService` and returns a response indicating success or failure.
|
||||
|
||||
|
||||
// 4. Define the `getPrescription` Method:
|
||||
// - Handles HTTP GET requests to retrieve a prescription by its associated appointment ID.
|
||||
// - Accepts the appointment ID and a doctor’s token as path variables.
|
||||
// - Validates the token for the `"doctor"` role using the shared service.
|
||||
// - If the token is valid, fetches the prescription using the `PrescriptionService`.
|
||||
// - Returns the prescription details or an appropriate error message if validation fails.
|
||||
|
||||
@PostMapping("/{token}")
|
||||
public ResponseEntity<Map<String, Object>> savePrescription(@Valid @RequestBody Prescription prescription, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "doctor");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
return prescriptionService.savePrescription(prescription);
|
||||
}
|
||||
|
||||
@GetMapping("/{appointmentId}/{token}")
|
||||
public ResponseEntity<Map<String, Object>> getPrescription(@PathVariable long appointmentId, @PathVariable String token) {
|
||||
ResponseEntity<Map<String, Object>> validation = service.validateToken(token, "doctor");
|
||||
if (!validation.getStatusCode().is2xxSuccessful()) {
|
||||
return validation;
|
||||
}
|
||||
return prescriptionService.getPrescription(appointmentId);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
package com.project.back_end.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.project.back_end.utils.PasswordUtil;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
@Entity
|
||||
@Table(name = "admins")
|
||||
public class Admin {
|
||||
@@ -23,12 +20,14 @@ public class Admin {
|
||||
|
||||
@NotNull
|
||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||
@Size(min = 256, max = 256)
|
||||
@Size(min = 3, max = 256)
|
||||
private String password;
|
||||
|
||||
public Admin() {}
|
||||
|
||||
public Admin(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = hashPassword(password);
|
||||
this.password = PasswordUtil.hashPassword(password);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
@@ -44,14 +43,6 @@ public class Admin {
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
private static String hashPassword(String rawPassword) {
|
||||
try {
|
||||
return new String(MessageDigest.getInstance("SHA-256").digest(rawPassword.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.password = PasswordUtil.hashPassword(password);
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,10 @@ public class Appointment {
|
||||
|
||||
@NotNull
|
||||
@ManyToOne
|
||||
@JsonIgnore
|
||||
private Doctor doctor;
|
||||
|
||||
@NotNull
|
||||
@ManyToOne
|
||||
@JsonIgnore
|
||||
private Patient patient;
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package com.project.back_end.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.project.back_end.utils.PasswordUtil;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@@ -21,32 +18,28 @@ public class Doctor {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@NotNull (message = "Name must not be empty")
|
||||
@Size(min = 3, max = 100)
|
||||
@Column(unique=true)
|
||||
private String name;
|
||||
|
||||
@NotNull
|
||||
@Email
|
||||
@NotNull(message = "Email must not be empty")
|
||||
@Email()
|
||||
@Column(unique=true)
|
||||
private String email;
|
||||
|
||||
@NotNull
|
||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||
@Size(min = 256,max = 256)
|
||||
@Size(min = 4,max = 256, message = "Password must be at least for characters")
|
||||
private String password;
|
||||
|
||||
@NotNull
|
||||
@NotNull (message = "Speciality must not be empty")
|
||||
@Size(min = 3, max = 50)
|
||||
private String specialty;
|
||||
|
||||
@NotNull
|
||||
@NotNull (message = "Phone must not be empty")
|
||||
@Pattern(regexp = "^[0-9]{10}$")
|
||||
private String phone;
|
||||
|
||||
@OneToMany(mappedBy = "doctor", fetch = FetchType.LAZY)
|
||||
private List<Appointment> appointments;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "doctors_available_times", uniqueConstraints = @UniqueConstraint(columnNames = {"element_value", "doctor_id"}))
|
||||
@Column(name = "available_times")
|
||||
@@ -58,7 +51,7 @@ public class Doctor {
|
||||
public Doctor(String name, String email, String password) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.password = hashPassword(password);
|
||||
this.password = PasswordUtil.hashPassword(password);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -77,10 +70,6 @@ public class Doctor {
|
||||
this.specialty = specialty;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = hashPassword(password);
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
@@ -105,12 +94,8 @@ public class Doctor {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public List<Appointment> getAppointments() {
|
||||
return appointments;
|
||||
}
|
||||
|
||||
public void setAppointments(List<Appointment> appointments) {
|
||||
this.appointments = appointments;
|
||||
public void setPassword(String password) {
|
||||
this.password = PasswordUtil.hashPassword(password);
|
||||
}
|
||||
|
||||
public Set<String> getAvailableTimes() {
|
||||
@@ -120,12 +105,4 @@ public class Doctor {
|
||||
public void setAvailableTimes(Set<String> availableTimes) {
|
||||
this.availableTimes = availableTimes;
|
||||
}
|
||||
|
||||
private static String hashPassword(String rawPassword) {
|
||||
try {
|
||||
return new String(MessageDigest.getInstance("SHA-256").digest(rawPassword.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package com.project.back_end.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.project.back_end.utils.PasswordUtil;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@@ -22,7 +20,7 @@ public class Patient {
|
||||
|
||||
@NotNull
|
||||
@Size(min = 3, max = 100)
|
||||
@Column(unique=true)
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@NotNull
|
||||
@@ -32,20 +30,17 @@ public class Patient {
|
||||
|
||||
@NotNull
|
||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||
@Size(min = 256,max = 256)
|
||||
@Size(min = 4, max = 256, message = "Password must be at least 4 characters")
|
||||
private String password;
|
||||
|
||||
@NotNull
|
||||
@Pattern(regexp = "^[0-9]{10}$")
|
||||
@Pattern(regexp = "^[0-9]{10}$", message = "Phone number must be 10 numbers")
|
||||
private String phone;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 255)
|
||||
private String address;
|
||||
|
||||
@OneToMany(mappedBy = "patient")
|
||||
private List<Appointment> appointments;
|
||||
|
||||
public Patient(){}
|
||||
|
||||
public Patient(String name, String email, String password, String phone, String address) {
|
||||
@@ -53,11 +48,7 @@ public class Patient {
|
||||
this.email = email;
|
||||
this.phone = phone;
|
||||
this.address = address;
|
||||
this.password = hashPassword(password);
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = hashPassword(password);
|
||||
this.password = PasswordUtil.hashPassword(password);
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
@@ -80,8 +71,8 @@ public class Patient {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public void setAppointments(List<Appointment> appointments) {
|
||||
this.appointments = appointments;
|
||||
public void setPassword(String password) {
|
||||
this.password = PasswordUtil.hashPassword(password);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -103,16 +94,4 @@ public class Patient {
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public List<Appointment> getAppointments() {
|
||||
return appointments;
|
||||
}
|
||||
|
||||
private static String hashPassword(String rawPassword) {
|
||||
try {
|
||||
return new String(MessageDigest.getInstance("SHA-256").digest(rawPassword.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,30 @@
|
||||
package com.project.back_end.models;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@Document(collation = "prescriptions")
|
||||
@Document(collection = "prescriptions")
|
||||
public class Prescription {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 3, max = 100)
|
||||
@Size(min = 3, max = 100, message = "Patient name must be at least 3 characters")
|
||||
private String patientName;
|
||||
|
||||
@ManyToOne
|
||||
private Appointment appointment;
|
||||
@NotNull(message = "Appointment id must be set")
|
||||
private Long appointmentId;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 3, max = 100)
|
||||
@NotNull(message = "Medication cannot be null")
|
||||
@Size(min = 3, max = 100, message = "Medication has to be more than 3 characters")
|
||||
private String medication;
|
||||
|
||||
@NotNull
|
||||
@NotNull(message = "Dosage cannot be null")
|
||||
private String dosage;
|
||||
|
||||
@Size(max = 200)
|
||||
@@ -34,8 +32,8 @@ public class Prescription {
|
||||
|
||||
public Prescription() {}
|
||||
|
||||
public Prescription(Patient patient, Appointment appointment, String medication, String dosage, String doctorNotes) {
|
||||
this.appointment = appointment;
|
||||
public Prescription(Patient patient, Long appointmentId, String medication, String dosage, String doctorNotes) {
|
||||
this.appointmentId = appointmentId;
|
||||
this.medication = medication;
|
||||
this.dosage = dosage;
|
||||
this.doctorNotes = doctorNotes;
|
||||
@@ -70,12 +68,12 @@ public class Prescription {
|
||||
this.doctorNotes = doctorNotes;
|
||||
}
|
||||
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
public Long getAppointmentId() {
|
||||
return appointmentId;
|
||||
}
|
||||
|
||||
public void setAppointment(Appointment appointment) {
|
||||
this.appointment = appointment;
|
||||
public void setAppointmentId(Long appointmentId) {
|
||||
this.appointmentId = appointmentId;
|
||||
}
|
||||
|
||||
public String getPatientName() {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.project.back_end.mvc;
|
||||
|
||||
import com.project.back_end.services.Service;
|
||||
import com.project.back_end.services.TokenService;
|
||||
import org.hibernate.annotations.View;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
@@ -19,7 +22,7 @@ public class DashboardController {
|
||||
if (!tokenService.validateToken(token, "admin")) {
|
||||
return "redirect:/";
|
||||
}
|
||||
return "redirect:admin/adminDashboard";
|
||||
return "admin/adminDashboard";
|
||||
}
|
||||
|
||||
@GetMapping("/doctorDashboard/{token}")
|
||||
@@ -27,6 +30,6 @@ public class DashboardController {
|
||||
if (!tokenService.validateToken(token, "doctor")) {
|
||||
return "redirect:/";
|
||||
}
|
||||
return "redirect:admin/doctorDashboard";
|
||||
return "doctor/doctorDashboard";
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ public interface AppointmentRepository extends JpaRepository<Appointment, Long>
|
||||
@Query("""
|
||||
FROM Appointment a
|
||||
LEFT JOIN FETCH Doctor d ON a.doctor = d
|
||||
LEFT JOIN FETCH Patient p on a.patient = p
|
||||
WHERE d.id = :doctorId
|
||||
AND a.appointmentTime BETWEEN :start and :end
|
||||
""")
|
||||
|
||||
@@ -4,9 +4,11 @@ import com.project.back_end.models.Appointment;
|
||||
import com.project.back_end.models.Doctor;
|
||||
import com.project.back_end.repo.AppointmentRepository;
|
||||
import com.project.back_end.repo.DoctorRepository;
|
||||
import com.project.back_end.repo.PatientRepository;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -14,38 +16,46 @@ import org.springframework.stereotype.Service;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@Service
|
||||
public class AppointmentService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AppointmentService.class);
|
||||
|
||||
private final AppointmentRepository appointmentRepository;
|
||||
private final PatientRepository patientRepository;
|
||||
private final DoctorRepository doctorRepository;
|
||||
private final TokenService tokenService;
|
||||
private final com.project.back_end.services.Service service;
|
||||
|
||||
public AppointmentService(AppointmentRepository appointmentRepository, PatientRepository patientRepository, DoctorRepository doctorRepository, TokenService tokenService, com.project.back_end.services.Service service) {
|
||||
public AppointmentService(AppointmentRepository appointmentRepository,
|
||||
DoctorRepository doctorRepository, TokenService tokenService,
|
||||
com.project.back_end.services.Service service) {
|
||||
this.appointmentRepository = appointmentRepository;
|
||||
this.patientRepository = patientRepository;
|
||||
this.doctorRepository = doctorRepository;
|
||||
this.tokenService = tokenService;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public int bookAppointment(@Valid Appointment appointment) {
|
||||
public int bookAppointment(@Valid @NotNull Appointment appointment) {
|
||||
try {
|
||||
requireNonNull(appointment, "Appointment cannot be null");
|
||||
appointmentRepository.save(appointment);
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, String>> updateAppointment(@Valid Appointment appointment) {
|
||||
|
||||
public ResponseEntity<Map<String, Object>> updateAppointment(@Valid @NotNull Appointment appointment) {
|
||||
try {
|
||||
requireNonNull(appointment, "Appointment cannot be null");
|
||||
if (appointmentRepository.findById(appointment.getId()).isEmpty()) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
@@ -53,36 +63,41 @@ public class AppointmentService {
|
||||
if (service.validateAppointment(appointment) < 1) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
try {
|
||||
appointmentRepository.save(appointment);
|
||||
return ResponseEntity.ok(Map.of("success", "true", "message", "Updated successfully!"));
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.ok(Map.of("success", "false", "message", e.getMessage()));
|
||||
log.error(e.getMessage(), e);
|
||||
return ResponseEntity.ok(Map.of("success", "false", "message", "Internal error"));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String,String>> cancelAppointment(@Valid Appointment appointment, String token) {
|
||||
public ResponseEntity<Map<String,Object>> cancelAppointment(long id, @NotNull String token) {
|
||||
try {
|
||||
requireNonNull(token, "Token cannot be null");
|
||||
|
||||
if (!tokenService.validateToken(token, "DOCTOR")) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
|
||||
if (appointmentRepository.findById(appointment.getId()).isEmpty()) {
|
||||
return ResponseEntity.noContent().build();
|
||||
Optional<Appointment> found = appointmentRepository.findById(id);
|
||||
if (found.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("success", "false", "message", "Appointment not found"));
|
||||
}
|
||||
|
||||
try {
|
||||
appointmentRepository.delete(appointment);
|
||||
appointmentRepository.delete(found.get());
|
||||
return ResponseEntity.ok(Map.of("success", "true", "message", "Removed successfully!"));
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.ok(Map.of("success", "false", "message", e.getMessage()));
|
||||
log.error(e.getMessage(), e);
|
||||
return ResponseEntity.internalServerError().body(Map.of("success", "false", "message", "Internal error"));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<String, Object> getAppointment(String pname, LocalDate date, String token) {
|
||||
public Map<String, Object> getAppointment(String pname, @NotNull LocalDate date, @NotNull String token) {
|
||||
try {
|
||||
requireNonNull(date, "Date cannot be null");
|
||||
requireNonNull(token, "Token cannot be null");
|
||||
String doctorEmail = tokenService.extractIdentifier(token);
|
||||
Optional<Doctor> found = doctorRepository.findByEmail(doctorEmail);
|
||||
if (found.isEmpty()) {
|
||||
@@ -90,12 +105,20 @@ public class AppointmentService {
|
||||
}
|
||||
|
||||
Long doctorId = found.get().getId();
|
||||
List<Appointment> appointments = appointmentRepository.findByDoctorIdAndAppointmentTimeBetween(
|
||||
doctorId, date.atStartOfDay(), date.plusDays(1).atStartOfDay());
|
||||
if (pname != null) {
|
||||
appointments = appointments.stream().filter(a -> a.getPatientName().contains(pname)).toList();
|
||||
}
|
||||
|
||||
return Map.of("appointments", appointments);
|
||||
List<Appointment> appointments;
|
||||
if (pname !=null) {
|
||||
appointments = appointmentRepository.findByDoctorIdAndPatient_NameContainingIgnoreCaseAndAppointmentTimeBetween(
|
||||
doctorId, pname, date.atStartOfDay(), date.plusDays(1).atStartOfDay());
|
||||
} else {
|
||||
appointments = appointmentRepository.findByDoctorIdAndAppointmentTimeBetween(
|
||||
doctorId, date.atStartOfDay(), date.plusDays(1).atStartOfDay());
|
||||
}
|
||||
return Map.of("success", "true", "appointments", appointments);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Map.of("success", "false", "message", "Internal error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import com.project.back_end.repo.AppointmentRepository;
|
||||
import com.project.back_end.repo.DoctorRepository;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -14,15 +17,16 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@Service
|
||||
public class DoctorService {
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
|
||||
private static final Logger log = LoggerFactory.getLogger(DoctorService.class);
|
||||
|
||||
private final DoctorRepository doctorRepository;
|
||||
private final AppointmentRepository appointmentRepository;
|
||||
@@ -35,33 +39,38 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<String> getDoctorAvailability(Long doctorId, LocalDate date) {
|
||||
public List<String> getDoctorAvailability(long doctorId, @NotNull LocalDate date) {
|
||||
requireNonNull(date, "Date cannot be null");
|
||||
Doctor doctor = doctorRepository.findById(doctorId).orElseThrow(() -> new IllegalArgumentException("Doctor not found"));
|
||||
return getAvailableTimes(doctor, date);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public int saveDoctor(@Valid Doctor doctor) {
|
||||
public int saveDoctor(@Valid @NotNull Doctor doctor) {
|
||||
try {
|
||||
requireNonNull(doctor, "Doctor cannot be null");
|
||||
if (doctorRepository.findByEmail(doctor.getEmail()).isPresent()) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
doctorRepository.save(doctor);
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public int updateDoctor(@Valid Doctor doctor) {
|
||||
public int updateDoctor(@Valid @NotNull Doctor doctor) {
|
||||
try {
|
||||
requireNonNull(doctor, "Doctor cannot be null");
|
||||
if (doctorRepository.findById(doctor.getId()).isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
doctorRepository.save(doctor);
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -72,13 +81,14 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public int deleteDoctor(Doctor doctor) {
|
||||
if (doctorRepository.findById(doctor.getId()).isEmpty()) {
|
||||
public int deleteDoctor(long id) {
|
||||
try {
|
||||
Optional<Doctor> found = doctorRepository.findById(id);
|
||||
if (found.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
appointmentRepository.deleteAllByDoctorId(doctor.getId());
|
||||
doctorRepository.delete(doctor);
|
||||
appointmentRepository.deleteAllByDoctorId(id);
|
||||
doctorRepository.delete(found.get());
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||
@@ -87,7 +97,7 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String,String>> validateDoctor(Login login) {
|
||||
public ResponseEntity<Map<String,Object>> validateDoctor(@Valid @NotNull Login login) {
|
||||
Optional<Doctor> found = doctorRepository.findByEmail(login.getIdentifier());
|
||||
if (found.isEmpty()) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
|
||||
@@ -104,12 +114,16 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Doctor> findDoctorByName(String name) {
|
||||
return doctorRepository.findByNameLike(name);
|
||||
public List<Doctor> findDoctorByName(@NotNull String name) {
|
||||
return doctorRepository.findByNameLike(requireNonNull(name, "Name cannot be null"));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<String, Object> filterDoctorsByNameSpecialityAndTime(String name, String specialty, String amOrPm) {
|
||||
public Map<String, Object> filterDoctorsByNameSpecialityAndTime(@NotNull String name, @NotNull String specialty, @NotNull String amOrPm) {
|
||||
requireNonNull(name, "Name cannot be null");
|
||||
requireNonNull(specialty, "Speciality cannot be null");
|
||||
requireNonNull(amOrPm, "Time cannot be null");
|
||||
|
||||
if (!"AM".equalsIgnoreCase(amOrPm) && !"PM".equalsIgnoreCase(amOrPm)) {
|
||||
throw new IllegalArgumentException("AM/PM only accepted");
|
||||
}
|
||||
@@ -121,10 +135,12 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<String, Object> filterDoctorByTime(String amOrPm) {
|
||||
public Map<String, Object> filterDoctorByTime(@NotNull String amOrPm) {
|
||||
requireNonNull(amOrPm, "Time cannot be null");
|
||||
if (!"AM".equalsIgnoreCase(amOrPm) && !"PM".equalsIgnoreCase(amOrPm)) {
|
||||
throw new IllegalArgumentException("AM/PM only accepted");
|
||||
}
|
||||
|
||||
List<Doctor> doctors = doctorRepository.findAll()
|
||||
.stream()
|
||||
.filter(d -> d.getAvailableTimes().stream().anyMatch(t -> matchesAMPM(t, amOrPm)))
|
||||
@@ -133,10 +149,14 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<String, Object> filterDoctorByNameAndTime(String name, String amOrPm) {
|
||||
public Map<String, Object> filterDoctorByNameAndTime(@NotNull String name, @NotNull String amOrPm) {
|
||||
requireNonNull(name, "Name cannot be null");
|
||||
requireNonNull(amOrPm, "Time cannot be null");
|
||||
|
||||
if (!"AM".equalsIgnoreCase(amOrPm) && !"PM".equalsIgnoreCase(amOrPm)) {
|
||||
throw new IllegalArgumentException("AM/PM only accepted");
|
||||
}
|
||||
|
||||
List<Doctor> doctors = doctorRepository.findByNameLike(name)
|
||||
.stream()
|
||||
.filter(d -> d.getAvailableTimes().stream().anyMatch(t -> matchesAMPM(t, amOrPm)))
|
||||
@@ -145,13 +165,19 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<String, Object> filterDoctorByNameAndSpeciality(String name, String speciality) {
|
||||
public Map<String, Object> filterDoctorByNameAndSpeciality(@NotNull String name, @NotNull String speciality) {
|
||||
requireNonNull(name, "Name cannot be null");
|
||||
requireNonNull(speciality, "Speciality cannot be null");
|
||||
|
||||
List<Doctor> doctors = doctorRepository.findByNameContainingIgnoreCaseAndSpecialtyIgnoreCase(name,speciality);
|
||||
return Map.of("doctors", doctors);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<String, Object> filterDoctorByTimeAndSpeciality(String speciality, String amOrPm) {
|
||||
public Map<String, Object> filterDoctorByTimeAndSpeciality(@NotNull String speciality, @NotNull String amOrPm) {
|
||||
requireNonNull(speciality, "Speciality cannot be null");
|
||||
requireNonNull(amOrPm, "Time cannot be null");
|
||||
|
||||
if (!"AM".equalsIgnoreCase(amOrPm) && !"PM".equalsIgnoreCase(amOrPm)) {
|
||||
throw new IllegalArgumentException("AM/PM only accepted");
|
||||
}
|
||||
@@ -163,22 +189,12 @@ public class DoctorService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<String, Object> filterDoctorBySpeciality(String speciality) {
|
||||
public Map<String, Object> filterDoctorBySpeciality(@NotNull String speciality) {
|
||||
requireNonNull(speciality, "Speciality cannot be null");
|
||||
List<Doctor> doctors = doctorRepository.findBySpecialtyIgnoreCase(speciality);
|
||||
return Map.of("doctors", doctors);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Doctor> filterDoctorsByTime(String amOrPm) {
|
||||
if (!"AM".equalsIgnoreCase(amOrPm) && !"PM".equalsIgnoreCase(amOrPm)) {
|
||||
throw new IllegalArgumentException("AM/PM only accepted");
|
||||
}
|
||||
return doctorRepository.findAll()
|
||||
.stream()
|
||||
.filter(d -> d.getAvailableTimes().stream().anyMatch(t -> matchesAMPM(t, amOrPm)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static boolean matchesAMPM(String time, String amOrPm) {
|
||||
LocalTime start = LocalTime.parse(time.substring(0, time.indexOf("-")));
|
||||
return switch (amOrPm.toUpperCase()) {
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.project.back_end.repo.AppointmentRepository;
|
||||
import com.project.back_end.repo.PatientRepository;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.validation.Valid;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -19,6 +21,7 @@ import java.util.Optional;
|
||||
@Service
|
||||
public class PatientService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PatientService.class);
|
||||
private final PatientRepository patientRepository;
|
||||
private final AppointmentRepository appointmentRepository;
|
||||
private final TokenService tokenService;
|
||||
@@ -35,6 +38,7 @@ public class PatientService {
|
||||
patientRepository.save(patient);
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create patient", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -42,7 +46,7 @@ public class PatientService {
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, Object>> getPatientAppointment(Long patientId, String token) {
|
||||
try {
|
||||
if (!tokenService.validateToken(token, "PATIENT")) {
|
||||
if (!tokenService.validateToken(token, "patient")) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
|
||||
@@ -57,8 +61,6 @@ public class PatientService {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<AppointmentDTO> appointments = appointmentRepository.findByPatientId(patientId)
|
||||
.stream()
|
||||
.map(AppointmentDTO::new)
|
||||
@@ -71,8 +73,8 @@ public class PatientService {
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, Object>> filterByCondition(String condition, Long patientId) {
|
||||
if (!"PAST".equalsIgnoreCase(condition) && !"PRESENT".equalsIgnoreCase(condition)) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
if (!"past".equalsIgnoreCase(condition) && !"future".equalsIgnoreCase(condition)) {
|
||||
return ResponseEntity.badRequest().body(Map.of("success", false, "message","Condition must be past or future"));
|
||||
}
|
||||
try {
|
||||
List<AppointmentDTO> appointments = appointmentRepository.findByPatientId(patientId)
|
||||
@@ -101,7 +103,7 @@ public class PatientService {
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, Object>> filterByDoctorAndCondition(String condition, String name, long patientId) {
|
||||
if (!"PAST".equalsIgnoreCase(condition) && !"PRESENT".equalsIgnoreCase(condition)) {
|
||||
if (!"past".equalsIgnoreCase(condition) && !"future".equalsIgnoreCase(condition)) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
try {
|
||||
@@ -119,7 +121,7 @@ public class PatientService {
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, Object>> getPatientDetails(String token) {
|
||||
try {
|
||||
if (!tokenService.validateToken(token, "PATIENT")) {
|
||||
if (!tokenService.validateToken(token, "patient")) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
|
||||
@@ -138,9 +140,9 @@ public class PatientService {
|
||||
}
|
||||
|
||||
private static boolean matchesCondition(Appointment appointment, String condition) {
|
||||
return switch (condition.toUpperCase()) {
|
||||
case "PAST" -> appointment.getAppointmentTime().isBefore(LocalDateTime.now());
|
||||
case "PRESENT" -> appointment.getAppointmentTime().isAfter(LocalDateTime.now());
|
||||
return switch (condition.toLowerCase()) {
|
||||
case "past" -> appointment.getAppointmentTime().isBefore(LocalDateTime.now());
|
||||
case "future" -> appointment.getAppointmentTime().isAfter(LocalDateTime.now());
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.project.back_end.models.Prescription;
|
||||
import com.project.back_end.repo.PrescriptionRepository;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.validation.Valid;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -14,6 +16,7 @@ import java.util.Map;
|
||||
@Service
|
||||
public class PrescriptionService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PrescriptionService.class);
|
||||
private final PrescriptionRepository prescriptionRepository;
|
||||
|
||||
public PrescriptionService(PrescriptionRepository prescriptionRepository) {
|
||||
@@ -21,14 +24,15 @@ public class PrescriptionService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, String>> savePrescription(@Valid Prescription prescription) {
|
||||
public ResponseEntity<Map<String, Object>> savePrescription(@Valid Prescription prescription) {
|
||||
try {
|
||||
if (!prescriptionRepository.findByAppointmentId(prescription.getAppointment().getId()).isEmpty()) {
|
||||
if (!prescriptionRepository.findByAppointmentId(prescription.getAppointmentId()).isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Prescription already exists"));
|
||||
}
|
||||
prescriptionRepository.save(prescription);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(Map.of("message", "Prescription saved"));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to save prescription", e);
|
||||
return ResponseEntity.internalServerError().body(Map.of("message", "Internal Error"));
|
||||
}
|
||||
}
|
||||
@@ -39,6 +43,7 @@ public class PrescriptionService {
|
||||
List<Prescription> prescriptions = prescriptionRepository.findByAppointmentId(appointmentId);
|
||||
return ResponseEntity.ok(Map.of("prescriptions", prescriptions));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to get prescription", e);
|
||||
return ResponseEntity.internalServerError().body(Map.of("message", "Internal Error"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,28 +37,30 @@ public class Service {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, String>> validateToken(String token, String user) {
|
||||
if (tokenService.validateToken(token, user)) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
public ResponseEntity<Map<String, Object>> validateToken(String token, String user) {
|
||||
if (!tokenService.validateToken(token, user)) {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.UNAUTHORIZED)
|
||||
.body(Map.of("success", false, "message", "User is not authorized!"));
|
||||
}
|
||||
return ResponseEntity.ok().body(Map.of("message", "User is valid"));
|
||||
return ResponseEntity.ok().body(Map.of("success", false, "message", "User is valid"));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, String>> validateAdmin(Admin receivedAdmin) {
|
||||
public ResponseEntity<Map<String, String>> validateAdminLogin(Login login) {
|
||||
try {
|
||||
Optional<Admin> found = adminRepository.findByUsername(receivedAdmin.getUsername());
|
||||
Optional<Admin> found = adminRepository.findByUsername(login.getIdentifier());
|
||||
if (found.isEmpty()) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
Admin admin = found.get();
|
||||
|
||||
if (!receivedAdmin.getPassword().equals(admin.getPassword())) {
|
||||
if (!login.getPassword().equals(admin.getPassword())) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
|
||||
String token = tokenService.generateToken(receivedAdmin.getUsername());
|
||||
String token = tokenService.generateToken(login.getIdentifier());
|
||||
return ResponseEntity.ok(Map.of("token", token));
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -105,7 +107,7 @@ public class Service {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ResponseEntity<Map<String, String>> validatePatientLogin(Login login) {
|
||||
public ResponseEntity<Map<String, Object>> validatePatientLogin(Login login) {
|
||||
try {
|
||||
Optional<Patient> found = patientRepository.findByEmail(login.getIdentifier());
|
||||
if (found.isEmpty()) {
|
||||
@@ -148,7 +150,7 @@ public class Service {
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.internalServerError().build();
|
||||
return ResponseEntity.internalServerError().body(Map.of("success", false, "message", "Internal Server Error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import com.project.back_end.repo.PatientRepository;
|
||||
import io.jsonwebtoken.JwtParser;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -17,6 +19,7 @@ import java.util.Date;
|
||||
@Component
|
||||
public class TokenService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TokenService.class);
|
||||
private final AdminRepository adminRepository;
|
||||
private final DoctorRepository doctorRepository;
|
||||
private final PatientRepository patientRepository;
|
||||
@@ -47,6 +50,7 @@ public class TokenService {
|
||||
try {
|
||||
return jwtParser.parseSignedClaims(token).getPayload().getSubject();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to parse token claims", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -55,15 +59,20 @@ public class TokenService {
|
||||
try {
|
||||
String identifier = extractIdentifier(token);
|
||||
if (identifier == null) {
|
||||
log.error("Failed to extract identifier from token {}", token);
|
||||
return false;
|
||||
}
|
||||
return switch (role.toUpperCase()) {
|
||||
case "ADMIN" -> adminRepository.findByUsername(identifier).isPresent();
|
||||
case "DOCTOR" -> doctorRepository.findByEmail(identifier).isPresent();
|
||||
case "PATIENT" -> patientRepository.findByEmail(identifier).isPresent();
|
||||
default -> false;
|
||||
default -> {
|
||||
log.error("Role {} unknown", role);
|
||||
yield false;
|
||||
}
|
||||
};
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to validate token.", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.project.back_end.utils;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HexFormat;
|
||||
|
||||
public class PasswordUtil {
|
||||
|
||||
private PasswordUtil(){}
|
||||
|
||||
public static String hashPassword(String rawPassword) {
|
||||
try {
|
||||
return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(rawPassword.getBytes()));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,8 @@ h2 {
|
||||
.main-content {
|
||||
flex-grow: 1;
|
||||
padding: 40px;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
background-image: url("index.png");
|
||||
background-image: url("/assets/images/defineRole/index.png");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@@ -18,9 +18,8 @@ html, body {
|
||||
.main-content {
|
||||
flex-grow: 1;
|
||||
padding: 40px;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
background-image: url("index.png");
|
||||
background-image: url("/assets/images/defineRole/index.png");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@@ -24,9 +24,10 @@ h2 {
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex-grow: 1;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
background-image: url("index.png");
|
||||
background-image: url("/assets/images/defineRole/index.png");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<script src="./js/components/footer.js" defer></script>
|
||||
<link rel="icon" type="image/png" href="./assets/images/logo/logo.png" />
|
||||
</head>
|
||||
<body>
|
||||
<body onload="renderContent()">
|
||||
<div class="container">
|
||||
<div class="wrapper">
|
||||
<div id="header"></div>
|
||||
@@ -19,15 +19,17 @@
|
||||
<h2>Select Your Role:</h2>
|
||||
<button id="adminLogin">Admin</button>
|
||||
<button id="doctorLogin">Doctor</button>
|
||||
<button id="patientLogin" onclick="window.location.href='/pages/loggedPatientDashboard.html'">Patient</button>
|
||||
<button id="patientLogin">Patient</button>
|
||||
</main>
|
||||
<div id="footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal" class="modal">
|
||||
<button id="closeModal">Close</button>
|
||||
<div class="modal-content">
|
||||
<span class="close" id="closeModal">×</span>
|
||||
<div id="modal-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module" src="js/services/index.js" defer></script>
|
||||
</body>
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import { openModal } from "../components/modals.js";
|
||||
import { openModal } from "./components/modals.js";
|
||||
import { getDoctors, filterDoctors, saveDoctor } from "./services/doctorServices.js";
|
||||
import { createDoctorCard } from "./components/doctorCard.js";
|
||||
|
||||
window.onload = function () {
|
||||
document.getElementById("searchBar").addEventListener("input", filterDoctorsOnChange);
|
||||
document.getElementById("filterTime").addEventListener("change", filterDoctorsOnChange);
|
||||
document.getElementById("filterSpecialty").addEventListener("change", filterDoctorsOnChange);
|
||||
document.getElementById('addDocBtn').addEventListener('click', () => { openModal('addDoctor'); });
|
||||
|
||||
loadDoctorCards();
|
||||
};
|
||||
|
||||
export async function loadDoctorCards() {
|
||||
async function loadDoctorCards() {
|
||||
try {
|
||||
const doctors = await getDoctors();
|
||||
renderDoctorCards(doctors);
|
||||
@@ -20,37 +15,30 @@ export async function loadDoctorCards() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function filterDoctorsOnChange() {
|
||||
const name = document.getElementById("searchBar").value;
|
||||
const time = document.getElementById("filterTime").value;
|
||||
const specialty = document.getElementById("filterSpecialty").value;
|
||||
const doctors = filterDoctors(name, time, specialty);
|
||||
renderDoctorCards(doctors);
|
||||
}
|
||||
|
||||
export async function renderDoctorCards(doctors) {
|
||||
const contentDiv = document.getElementById("content");
|
||||
contentDiv.innerHTML = "";
|
||||
for (doctor : doctors) {
|
||||
const card = createDoctorCard(doctor);
|
||||
contentDiv.appendChild(card);
|
||||
}
|
||||
}
|
||||
|
||||
export async function adminAddDoctor() {
|
||||
window.adminAddDoctor = async function() {
|
||||
const doctor = {
|
||||
"name": document.getElementById("doctorName").value,
|
||||
"email": document.getElementById("doctorEmail").value,
|
||||
"password": document.getElementById("doctorPassword").value,
|
||||
"speciality": document.getElementById("specialization").value,
|
||||
"specialty": document.getElementById("specialization").value,
|
||||
"phone": document.getElementById("doctorPhone").value,
|
||||
"availability": document.querySelectorAll('input[name=availability]:checked').map(e => e.value)
|
||||
"availableTimes": Array.from( document.querySelectorAll('input[name=availability]:checked').values()).map(input => input.value)
|
||||
}
|
||||
|
||||
const token = localStorage.getItem("TOKEN");
|
||||
const token = localStorage.getItem("token");
|
||||
if (token == 'undefined') {
|
||||
throw Error("No Authentication token found!");
|
||||
}
|
||||
|
||||
saveDoctor(doctor, token);
|
||||
try {
|
||||
const { success, message } = await saveDoctor(doctor, token);
|
||||
if (success) {
|
||||
alert(message);
|
||||
document.getElementById("modal").style.display = "none";
|
||||
window.location.reload();
|
||||
}
|
||||
else alert(message);
|
||||
} catch(error) {
|
||||
console.error("Registration failed:", error);
|
||||
alert("❌ An error occurred while registering up.");
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export function createDoctorCard(doctor) {
|
||||
email.textContent = doctor.email;
|
||||
|
||||
const availability = document.createElement("h3");
|
||||
availability.textContent = doctor.availability.join(", ");
|
||||
availability.textContent = doctor.availableTimes.join(", ");
|
||||
|
||||
infoDiv.appendChild(name);
|
||||
infoDiv.appendChild(specialization);
|
||||
@@ -35,8 +35,8 @@ export function createDoctorCard(doctor) {
|
||||
const removeBtn = document.createElement("button");
|
||||
removeBtn.textContent = "Delete";
|
||||
removeBtn.addEventListener("click", async () => {
|
||||
if (confirm("Arey you sure?") == true) {
|
||||
const token = localStorage.getItem("TOKEN");
|
||||
if (confirm("Are you sure?") == true) {
|
||||
const token = localStorage.getItem("token");
|
||||
const result = await deleteDoctor(doctor.id, token);
|
||||
if (result.success) {
|
||||
card.remove();
|
||||
@@ -57,7 +57,7 @@ export function createDoctorCard(doctor) {
|
||||
const bookNow = document.createElement("button");
|
||||
bookNow.textContent = "Book Now";
|
||||
bookNow.addEventListener("click", async (e) => {
|
||||
const token = localStorage.getItem("TOKEN");
|
||||
const token = localStorage.getItem("token");
|
||||
const patientData = await getPatientData(token);
|
||||
showBookingOverlay(e, doctor, patientData);
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ function renderHeader() {
|
||||
}
|
||||
|
||||
const role = localStorage.getItem("userRole");
|
||||
const token = localStorage.getItem("TOKEN");
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
let headerContent = `<header class="header">
|
||||
<div class="logo-section">
|
||||
@@ -30,7 +30,7 @@ function renderHeader() {
|
||||
return;
|
||||
} else if (role === "admin") {
|
||||
headerContent += `
|
||||
<button id="addDocBtn" class="adminBtn" onclick="openModal('addDoctor')">Add Doctor</button>
|
||||
<button id="addDocBtn" class="adminBtn">Add Doctor</button>
|
||||
<a href="#" onclick="logout()">Logout</a>`;
|
||||
} else if (role === "doctor") {
|
||||
headerContent += `
|
||||
@@ -67,12 +67,15 @@ function attachHeaderButtonListeners() {
|
||||
|
||||
function logout() {
|
||||
localStorage.removeItem("userRole");
|
||||
localStorage.removeItem("TOKEN");
|
||||
localStorage.removeItem("token");
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
function logoutPatient() {
|
||||
localStorage.removeItem("userRole");
|
||||
selectRole('patient');
|
||||
window.location.href='/pages/loggedPatientDashboard.html';
|
||||
localStorage.removeItem("token");
|
||||
setRole('patient')
|
||||
window.location.href='/pages/patientDashboard.html';
|
||||
}
|
||||
|
||||
renderHeader();
|
||||
@@ -21,7 +21,6 @@ export function openModal(type) {
|
||||
<option value="oncologist">Oncologist</option>
|
||||
<option value="gastroenterologist">Gastroenterologist</option>
|
||||
<option value="general">General Physician</option>
|
||||
|
||||
</select>
|
||||
<input type="email" id="doctorEmail" placeholder="Email" class="input-field">
|
||||
<input type="password" id="doctorPassword" placeholder="Password" class="input-field">
|
||||
|
||||
@@ -2,23 +2,26 @@ import { getAllAppointments } from "./services/appointmentRecordService.js";
|
||||
import { createPatientRow } from "./components/patientRows.js";
|
||||
|
||||
const patientTable = document.getElementById("patientTableBody");
|
||||
const token = localStorage.getItem("TOKEN");
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
var selectedDate = new Date();
|
||||
var selectedDate = new Date().toISOString().split('T')[0]; //YYYY-MM-DD
|
||||
var patientName = null;
|
||||
|
||||
window.onload = function () {
|
||||
document.getElementById("searchBar").addEventListener("input", filterPatientsOnChange);
|
||||
|
||||
document.getElementById('todayButton').addEventListener('click', () => {
|
||||
selectedDate = new Date();
|
||||
selectedDate = new Date().toISOString().split('T')[0]; //YYYY-MM-DD
|
||||
document.getElementById('datePicker').value = selectedDate;
|
||||
loadAppointments();
|
||||
});
|
||||
document.getElementById('datePicker').addEventListener('click', () => {
|
||||
|
||||
document.getElementById('datePicker').addEventListener('change', () => {
|
||||
selectedDate = document.getElementById('datePicker').value;
|
||||
loadAppointments();
|
||||
});
|
||||
}
|
||||
loadAppointments();
|
||||
};
|
||||
|
||||
export async function filterPatientsOnChange() {
|
||||
patientName = document.getElementById("searchBar").value.trim();
|
||||
@@ -28,75 +31,22 @@ export async function filterPatientsOnChange() {
|
||||
loadAppointments();
|
||||
}
|
||||
|
||||
export async loadAppointments() {
|
||||
export async function loadAppointments() {
|
||||
try {
|
||||
const appointments = await getAllAppointments(selectedDate, patientName, token);
|
||||
console.log(appointments);
|
||||
if (appointments.length == 0) {
|
||||
patientTable.innerHTML = "<tr><td>No Appointments found for today</td></tr>”;
|
||||
patientTable.innerHTML = "<tr><td colspan=5>No Patients found for the selected day</td></tr>";
|
||||
return;
|
||||
}
|
||||
patientTable.innerHTML = "";
|
||||
for (appointment : appointments) {
|
||||
appointments.forEach(appointment => {
|
||||
const row = createPatientRow(appointment.patient, appointment.id, appointment.doctorId);
|
||||
patientTable.appendChild(row);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error: ", error);
|
||||
patientTable.innerHTML = "<tr><td>Failed to load appointments</td></tr>”;
|
||||
patientTable.innerHTML = "<tr><td colspan=5>Error loading patients. Try again later.</td></tr>";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Import getAllAppointments to fetch appointments from the backend
|
||||
Import createPatientRow to generate a table row for each patient appointment
|
||||
|
||||
|
||||
Get the table body where patient rows will be added
|
||||
Initialize selectedDate with today's date in 'YYYY-MM-DD' format
|
||||
Get the saved token from localStorage (used for authenticated API calls)
|
||||
Initialize patientName to null (used for filtering by name)
|
||||
|
||||
|
||||
Add an 'input' event listener to the search bar
|
||||
On each keystroke:
|
||||
- Trim and check the input value
|
||||
- If not empty, use it as the patientName for filtering
|
||||
- Else, reset patientName to "null" (as expected by backend)
|
||||
- Reload the appointments list with the updated filter
|
||||
|
||||
|
||||
Add a click listener to the "Today" button
|
||||
When clicked:
|
||||
- Set selectedDate to today's date
|
||||
- Update the date picker UI to match
|
||||
- Reload the appointments for today
|
||||
|
||||
|
||||
Add a change event listener to the date picker
|
||||
When the date changes:
|
||||
- Update selectedDate with the new value
|
||||
- Reload the appointments for that specific date
|
||||
|
||||
|
||||
Function: loadAppointments
|
||||
Purpose: Fetch and display appointments based on selected date and optional patient name
|
||||
|
||||
Step 1: Call getAllAppointments with selectedDate, patientName, and token
|
||||
Step 2: Clear the table body content before rendering new rows
|
||||
|
||||
Step 3: If no appointments are returned:
|
||||
- Display a message row: "No Appointments found for today."
|
||||
|
||||
Step 4: If appointments exist:
|
||||
- Loop through each appointment and construct a 'patient' object with id, name, phone, and email
|
||||
- Call createPatientRow to generate a table row for the appointment
|
||||
- Append each row to the table body
|
||||
|
||||
Step 5: Catch and handle any errors during fetch:
|
||||
- Show a message row: "Error loading appointments. Try again later."
|
||||
|
||||
|
||||
When the page is fully loaded (DOMContentLoaded):
|
||||
- Call renderContent() (assumes it sets up the UI layout)
|
||||
- Call loadAppointments() to display today's appointments by default
|
||||
*/
|
||||
@@ -4,9 +4,11 @@ import { createDoctorCard } from './components/doctorCard.js';
|
||||
import { filterDoctors } from './services/doctorServices.js';
|
||||
import { bookAppointment } from './services/appointmentRecordService.js';
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
loadDoctorCards();
|
||||
document.getElementById("searchBar").addEventListener("input", filterDoctorsOnChange);
|
||||
document.getElementById("filterTime").addEventListener("change", filterDoctorsOnChange);
|
||||
document.getElementById("filterSpecialty").addEventListener("change", filterDoctorsOnChange);
|
||||
});
|
||||
|
||||
function loadDoctorCards() {
|
||||
@@ -84,16 +86,8 @@ export function showBookingOverlay(e, doctor, patient) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Filter Input
|
||||
document.getElementById("searchBar").addEventListener("input", filterDoctorsOnChange);
|
||||
document.getElementById("filterTime").addEventListener("change", filterDoctorsOnChange);
|
||||
document.getElementById("filterSpecialty").addEventListener("change", filterDoctorsOnChange);
|
||||
|
||||
|
||||
|
||||
function filterDoctorsOnChange() {
|
||||
|
||||
const searchBar = document.getElementById("searchBar").value.trim();
|
||||
const filterTime = document.getElementById("filterTime").value;
|
||||
const filterSpecialty = document.getElementById("filterSpecialty").value;
|
||||
@@ -104,8 +98,7 @@ function filterDoctorsOnChange() {
|
||||
const specialty = filterSpecialty.length > 0 ? filterSpecialty : null;
|
||||
|
||||
filterDoctors(name, time, specialty)
|
||||
.then(response => {
|
||||
const doctors = response.doctors;
|
||||
.then(doctors => {
|
||||
const contentDiv = document.getElementById("content");
|
||||
contentDiv.innerHTML = "";
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { filterDoctors } from './services/doctorServices.js';//call the same fun
|
||||
import { patientSignup, patientLogin } from './services/patientServices.js';
|
||||
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
loadDoctorCards();
|
||||
});
|
||||
@@ -27,9 +26,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
})
|
||||
|
||||
document.getElementById("searchBar").addEventListener("input", filterDoctorsOnChange);
|
||||
document.getElementById("filterTime").addEventListener("change", filterDoctorsOnChange);
|
||||
document.getElementById("filterSpecialty").addEventListener("change", filterDoctorsOnChange);
|
||||
|
||||
function loadDoctorCards() {
|
||||
getDoctors()
|
||||
.then(doctors => {
|
||||
const doctors = getDoctors().then(doctors => {
|
||||
|
||||
const contentDiv = document.getElementById("content");
|
||||
contentDiv.innerHTML = "";
|
||||
|
||||
@@ -38,15 +41,7 @@ function loadDoctorCards() {
|
||||
contentDiv.appendChild(card);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Failed to load doctors:", error);
|
||||
});
|
||||
}
|
||||
// Filter Input
|
||||
document.getElementById("searchBar").addEventListener("input", filterDoctorsOnChange);
|
||||
document.getElementById("filterTime").addEventListener("change", filterDoctorsOnChange);
|
||||
document.getElementById("filterSpecialty").addEventListener("change", filterDoctorsOnChange);
|
||||
|
||||
|
||||
|
||||
function filterDoctorsOnChange() {
|
||||
@@ -54,14 +49,11 @@ function filterDoctorsOnChange() {
|
||||
const filterTime = document.getElementById("filterTime").value;
|
||||
const filterSpecialty = document.getElementById("filterSpecialty").value;
|
||||
|
||||
|
||||
const name = searchBar.length > 0 ? searchBar : null;
|
||||
const time = filterTime.length > 0 ? filterTime : null;
|
||||
const specialty = filterSpecialty.length > 0 ? filterSpecialty : null;
|
||||
|
||||
filterDoctors(name, time, specialty)
|
||||
.then(response => {
|
||||
const doctors = response.doctors;
|
||||
filterDoctors(name, time, specialty).then(doctors => {
|
||||
const contentDiv = document.getElementById("content");
|
||||
contentDiv.innerHTML = "";
|
||||
|
||||
@@ -76,10 +68,7 @@ function filterDoctorsOnChange() {
|
||||
console.log("Nothing");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Failed to filter doctors:", error);
|
||||
alert("❌ An error occurred while filtering doctors.");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
window.signupPatient = async function () {
|
||||
|
||||
@@ -3,25 +3,27 @@
|
||||
function selectRole(role) {
|
||||
setRole(role);
|
||||
const token = localStorage.getItem('token');
|
||||
if (role === "admin") {
|
||||
if (token) {
|
||||
if (role === "admin" && token) {
|
||||
window.location.href = `/adminDashboard/${token}`;
|
||||
}
|
||||
} if (role === "patient") {
|
||||
|
||||
} else if (role === "loggedPatient" && token) {
|
||||
window.location.href = "/pages/loggedPatientDashboard.html";
|
||||
|
||||
} else if (role === "patient") {
|
||||
window.location.href = "/pages/patientDashboard.html";
|
||||
} else if (role === "doctor") {
|
||||
if (token) {
|
||||
|
||||
} else if (role === "doctor" && token) {
|
||||
window.location.href = `/doctorDashboard/${token}`;
|
||||
} else if (role === "loggedPatient") {
|
||||
window.location.href = "loggedPatientDashboard.html";
|
||||
}
|
||||
|
||||
} else {
|
||||
window.location.href = "/";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function renderContent() {
|
||||
const role = getRole();
|
||||
if (!role) {
|
||||
console.error("No role set!")
|
||||
window.location.href = "/"; // if no role, send to role selection page
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,17 @@ const APPOINTMENT_API = `${API_BASE_URL}/appointments`;
|
||||
|
||||
//This is for the doctor to get all the patient Appointments
|
||||
export async function getAllAppointments(date, patientName, token) {
|
||||
try {
|
||||
const response = await fetch(`${APPOINTMENT_API}/${date}/${patientName}/${token}`);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch appointments");
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
const data = await response.json();
|
||||
return data.appointments;
|
||||
} catch (error) {
|
||||
console.error("Error while fetching appointments:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function bookAppointment(appointment, token) {
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function getDoctors() {
|
||||
if (!response.ok) {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
return response.doctors;
|
||||
return result.doctors;
|
||||
} catch (error) {
|
||||
console.log("Error fetching doctors:", error);
|
||||
return [];
|
||||
@@ -21,7 +21,7 @@ export async function getDoctors() {
|
||||
|
||||
export async function deleteDoctor(id, token) {
|
||||
try {
|
||||
const response = await fetch(`${DOCTOR_API}/${id}/{token}`, {
|
||||
const response = await fetch(`${DOCTOR_API}/${id}/${token}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
@@ -54,9 +54,15 @@ export async function saveDoctor(doctor, token) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function filterDoctors(name ,time ,specialty) {
|
||||
export async function filterDoctors(name, time, specialty) {
|
||||
try {
|
||||
const response = await fetch(`${DOCTOR_API}?name=${name}&time=${time}&specialty=${specialty}`, {
|
||||
const url = new URL(DOCTOR_API);
|
||||
|
||||
if (name) url.searchParams.append("name", name);
|
||||
if (time) url.searchParams.append("time", time);
|
||||
if (specialty) url.searchParams.append("specialty", specialty);
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
@@ -64,7 +70,7 @@ export async function filterDoctors(name ,time ,specialty) {
|
||||
if (!response.ok) {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
return response.doctors;
|
||||
return result.doctors;
|
||||
} catch (error) {
|
||||
console.error("Error :: filterDoctors :: ", error)
|
||||
return [];
|
||||
|
||||
@@ -19,6 +19,14 @@ window.onload = function () {
|
||||
openModal('doctorLogin');
|
||||
});
|
||||
}
|
||||
|
||||
const patientBtn = document.getElementById('patientLogin');
|
||||
if (patientBtn) {
|
||||
patientBtn.addEventListener('click', () => {
|
||||
selectRole('patient');
|
||||
window.location.href = '/pages/patientDashboard.html';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.adminLoginHandler = async function() {
|
||||
@@ -35,7 +43,7 @@ window.adminLoginHandler = async function() {
|
||||
if (!response.ok) {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
localStorage.setItem("TOKEN", result)
|
||||
localStorage.setItem("token", result.token)
|
||||
selectRole('admin');
|
||||
} catch (error) {
|
||||
alert("Invalid credentials!");
|
||||
@@ -56,7 +64,7 @@ window.doctorLoginHandler = async function() {
|
||||
if (!response.ok) {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
localStorage.setItem("TOKEN", result)
|
||||
localStorage.setItem("token", result.token)
|
||||
selectRole('doctor');
|
||||
} catch (error) {
|
||||
alert("Invalid credentials!");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// patientServices
|
||||
import { API_BASE_URL } from "../config/config.js";
|
||||
|
||||
|
||||
const PATIENT_API = API_BASE_URL + '/patient'
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="wrapper">
|
||||
<div id="header"></div>
|
||||
<main class="main-content">
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Search Bar for custom output" />
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Filter by doctor..." />
|
||||
<div class="filter-wrapper">
|
||||
<select class="filter-select" id="filterTime">
|
||||
<option value="">Sort by Time</option>
|
||||
@@ -44,8 +44,8 @@
|
||||
<option value="General">General Physician</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="content"></div>
|
||||
</main>
|
||||
<div id="content"></div>
|
||||
<div id="footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<div id="header"></div>
|
||||
<div class="main-content">
|
||||
<h2>Patient <span>Appointment</span></h2>
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Search Bar for custom output" />
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Filter by doctor.." />
|
||||
<div class="filter-wrapper">
|
||||
<select class="filter-select" id="appointmentFilter">
|
||||
<option value="allAppointments">All Appointments</option>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<script src="../js/util.js" defer></script>
|
||||
<script src="../js/components/header.js" defer></script>
|
||||
<script src="../js/components/footer.js" defer></script>
|
||||
<script type="module" src="../js/components/modals.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="renderContent()">
|
||||
@@ -21,7 +20,7 @@
|
||||
<div class="wrapper">
|
||||
<div id="header"></div>
|
||||
<main class="main-content">
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Search Bar for custom output" />
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Filter by doctor..." />
|
||||
<div class="filter-wrapper">
|
||||
<select class="filter-select" id="filterTime">
|
||||
<option value="">Sort by Time</option>
|
||||
|
||||
@@ -17,24 +17,44 @@
|
||||
<div class="wrapper">
|
||||
<div id="header"></div>
|
||||
<main class="main-content">
|
||||
<input type="text" id="searchBar" placeholder="search by doctor name" />
|
||||
<select id="time">
|
||||
<option></option>
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="search by doctor name" />
|
||||
<div class="filter-wrapper">
|
||||
<select id="filterTime" class="filter-select">
|
||||
<option value="">Time</option>
|
||||
<option value="AM">Morning</option>
|
||||
<option value="PM">Afternoon</option>
|
||||
</select>
|
||||
<select id="speciality">
|
||||
<option></option>
|
||||
<select id="filterSpecialty" class="filter-select">
|
||||
<option value="">Speciality</option>
|
||||
<option value="cardiologist">Cardiologist</option>
|
||||
<option value="dermatologist">Dermatologist</option>
|
||||
<option value="neurologist">Neurologist</option>
|
||||
<option value="pediatrician">Pediatrician</option>
|
||||
<option value="orthopedic">Orthopedic</option>
|
||||
<option value="gynecologist">Gynecologist</option>
|
||||
<option value="psychiatrist">Psychiatrist</option>
|
||||
<option value="dentist">Dentist</option>
|
||||
<option value="ophthalmologist">Ophthalmologist</option>
|
||||
<option value="ent">ENT Specialist</option>
|
||||
<option value="urologist">Urologist</option>
|
||||
<option value="oncologist">Oncologist</option>
|
||||
<option value="gastroenterologist">Gastroenterologist</option>
|
||||
<option value="general">General Physician</option>
|
||||
</select>
|
||||
<div id="content"></div>
|
||||
</div>
|
||||
</main>
|
||||
<div id="content"></div>
|
||||
<div id="footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal" class="modal">
|
||||
<span id="closeModal" class="close">×</span>
|
||||
<div class="modal-content">
|
||||
<span class="close" id="closeModal">×</span>
|
||||
<div id="modal-body"></div>
|
||||
</div>
|
||||
<script type="module" src="../js/services/adminDashboard.js" defer></script>
|
||||
<script type="module" src="../js/components/doctorCard.js" defer></script>
|
||||
</div>
|
||||
<script type="module" src="/js/adminDashboard.js" defer></script>
|
||||
<script type="module" src="/js/components/doctorCard.js" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -6,14 +6,11 @@
|
||||
<link rel="stylesheet" th:href="@{/assets/css/adminDashboard.css}">
|
||||
<link rel="stylesheet" th:href="@{/assets/css/doctorDashboard.css}">
|
||||
<link rel="stylesheet" th:href="@{/assets/css/style.css}">
|
||||
<link rel="icon" type="image/png" th:href="@{/assets/images/logo/logo.png}" />
|
||||
<script th:src="@{/js/render.js}" defer></script>
|
||||
<script th:src="@{/js/util.js}" defer></script>
|
||||
<script th:src="@{/js/components/header.js}" defer></script>
|
||||
<script th:src="@{/js/components/footer.js}" defer></script>
|
||||
<script th:src="@{/js/components/patientRows.js}" defer></script>
|
||||
<script th:src="@{/js/components/patientServices.js}" defer></script>
|
||||
<script th:src="@{/js/components/doctorDashboard.js}" defer></script>
|
||||
<link rel="icon" type="image/png" th:href="@{/assets/images/logo/logo.png}" />
|
||||
</head>
|
||||
|
||||
<body onload="renderContent()">
|
||||
@@ -21,11 +18,13 @@
|
||||
<div class="wrapper">
|
||||
<div id="header"></div>
|
||||
<div class="main-content">
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Search Bar for custom output" />
|
||||
<input type="text" id="searchBar" class="searchBar" placeholder="Filter doctor..." />
|
||||
<div class="filter-wrapper">
|
||||
<button id="todayButton">Today</button>
|
||||
<input type="date" id="datePicker" />
|
||||
</div>
|
||||
<table id="patientTable">
|
||||
<thead>
|
||||
<thead class="table-header">
|
||||
<tr>
|
||||
<th>Patient ID</th>
|
||||
<th>Name</th>
|
||||
@@ -40,6 +39,10 @@
|
||||
<div id="footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module" th:src="@{/js/services/patientServices.js}" defer></script>
|
||||
<script type="module" th:src="@{/js/doctorDashboard.js}" defer></script>
|
||||
<script type="module" th:src="@{/js/components/patientRows.js}" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user