/* File: AdminMenu.cpp Description: Implements the AdminMenu class which provides the administrator’s console interface in the Vehicle Service Management System. Handles menu display, user input, and admin-specific operations such as inventory management, technician management, service creation, combo package management, job assignment, and notifications. Author: Trenser Date: 19-May-2026 */ #include #include #include "AdminMenu.h" #include "Enums.h" #include "InputHelper.h" #include "InventoryItem.h" #include "MenuHelper.h" #include "OutputHelper.h" #include "Service.h" #include "ServiceBooking.h" #include "User.h" #include "Utility.h" #include "Validator.h" /* Function: showMenu Description: Displays the admin menu and handles user input until logout is selected. Parameter: None Return type: void */ void AdminMenu::showMenu() { while (true) { try { int choice; util::clear(); std::cout << "Admin Menu" << "\n1. View Stock Levels" << "\n2. Add Inventory Item" << "\n3. Remove Inventory Item" << "\n4. Check Stock Availability" << "\n5. Assign Job to Technician" << "\n6. Add Technician" << "\n7. Remove Customer/Technician" << "\n8. Create Service" << "\n9. Remove Service" << "\n10. Create Combo Package" << "\n11. Remove Combo Package" << "\n12. View Notifications" << "\n13. Change Password" << "\n14. Logout" << "\nEnter a choice: "; util::read(choice); if (!handleOperation(choice)) { break; } } catch (const std::exception& e) { std::cout << "Exception: " << e.what() << std::endl; util::pressEnter(); } } } /* Function: handleOperation Description: Executes the corresponding admin operation based on the selected menu choice. Parameter: int choice - selected menu option Return type: bool - true if menu continues, false if logout */ bool AdminMenu::handleOperation(int choice) { switch (choice) { case 1: viewStockLevels(); break; case 2: addInventoryItem(); break; case 3: removeInventoryItem(); break; case 4: checkStockAvailability(); break; case 5: assignJob(); break; case 6: addTechnician(); break; case 7: removeUser(); break; case 8: createService(); break; case 9: removeService(); break; case 10: createComboPackages(); break; case 11: removeComboPackage(); break; case 12: viewNotifications(); break; case 13: changePassword(); break; case 14: logout(); return false; default: std::cout << "Enter a valid choice!" << std::endl; util::pressEnter(); } return true; } /* Function: logout Description: Logs out the currently authenticated admin user. Parameter: None Return type: void */ void AdminMenu::logout() { m_controller.logout(); } /* Function: changePassword Description: Allows the admin to change their password after validation. Parameter: None Return type: void */ void AdminMenu::changePassword() { changePasswordHelper(m_controller); } /* Function: viewStockLevels Description: Displays all active inventory items with their details including ID, part name, quantity, and price. Parameter: None Return type: void */ void AdminMenu::viewStockLevels() { util::clear(); auto inventoryItems = m_controller.getInventoryItems(); bool hasActiveItems = false; if (inventoryItems.isEmpty()) { std::cout << "No items found in Inventory.\n"; util::pressEnter(); return; } for (int index = 0; index < inventoryItems.getSize(); index++) { const InventoryItem* item = inventoryItems.getValueAt(index); if (item->getState() == util::State::ACTIVE) { hasActiveItems = true; break; } } if (!hasActiveItems) { std::cout << "No active Inventory Item found.\n"; util::pressEnter(); return; } std::cout << std::left << std::setw(15) << "Item ID" << std::setw(25) << "Part Name" << std::setw(15) << "Quantity" << std::setw(15) << "Price" << std::endl; for (int iterator = 0; iterator < inventoryItems.getSize(); ++iterator) { const InventoryItem* item = inventoryItems.getValueAt(iterator); if (item != nullptr) { if (item->getState() != util::State::INACTIVE) { std::cout << std::left << std::setw(15) << item->getId() << std::setw(25) << item->getPartName() << std::setw(15) << item->getQuantity() << std::setw(15) << item->getPrice() << std::endl; } } } std::cout << "\n"; util::pressEnter(); } /* Function: addInventoryItem Description: Allows the admin to either add a new inventory item or increase the quantity of an existing item. Parameter: None Return type: void */ void AdminMenu::addInventoryItem() { util::clear(); int choice, quantity; double price; std::string partName; std::cout << "1. Add new item \n2. Add Quantity\nEnter your choice : "; util::read(choice); switch (choice) { case 1: { std::cout << "--------Enter Item Details----------\n"; std::cout << "Part Name : "; util::read(partName); std::cout << "Quantity : "; util::read(quantity); std::cout << "Price : "; util::read(price); m_controller.addInventoryItem(partName, quantity, price); std::cout << "New Item " << partName << " added to the Inventory.\n"; break; } case 2: { auto inventoryItems = m_controller.getInventoryItems(); addQuantityToItem(inventoryItems, m_controller); break; } } util::pressEnter(); } /* Function: removeInventoryItem Description: Removes an active inventory item by marking it inactive after user selection. Parameter: None Return type: void */ void AdminMenu::removeInventoryItem() { util::clear(); auto inventoryItems = m_controller.getInventoryItems(); auto activeItems = filterActiveItems(inventoryItems); int activeItemsSize = activeItems.getSize(); if (activeItemsSize == 0) { std::cout << "No items available in Inventory." << std::endl; util::pressEnter(); return; } displayInventoryWithItems(activeItems); int itemIndex; std::cout << "Enter the index of the item to remove: "; util::read(itemIndex); if (itemIndex < 1 || itemIndex > activeItemsSize) { std::cout << "Invalid index selected." << std::endl; util::pressEnter(); return; } const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1); if (selectedItem != nullptr) { if(selectedItem->getState() != util::State::INACTIVE) { std::string selectedItemId = selectedItem->getId(); m_controller.removeInventoryItem(selectedItemId); std::cout << "Item " << selectedItem->getPartName() << " removed successfully." << std::endl; } } util::pressEnter(); } /* Function: checkStockAvailability Description: Checks if a specific inventory item is available and displays its details if active. Parameter: None Return type: void */ void AdminMenu::checkStockAvailability() { util::clear(); std::string itemId; std::cout << "Enter the Item Id : "; util::read(itemId); const InventoryItem* selectedItem = m_controller.getInventoryItem(itemId); if (selectedItem != nullptr) { if (selectedItem->getState() != util::State::INACTIVE) { std::cout << "Item Details\n"; std::cout << "---------------------------------------------\n"; std::cout << "Item ID : " << selectedItem->getId() << "\n"; std::cout << "Part Name : " << selectedItem->getPartName() << "\n"; std::cout << "Quantity : " << selectedItem->getQuantity() << "\n"; } } util::pressEnter(); } /* Function: assignJob Description: Allows the admin to assign pending service bookings to available technicians. Creates job cards for selected services. Parameters: - None Returns: - void */ void AdminMenu::assignJob() { util::clear(); std::string selectedService; bool hasPendingService = false; auto currentBookings = m_controller.getServiceBookings(); auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN); int bookingsSize = currentBookings.getSize(); util::Map serviceBookingsMap; util::Map currentAvailableTechniciansMap; if (listServiceBookings(currentBookings, bookingsSize, serviceBookingsMap)) { const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap); if (selectedService) { if (availableTechnicians.getSize() != 0) { listAvailableTechnicians(availableTechnicians, availableTechnicians.getSize(), currentAvailableTechniciansMap); const User* selectedTechnician = selectTechnician(currentAvailableTechniciansMap); if (selectedTechnician) { auto& servicesInBooking = selectedService->getServices(); for (int iterator = 0; iterator < servicesInBooking.getSize(); iterator++) { m_controller.createJobCard(selectedService->getId(), selectedTechnician->getId(), servicesInBooking.getValueAt(iterator)->getId()); } } } else { std::cout << "No technicians are currently available."; } } } util::pressEnter(); } /* Function: createService Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost. Parameters: - None Returns: - void */ void AdminMenu::createService() { util::clear(); std::string serviceName; double labourCost; std::cout << "Enter the service name: "; util::read(serviceName); util::Map currentInventoryItems = m_controller.getInventoryItems(); util::Vector selectedInventoryItems; selectInventoryItems(currentInventoryItems,selectedInventoryItems); std::cout << "Enter the labour cost: "; util::read(labourCost); m_controller.createService(serviceName, selectedInventoryItems, labourCost); std::cout << "Service created sucessfully.\n"; util::pressEnter(); } /* Function: removeService Description: Allows the admin to remove an existing service by selecting from available services. Parameters: - None Returns: - void */ void AdminMenu::removeService() { util::clear(); std::string selectedServiceID; util::Map currentServices = m_controller.getServices(); selectedServiceID = selectServicesToRemove(currentServices); if (selectedServiceID != "") { m_controller.removeService(selectedServiceID); std::cout << "Service removed sucessfully."; } else { std::cout << "Failed to remove service."; } util::pressEnter(); } /* Function: addTechnician Description: Adds a new technician after validating username, password, email, and phone number. Parameter: None Return type: void */ void AdminMenu::addTechnician() { util::clear(); std::string username, name, password, email, phoneNumber; std::cout << std::left << std::setw(25) << "Enter Technician Username: "; util::read(username); std::cout << std::left << std::setw(25) << "Enter Technician Name: "; util::read(name); std::cout << std::setw(25) << "Enter Technician Password: "; util::read(password); if(!util::isPasswordValid(password)) { std::cout << "Error: Password is invalid!"; util::pressEnter(); return; } std::cout << std::setw(25) << "Enter Technician Email: "; util::read(email); if(!util::isEmailValid(email)) { std::cout << "Error: Email is invalid!"; util::pressEnter(); return; } std::cout << std::setw(25) << "Enter Technician Phone: "; util::read(phoneNumber); if(!util::isPhoneNumberValid(phoneNumber)) { std::cout << "Error: Phone Number is invalid!"; util::pressEnter(); return; } m_controller.createTechnician(username, name, password, email, phoneNumber); std::cout << "\nTechnician Added Successfully.\n"; util::pressEnter(); } /* Function: removeUser Description: Removes a selected active user (customer or technician) from the system. Parameter: None Return type: void */ void AdminMenu::removeUser() { util::clear(); int indexChoice; auto listOfUsers = m_controller.getUsers(); auto listOfActiveUsers = filterActiveUsers(listOfUsers); int activeUserCount = listOfActiveUsers.getSize(); if (activeUserCount < 1) { std::cout << "No Active users." << std::endl; util::pressEnter(); return; } displayAllActiveUsers(listOfActiveUsers, activeUserCount); std::cout << "Enter the index of the user to delete : "; util::read(indexChoice); if (indexChoice < 1 || indexChoice > activeUserCount) { std::cout << "Error Invaild index.\n" << std::endl; util::pressEnter(); return; } const User* userToRemove = listOfActiveUsers.getValueAt(indexChoice - 1); if (userToRemove != nullptr) { std::string userIdToRemove = userToRemove->getId(); m_controller.removeUser(userIdToRemove); std::cout << userToRemove->getUserName() << " removed Successfully.\n"; } util::pressEnter(); } /* Function: createComboPackages Description: Creates a new combo package by selecting two active services and applying a discount. Parameter: None Return type: void */ void AdminMenu::createComboPackages() { util::clear(); auto serviceList = m_controller.getServices(); const int NUMBER_OF_SERVICE_PER_PACKAGE = 2; util::Vector selectedServiceID; for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++) { const Service* chosenService = nullptr; while (true) { chosenService = selectServiceFromServices(serviceList); if (chosenService == nullptr) { std::cout << "Failed to create combo package!"; util::pressEnter(); return; } bool alreadyChosen = false; for (int iteratorOne = 0; iteratorOne < selectedServiceID.getSize(); iteratorOne++) { if (selectedServiceID[iteratorOne] == chosenService->getId()) { alreadyChosen = true; break; } } if (alreadyChosen) { std::cout << "Service already selected. Please choose a different one." << std::endl; continue; } selectedServiceID.push_back(chosenService->getId()); util::clear(); break; } } std::string packageName; double discountPercentage; std::cout << "Enter combo package name: "; util::read(packageName); std::cout << "Enter discount percentage: "; util::read(discountPercentage); if (discountPercentage < 0.0 || discountPercentage > 100.0) { std::cout << "Error: Discount percentage must be between 0 and 100." << std::endl; util::pressEnter(); return; } m_controller.createComboPackage(packageName, selectedServiceID, discountPercentage); std::cout << "Combo package '" << packageName << "' created successfully." << std::endl; util::pressEnter(); } /* Function: removeComboPackage Description: Removes a selected combo package from the system. Parameter: None Return type: void */ void AdminMenu::removeComboPackage() { util::clear(); util::Map currentComboPackages = m_controller.getComboPackages(); std::string selectedComboPackageID = selectComboPackage(currentComboPackages); if (selectedComboPackageID != "") { m_controller.removeComboPackage(selectedComboPackageID); std::cout << "Combo Package removed successfully.\n"; } else { std::cout << "Combo package removal failed.\n"; } util::pressEnter(); } /* Function: viewNotifications Description: Displays notifications for the admin and allows deletion of notifications. Parameters: - None Returns: - void */ void AdminMenu::viewNotifications() { viewAndDeleteNotification(m_controller); }