From c3bb12e580c2eb0cbb79ddcbbb65adb590cfb83c Mon Sep 17 00:00:00 2001 From: C24053098 <akbarb@cardiff.ac.uk> Date: Wed, 11 Dec 2024 19:03:33 +0000 Subject: [PATCH] approved hospitals shown only See merge request c24025433/healthcare!78 --- .../nursinghome/NursingHomeController.java | 45 +++++++- .../mapper/NursingHomeMapper.java | 86 +++++++++----- .../client_project/pojo/dto/HospitalDTO.java | 1 + .../client_project/pojo/vo/HospitalVO.java | 2 + .../service/NursingHomeService.java | 3 + .../service/imp/NursingHomeServiceImp.java | 108 +++++++++++++++++- src/main/resources/static/css/beds.css | 17 +++ src/main/resources/static/js/beds.js | 103 +++++++++++------ 8 files changed, 297 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/cardiff/client_project/controller/nursinghome/NursingHomeController.java b/src/main/java/com/cardiff/client_project/controller/nursinghome/NursingHomeController.java index e4bada7..59d8283 100644 --- a/src/main/java/com/cardiff/client_project/controller/nursinghome/NursingHomeController.java +++ b/src/main/java/com/cardiff/client_project/controller/nursinghome/NursingHomeController.java @@ -3,18 +3,24 @@ package com.cardiff.client_project.controller.nursinghome; import com.cardiff.client_project.pojo.dto.HospitalDTO; import com.cardiff.client_project.service.NursingHomeService; import com.cardiff.client_project.utils.Result; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; +@Slf4j @RestController @RequestMapping("/api/hospitals") @CrossOrigin(origins = "*") public class NursingHomeController { + private final NursingHomeService nursingHomeService; + @Autowired - private NursingHomeService nursingHomeService; + public NursingHomeController(NursingHomeService nursingHomeService) { + this.nursingHomeService = nursingHomeService; + } // READ - Get available beds @GetMapping("/available") @@ -58,4 +64,41 @@ public class NursingHomeController { return Result.error("Error deleting hospital: " + e.getMessage()); } } + + @GetMapping("/search") + public Result<List<HospitalDTO>> searchHospitals(@RequestParam(required = false) String name) { + try { + if (name == null || name.trim().isEmpty()) { + return nursingHomeService.getAvailableBeds(); + } + return nursingHomeService.searchHospitals(name.trim()); + } catch (Exception e) { + log.error("Search error: ", e); + return Result.error("Search failed: " + e.getMessage()); + } + } + + @PutMapping("/{id}/approval") + public Result<String> updateApprovalStatus( + @PathVariable Integer id, + @RequestParam String status) { + try { + log.info("Updating approval status for hospital {}: {}", id, status); + return nursingHomeService.updateApprovalStatus(id, status); + } catch (Exception e) { + log.error("Error updating approval status: ", e); + return Result.error("Failed to update approval status"); + } + } + + @GetMapping("/pending") + public Result<List<HospitalDTO>> getPendingApprovals() { + try { + log.info("Fetching pending approvals"); + return nursingHomeService.getPendingApprovals(); + } catch (Exception e) { + log.error("Error fetching pending approvals: ", e); + return Result.error("Failed to fetch pending approvals"); + } + } } diff --git a/src/main/java/com/cardiff/client_project/mapper/NursingHomeMapper.java b/src/main/java/com/cardiff/client_project/mapper/NursingHomeMapper.java index 5303ec1..2be6c14 100644 --- a/src/main/java/com/cardiff/client_project/mapper/NursingHomeMapper.java +++ b/src/main/java/com/cardiff/client_project/mapper/NursingHomeMapper.java @@ -5,6 +5,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.List; @Repository @@ -13,33 +15,64 @@ public class NursingHomeMapper { @Autowired private JdbcTemplate jdbcTemplate; + public List<HospitalDTO> searchHospitals(String name) { + String sql = """ + SELECT + id, name, address, phone, maxAmount, + amountPatient, status, approval_status + FROM hospital + WHERE status = 1 + AND name LIKE CONCAT('%', ?, '%') + ORDER BY name ASC + """; + + return jdbcTemplate.query(sql, + ps -> ps.setString(1, name), + this::mapToDTO); + } + public List<HospitalDTO> findAllNursingHomes() { String sql = """ SELECT - id, - name, - address, - phone, - maxAmount, - amountPatient, - status + id, name, address, phone, maxAmount, + amountPatient, status, approval_status FROM hospital WHERE status = 1 """; - return jdbcTemplate.query(sql, (rs, rowNum) -> { - HospitalDTO dto = new HospitalDTO(); - dto.setId(rs.getInt("id")); - dto.setName(rs.getString("name")); - dto.setLocation(rs.getString("address")); - dto.setPhone(rs.getString("phone")); - dto.setTotalBeds(rs.getInt("maxAmount")); - int maxAmount = rs.getInt("maxAmount"); - int amountPatient = rs.getInt("amountPatient"); - dto.setAvailableBeds(maxAmount - amountPatient); - dto.setOccupancyRate(calculateOccupancy(maxAmount, amountPatient)); - return dto; - }); + return jdbcTemplate.query(sql, this::mapToDTO); + } + + public List<HospitalDTO> getPendingApprovals() { + String sql = """ + SELECT + id, name, address, phone, maxAmount, + amountPatient, status, approval_status + FROM hospital + WHERE approval_status = 'PENDING' + """; + + return jdbcTemplate.query(sql, this::mapToDTO); + } + + public int updateApprovalStatus(int id, String status) { + String sql = "UPDATE hospital SET approval_status = ? WHERE id = ?"; + return jdbcTemplate.update(sql, status, id); + } + + private HospitalDTO mapToDTO(ResultSet rs, int rowNum) throws SQLException { + HospitalDTO dto = new HospitalDTO(); + dto.setId(rs.getInt("id")); + dto.setName(rs.getString("name")); + dto.setLocation(rs.getString("address")); + dto.setPhone(rs.getString("phone")); + int maxAmount = rs.getInt("maxAmount"); + int amountPatient = rs.getInt("amountPatient"); + dto.setTotalBeds(maxAmount); + dto.setAvailableBeds(maxAmount - amountPatient); + dto.setOccupancyRate(calculateOccupancy(maxAmount, amountPatient)); + dto.setApprovalStatus(rs.getString("approval_status")); + return dto; } private double calculateOccupancy(int maxAmount, int amountPatient) { @@ -49,15 +82,10 @@ public class NursingHomeMapper { public int insertHospital(HospitalDTO dto) { String sql = """ INSERT INTO hospital ( - name, - address, - phone, - maxAmount, - amountPatient, - status, - type, - roleId - ) VALUES (?, ?, ?, ?, ?, 1, 'hospital', 3) + name, address, phone, maxAmount, + amountPatient, status, type, roleId, + approval_status + ) VALUES (?, ?, ?, ?, ?, 1, 'hospital', 3, 'PENDING') """; return jdbcTemplate.update(sql, diff --git a/src/main/java/com/cardiff/client_project/pojo/dto/HospitalDTO.java b/src/main/java/com/cardiff/client_project/pojo/dto/HospitalDTO.java index 0bc6896..9bb0df2 100644 --- a/src/main/java/com/cardiff/client_project/pojo/dto/HospitalDTO.java +++ b/src/main/java/com/cardiff/client_project/pojo/dto/HospitalDTO.java @@ -12,4 +12,5 @@ public class HospitalDTO { private int totalBeds; private int availableBeds; private double occupancyRate; + private String approvalStatus; } \ No newline at end of file diff --git a/src/main/java/com/cardiff/client_project/pojo/vo/HospitalVO.java b/src/main/java/com/cardiff/client_project/pojo/vo/HospitalVO.java index 3e673b8..a12f13c 100644 --- a/src/main/java/com/cardiff/client_project/pojo/vo/HospitalVO.java +++ b/src/main/java/com/cardiff/client_project/pojo/vo/HospitalVO.java @@ -15,4 +15,6 @@ public class HospitalVO { private String status_str; private int maxAmount; private int amountPatient; + private String approvalStatus; + private String approvalStatus_str; } diff --git a/src/main/java/com/cardiff/client_project/service/NursingHomeService.java b/src/main/java/com/cardiff/client_project/service/NursingHomeService.java index c0e0026..f31c3ba 100644 --- a/src/main/java/com/cardiff/client_project/service/NursingHomeService.java +++ b/src/main/java/com/cardiff/client_project/service/NursingHomeService.java @@ -11,4 +11,7 @@ public interface NursingHomeService { Result<String> deletePatientById(List<Integer> ids); Result<List<HospitalDTO>> getAllPatients(); Result<String> updateBedCount(int hospitalId, int currentPatients); + Result<List<HospitalDTO>> searchHospitals(String name); + Result<String> updateApprovalStatus(Integer hospitalId, String status); + Result<List<HospitalDTO>> getPendingApprovals(); } \ No newline at end of file diff --git a/src/main/java/com/cardiff/client_project/service/imp/NursingHomeServiceImp.java b/src/main/java/com/cardiff/client_project/service/imp/NursingHomeServiceImp.java index 8a3a75e..a9708a4 100644 --- a/src/main/java/com/cardiff/client_project/service/imp/NursingHomeServiceImp.java +++ b/src/main/java/com/cardiff/client_project/service/imp/NursingHomeServiceImp.java @@ -7,27 +7,40 @@ import com.cardiff.client_project.utils.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.dao.DataAccessException; +import org.springframework.transaction.annotation.Transactional; +import lombok.extern.slf4j.Slf4j; import java.util.List; +import java.util.stream.Collectors; @Service +@Slf4j public class NursingHomeServiceImp implements NursingHomeService { + private final NursingHomeMapper nursingHomeMapper; + @Autowired - private NursingHomeMapper nursingHomeMapper; + public NursingHomeServiceImp(NursingHomeMapper nursingHomeMapper) { + this.nursingHomeMapper = nursingHomeMapper; + } @Override public Result<List<HospitalDTO>> getAvailableBeds() { try { List<HospitalDTO> hospitals = nursingHomeMapper.findAllNursingHomes(); - if (hospitals == null || hospitals.isEmpty()) { - return Result.error("No hospitals available"); + hospitals = hospitals.stream() + .filter(h -> "APPROVED".equals(h.getApprovalStatus())) + .collect(Collectors.toList()); + + if (hospitals.isEmpty()) { + return Result.error("No approved hospitals available"); } return Result.success(hospitals); } catch (DataAccessException e) { return Result.error("Database error: " + e.getMessage()); } catch (Exception e) { - return Result.error("Internal server error"); + log.error("Error fetching available beds: {}", e.getMessage(), e); + return Result.error("Failed to fetch available beds"); } } @@ -96,6 +109,80 @@ public class NursingHomeServiceImp implements NursingHomeService { } } + @Override + @Transactional(readOnly = true) + public Result<List<HospitalDTO>> searchHospitals(String name) { + try { + if (name == null || name.trim().isEmpty()) { + return Result.error("Search term cannot be empty"); + } + List<HospitalDTO> hospitals = nursingHomeMapper.searchHospitals(name); + return hospitals.isEmpty() ? + Result.error("No hospitals found") : + Result.success(hospitals); + } catch (Exception e) { + log.error("Search error: ", e); + return Result.error("Search failed"); + } + } + + @Override + @Transactional + public Result<String> updateApprovalStatus(Integer hospitalId, String status) { + try { + log.info("Updating approval status for hospital {}: {}", hospitalId, status); + + if (hospitalId == null || hospitalId <= 0) { + log.warn("Invalid hospital ID: {}", hospitalId); + return Result.error("Invalid hospital ID"); + } + + if (!isValidApprovalStatus(status)) { + log.warn("Invalid approval status: {}", status); + return Result.error("Invalid approval status"); + } + + int result = nursingHomeMapper.updateApprovalStatus(hospitalId, status); + if (result > 0) { + log.info("Successfully updated approval status for hospital {}", hospitalId); + return Result.success("Approval status updated successfully"); + } + + log.warn("Hospital not found with ID: {}", hospitalId); + return Result.error("Hospital not found"); + + } catch (DataAccessException e) { + log.error("Database error while updating approval status: {}", e.getMessage(), e); + return Result.error("Database error occurred"); + } catch (Exception e) { + log.error("Unexpected error while updating approval status: {}", e.getMessage(), e); + return Result.error("Failed to update approval status"); + } + } + + @Override + @Transactional(readOnly = true) + public Result<List<HospitalDTO>> getPendingApprovals() { + try { + log.info("Fetching pending approval hospitals"); + List<HospitalDTO> pendingHospitals = nursingHomeMapper.getPendingApprovals(); + + if (pendingHospitals.isEmpty()) { + log.info("No pending approvals found"); + return Result.error("No pending approvals"); + } + + log.info("Found {} pending approvals", pendingHospitals.size()); + return Result.success(pendingHospitals); + } catch (DataAccessException e) { + log.error("Database error while fetching pending approvals: {}", e.getMessage(), e); + return Result.error("Database error occurred"); + } catch (Exception e) { + log.error("Unexpected error while fetching pending approvals: {}", e.getMessage(), e); + return Result.error("Failed to fetch pending approvals"); + } + } + private boolean validateHospitalData(HospitalDTO hospitalDTO) { if (hospitalDTO == null) return false; return hospitalDTO.getName() != null && @@ -108,4 +195,17 @@ public class NursingHomeServiceImp implements NursingHomeService { hospitalDTO.getAvailableBeds() >= 0 && hospitalDTO.getAvailableBeds() <= hospitalDTO.getTotalBeds(); } + + private boolean isValidStatus(String status) { + return status != null && + (status.equals("APPROVED") || + status.equals("REJECTED") || + status.equals("PENDING")); + } + + private boolean isValidApprovalStatus(String status) { + if (status == null) return false; + return List.of("PENDING", "APPROVED", "REJECTED") + .contains(status.toUpperCase()); + } } \ No newline at end of file diff --git a/src/main/resources/static/css/beds.css b/src/main/resources/static/css/beds.css index 18f829e..4f84052 100644 --- a/src/main/resources/static/css/beds.css +++ b/src/main/resources/static/css/beds.css @@ -342,3 +342,20 @@ footer { padding: 1rem; } +.approval-pending { + background-color: var(--warning-color); + color: white; + padding: 0.25rem 0.5rem; + border-radius: 4px; +} + +.approval-rejected { + background-color: var(--danger-color); + color: white; +} + +.approval-approved { + background-color: var(--success-color); + color: white; +} + diff --git a/src/main/resources/static/js/beds.js b/src/main/resources/static/js/beds.js index 8b9d18e..f9b3737 100644 --- a/src/main/resources/static/js/beds.js +++ b/src/main/resources/static/js/beds.js @@ -13,10 +13,10 @@ $(document).ready(function () { <nav class="top-nav"> <div class="nav-brand">Digital Insight for Health</div> <div class="nav-items"> - <a href="/dashboard" class="nav-link"> + <a href="/superAdminView.html?type=hospital" class="nav-link"> <i class="fas fa-home"></i> Home </a> - <a href="/beds" class="nav-link active"> + <a href="/beds.html" class="nav-link active"> <i class="fas fa-bed"></i> Beds </a> <button class="nav-link sign-out" onclick="handleSignOut()"> @@ -52,35 +52,46 @@ $(document).ready(function () { function updateTable(hospitals) { const tbody = $('#hospitalTable tbody'); tbody.empty(); - + + if (!hospitals || hospitals.length === 0) { + showNoDataMessage(); + return; + } + hospitals.forEach(function(hospital) { - const tr = ` - <tr> - <td>${hospital.id}</td> - <td>${hospital.name || ''}</td> - <td>${hospital.location || ''}</td> - <td>${hospital.phone || ''}</td> - <td>${hospital.totalBeds || 0}</td> - <td>${hospital.availableBeds || 0}</td> - <td>${Math.round(hospital.occupancyRate)}%</td> - <td> - <button class="btn edit-btn" data-id="${hospital.id}"> - <i class="fas fa-edit"></i> - </button> - <button class="btn delete-btn" data-id="${hospital.id}"> - <i class="fas fa-trash"></i> - </button> - </td> - </tr> - `; - tbody.append(tr); + // Only show approved hospitals + if (hospital.approvalStatus === 'APPROVED') { + const tr = $('<tr>').append( + $('<td>').text(hospital.name), + $('<td>').text(hospital.location), + $('<td>').text(hospital.phone), + $('<td>').text(hospital.totalBeds), + $('<td>').text(hospital.availableBeds), + $('<td>').text(hospital.occupancyRate + '%'), + $('<td>').append( + $('<span>') + .addClass('status-badge') + .addClass('approval-' + hospital.approvalStatus.toLowerCase()) + .text(hospital.approvalStatus) + ) + ); + tbody.append(tr); + } }); + + if (tbody.children().length === 0) { + tbody.append( + $('<tr>').append( + $('<td>') + .attr('colspan', '7') + .addClass('no-data') + .text('No approved hospitals found') + ) + ); + } } function initializeEventHandlers() { - // Search Handler - $("#searchButton").click(handleSearch); - // Add Hospital Handler $("#addHospitalBtn").click(function() { $("#hospitalModal").fadeIn(); @@ -159,17 +170,23 @@ $(document).ready(function () { }); } }); + + // Update event handler binding + $("#searchButton").click(handleSearch); } function handleSearch(event) { event.preventDefault(); const searchTerm = $("#searchName").val().trim(); + if (!searchTerm) { + loadHospitals(); + return; + } + $.ajax({ - url: `${API_BASE_URL}/search`, - method: 'POST', - contentType: 'application/json', - data: JSON.stringify({ name: searchTerm }), + url: `${API_BASE_URL}/search?name=${encodeURIComponent(searchTerm)}`, + method: 'GET', success: function(response) { if(response && response.code === 1) { updateTable(response.data || []); @@ -177,7 +194,10 @@ $(document).ready(function () { showError('No hospitals found'); } }, - error: handleAjaxError + error: function(xhr) { + console.error('Search Error:', xhr); + showError('Search failed'); + } }); } @@ -326,11 +346,26 @@ $(document).ready(function () { $('<style>').text(styles).appendTo('head'); - // Initialize tooltips and other UI enhancements - $('[data-toggle="tooltip"]').tooltip(); - // Add fade effects for smoother transitions $('.table-container').hide().fadeIn(); + + // Add new function for admin approval handling + function handleApproval(hospitalId, status) { + $.ajax({ + url: `${API_BASE_URL}/approval/${hospitalId}`, + method: 'PUT', + data: { status: status }, + success: function(response) { + if(response.code === 1) { + showSuccess(`Hospital ${status.toLowerCase()} successfully`); + loadHospitals(); + } else { + showError(response.msg || DEFAULT_ERROR); + } + }, + error: handleAjaxError + }); + } }); function handleSignOut() { -- GitLab