diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj
index 34bfc34..e554d2b 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj
@@ -102,7 +102,7 @@
true
_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories)
+ $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)core\sharedmemory;$(ProjectDir)core\events;%(AdditionalIncludeDirectories)
Console
@@ -117,7 +117,7 @@
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories)
+ $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)core\sharedmemory;$(ProjectDir)core\events;%(AdditionalIncludeDirectories)
Console
@@ -126,10 +126,11 @@
+
+
-
@@ -148,21 +149,23 @@
+
+
+
+
+
+
+
+
-
-
-
-
-
-
@@ -191,6 +194,7 @@
+
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters
index c13b320..ac65e97 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters
@@ -64,11 +64,17 @@
{8057b93d-51a9-42df-b06e-01ce395f6308}
-
- {ec639004-44c6-4bd6-9963-077adde82b5f}
+
+ {d9da9793-fe6f-4914-bee3-99d5934da228}
-
- {7aa8722e-adfa-466e-8211-de63f3b7892b}
+
+ {0769afb6-f57d-4ae3-a1cf-ceca6e606af0}
+
+
+ {85029bdb-6941-41dc-a3a7-9e5841671d8c}
+
+
+ {1050aca7-6f2c-4ccb-a446-db9c898c3599}
@@ -144,8 +150,14 @@
Source Files\Models
-
- Source Files\DataStores\SharedMemory
+
+ Source Files\Core\SharedMemory
+
+
+ Source Files\Core\Events
+
+
+ Source Files\Views
@@ -254,26 +266,32 @@
Header Files\Views
-
- Header Files\DataStores\SharedMemory
-
-
- Header Files\DataStores\SharedMemory
-
-
- Header Files\DataStores\SharedMemory
-
-
- Header Files\DataStores\SharedMemory
-
-
- Header Files\DataStores\SharedMemory
-
-
- Header Files\DataStores\SharedMemory
-
Header Files\DataStores
+
+ Header Files\Core\SharedMemory
+
+
+ Header Files\Core\SharedMemory
+
+
+ Header Files\Core\SharedMemory
+
+
+ Header Files\Core\SharedMemory
+
+
+ Header Files\Core\SharedMemory
+
+
+ Header Files\Core\SharedMemory
+
+
+ Header Files\Core\Events
+
+
+ Header Files\Views
+
\ No newline at end of file
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp
index 487ecd5..d892e36 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp
@@ -622,3 +622,16 @@ void Controller::shutdown()
auto& dataStore = DataStore::getInstance();
dataStore.shutdown();
}
+
+/*
+Function: registerEvents
+Description: Registers menu event handles with the authentication
+ service.
+Parameter: HANDLE accountDisabledEvent - account disabled event handle
+ HANDLE notificationAvailableEvent - notification event handle
+Return type: void
+*/
+void Controller::registerEvents(HANDLE accountDisabledEvent, HANDLE notificationAvailableEvent)
+{
+ m_authenticationManagementService.registerEvents(accountDisabledEvent, notificationAvailableEvent);
+}
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h
index 7ec1c30..622c7b7 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h
@@ -8,6 +8,7 @@ Date:19-May-2026
*/
#pragma once
+#include
#include
#include "AuthenticationManagementService.h"
#include "Enums.h"
@@ -72,4 +73,5 @@ public:
void configureNotifications(bool paymentNotifications, bool serviceNotifications);
bool initialize();
void shutdown();
+ void registerEvents(HANDLE accountDisabledEvent, HANDLE notificationAvailableEvent);
};
\ No newline at end of file
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.cpp
new file mode 100644
index 0000000..568a0e6
--- /dev/null
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.cpp
@@ -0,0 +1,225 @@
+/*
+File: EventManager.cpp
+Description: Implementation file containing the method definitions of the
+ EventManager class, including listener management and
+ interprocess event publishing.
+Author: Trenser
+Date:15-Jun-2026
+*/
+
+#include
+#include
+#include "EventManager.h"
+
+namespace
+{
+ const std::string USER_DISABLED_EVENT = "userDisabled_";
+
+ const std::string NOTIFICATION_AVAILABLE_EVENT = "notificationAvailable_";
+}
+
+/*
+Function: EventManager
+Description: Constructs an EventManager instance with default values.
+Parameter: None
+Return type: None
+*/
+EventManager::EventManager()
+ :
+ m_userDisabledEvent(NULL),
+ m_notificationAvailableEvent(NULL),
+ m_shutdownEvent(NULL),
+ m_running(false) {}
+
+/*
+Function: ~EventManager
+Description: Destroys the EventManager and performs final cleanup.
+Parameter: None
+Return type: None
+*/
+EventManager::~EventManager()
+{
+ shutdown();
+ if (m_listenerThread.joinable())
+ {
+ m_listenerThread.join();
+ }
+}
+
+/*
+Function: initialize
+Description: Creates the user-specific events and starts the listener
+ thread.
+Parameter: const std::string& userId - unique identifier of the user
+ std::function userDisabledCallback - callback for
+ user disable events
+ std::function notificationCallback - callback for
+ notification events
+Return type: bool - true if initialization succeeds, false otherwise
+*/
+bool EventManager::initialize(const std::string& userId, std::function userDisabledCallback, std::function notificationCallback)
+{
+ if (m_running.load())
+ {
+ return false;
+ }
+ m_userDisabledCallback = userDisabledCallback;
+ m_notificationCallback = notificationCallback;
+ m_userDisabledEvent = CreateEventA(NULL, FALSE, FALSE, (USER_DISABLED_EVENT + userId).c_str());
+ if (!m_userDisabledEvent)
+ {
+ return false;
+ }
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ CloseHandle(m_userDisabledEvent);
+ m_userDisabledEvent = NULL;
+ throw std::runtime_error("Only one session allowed per user.");
+ }
+ m_notificationAvailableEvent = CreateEventA(NULL, FALSE, FALSE, (NOTIFICATION_AVAILABLE_EVENT + userId).c_str());
+ if (!m_notificationAvailableEvent)
+ {
+ CloseHandle(m_userDisabledEvent);
+ m_userDisabledEvent = NULL;
+ return false;
+ }
+ m_shutdownEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+ if (!m_shutdownEvent)
+ {
+ CloseHandle(m_userDisabledEvent);
+ CloseHandle(m_notificationAvailableEvent);
+ m_userDisabledEvent = NULL;
+ m_notificationAvailableEvent = NULL;
+ return false;
+ }
+ m_running.store(true);
+ m_listenerThread = std::thread(&EventManager::run, this);
+ return true;
+}
+
+/*
+Function: shutdown
+Description: Stops the listener thread and releases event resources.
+Parameter: None
+Return type: None
+*/
+void EventManager::shutdown()
+{
+ if (!m_running.load())
+ {
+ return;
+ }
+ m_running.store(false);
+ if (m_shutdownEvent)
+ {
+ SetEvent(m_shutdownEvent);
+ }
+ if (m_listenerThread.joinable())
+ {
+ if (std::this_thread::get_id() != m_listenerThread.get_id())
+ {
+ m_listenerThread.join();
+ }
+ }
+ if (m_userDisabledEvent)
+ {
+ CloseHandle(m_userDisabledEvent);
+ m_userDisabledEvent = NULL;
+ }
+ if (m_notificationAvailableEvent)
+ {
+ CloseHandle(m_notificationAvailableEvent);
+ m_notificationAvailableEvent = NULL;
+ }
+ if (m_shutdownEvent)
+ {
+ CloseHandle(m_shutdownEvent);
+ m_shutdownEvent = NULL;
+ }
+}
+
+/*
+Function: run
+Description: Waits for and dispatches user-related events.
+Parameter: None
+Return type: void
+*/
+void EventManager::run()
+{
+ HANDLE handles[3];
+ handles[0] = m_userDisabledEvent;
+ handles[1] = m_notificationAvailableEvent;
+ handles[2] = m_shutdownEvent;
+ while (m_running.load())
+ {
+ DWORD result = WaitForMultipleObjects(3, handles, FALSE, INFINITE);
+ switch (result)
+ {
+ case WAIT_OBJECT_0:
+ try
+ {
+ if (m_userDisabledCallback)
+ {
+ m_userDisabledCallback();
+ }
+ }
+ catch (const std::exception& exception)
+ {
+ std::cout << exception.what() << std::endl;
+ }
+ break;
+ case WAIT_OBJECT_0 + 1:
+ try
+ {
+ if (m_notificationCallback)
+ {
+ m_notificationCallback();
+ }
+ }
+ catch (const std::exception& exception)
+ {
+ std::cout << exception.what() << std::endl;
+ }
+ break;
+ case WAIT_OBJECT_0 + 2:
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+Function: sendUserDisabledEvent
+Description: Publishes a user disabled event for a specific user.
+Parameter: const std::string& userId - target user identifier
+Return type: void
+*/
+void EventManager::sendUserDisabledEvent(const std::string& userId)
+{
+ HANDLE eventHandle = CreateEventA(NULL, FALSE, FALSE, (USER_DISABLED_EVENT + userId).c_str());
+ if (!eventHandle)
+ {
+ return;
+ }
+ SetEvent(eventHandle);
+ CloseHandle(eventHandle);
+}
+
+/*
+Function: sendNotificationAvailableEvent
+Description: Publishes a notification available event for a specific
+ user.
+Parameter: const std::string& userId - target user identifier
+Return type: void
+*/
+void EventManager::sendNotificationAvailableEvent(const std::string& userId)
+{
+ HANDLE eventHandle = CreateEventA(NULL, FALSE, FALSE, (NOTIFICATION_AVAILABLE_EVENT + userId).c_str());
+ if (!eventHandle)
+ {
+ return;
+ }
+ SetEvent(eventHandle);
+ CloseHandle(eventHandle);
+}
\ No newline at end of file
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.h
new file mode 100644
index 0000000..01de6c4
--- /dev/null
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.h
@@ -0,0 +1,37 @@
+/*
+File: EventManager.h
+Description: Header file declaring the EventManager class, which manages
+ user-specific interprocess events for user disable and
+ notification availability updates.
+Author: Trenser
+Date:15-Jun-2026
+*/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+class EventManager
+{
+private:
+ HANDLE m_userDisabledEvent;
+ HANDLE m_notificationAvailableEvent;
+ HANDLE m_shutdownEvent;
+ std::atomic m_running;
+ std::thread m_listenerThread;
+ std::function m_userDisabledCallback;
+ std::function m_notificationCallback;
+ void run();
+
+public:
+ EventManager();
+ ~EventManager();
+ bool initialize(const std::string& userId, std::function userDisabledCallback, std::function notificationCallback);
+ void shutdown();
+ static void sendUserDisabledEvent(const std::string& userId);
+ static void sendNotificationAvailableEvent(const std::string& userId);
+};
\ No newline at end of file
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/FileHeader.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/FileHeader.h
similarity index 100%
rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/FileHeader.h
rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/FileHeader.h
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/MappingInfo.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/MappingInfo.h
similarity index 100%
rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/MappingInfo.h
rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/MappingInfo.h
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/RecordState.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/RecordState.h
similarity index 100%
rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/RecordState.h
rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/RecordState.h
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SerializedRecords.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SerializedRecords.h
similarity index 100%
rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SerializedRecords.h
rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SerializedRecords.h
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.cpp
similarity index 100%
rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp
rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.cpp
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.h
similarity index 100%
rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.h
rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.h
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/TrackedRecord.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/TrackedRecord.h
similarity index 100%
rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/TrackedRecord.h
rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/TrackedRecord.h
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp
index 71d66b6..f573da9 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp
@@ -14,6 +14,9 @@ Date:19-May-2026
#include "DataStoreLockGuard.h"
User* AuthenticationManagementService::m_authenticatedUser = nullptr;
+EventManager AuthenticationManagementService::m_eventManager;
+HANDLE AuthenticationManagementService::m_accountDisabledEvent = NULL;
+HANDLE AuthenticationManagementService::m_notificationsAvailableEvent = NULL;
/*
Function: login
@@ -37,6 +40,22 @@ bool AuthenticationManagementService::login(const std::string& username, const s
if (password == user->getPassword())
{
m_authenticatedUser = user;
+ m_eventManager.initialize(
+ user->getId(),
+ []()
+ {
+ if (m_accountDisabledEvent)
+ {
+ SetEvent(m_accountDisabledEvent);
+ }
+ },
+ []()
+ {
+ if (m_notificationsAvailableEvent)
+ {
+ SetEvent(m_notificationsAvailableEvent);
+ }
+ });
return true;
}
return false;
@@ -65,7 +84,10 @@ Return type: void
*/
void AuthenticationManagementService::logout()
{
+ m_eventManager.shutdown();
m_authenticatedUser = nullptr;
+ m_accountDisabledEvent = NULL;
+ m_notificationsAvailableEvent = NULL;
}
/*
@@ -92,3 +114,17 @@ void AuthenticationManagementService::changePassword(const std::string& newPassw
trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED;
m_dataStore.saveUsers();
}
+
+/*
+Function: registerEvents
+Description: Registers menu event handles used to notify the active
+ menu of account disable and notification events.
+Parameter: HANDLE accountDisabledEvent - account disabled event handle
+ HANDLE notificationAvailableEvent - notification event handle
+Return type: void
+*/
+void AuthenticationManagementService::registerEvents(HANDLE accountDisabledEvent, HANDLE notifictionAvailableEvent)
+{
+ m_accountDisabledEvent = accountDisabledEvent;
+ m_notificationsAvailableEvent = notifictionAvailableEvent;
+}
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h
index 47266a1..d512892 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h
@@ -9,6 +9,8 @@ Date:19-May-2026
#pragma once
#include
+#include
+#include "EventManager.h"
#include "DataStore.h"
class User;
@@ -17,6 +19,9 @@ class AuthenticationManagementService
{
private:
static User* m_authenticatedUser;
+ static EventManager m_eventManager;
+ static HANDLE m_accountDisabledEvent;
+ static HANDLE m_notificationsAvailableEvent;
DataStore& m_dataStore;
public:
AuthenticationManagementService() : m_dataStore(DataStore::getInstance()) {}
@@ -24,4 +29,5 @@ public:
void logout();
void changePassword(const std::string& newPassword);
User* getAuthenticatedUser();
+ void registerEvents(HANDLE accountDisabledEvent, HANDLE notificationAvailableEvent);
};
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp
index 8e17739..a007ac1 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp
@@ -19,6 +19,7 @@ Date: 22-May-2026
#include "Utility.h"
#include "Vector.h"
#include "DataStoreLockGuard.h"
+#include "EventManager.h"
util::Map InventoryManagementService::m_observers{};
@@ -281,5 +282,6 @@ void InventoryManagementService::sendNotification(User* user, const std::string&
auto& trackedNotificationsMap = m_dataStore.getNotifications();
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications();
+ EventManager::sendNotificationAvailableEvent(user->getId());
}
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp
index dc42a5b..09bf1da 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp
@@ -22,6 +22,7 @@ Date: 20-May-2026
#include "User.h"
#include "Utility.h"
#include "DataStoreLockGuard.h"
+#include "EventManager.h"
util::Map PaymentManagementService::m_observers{};
@@ -109,6 +110,7 @@ void PaymentManagementService::sendNotification(User* user, const std::string& t
auto& trackedNotificationsMap = m_dataStore.getNotifications();
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications();
+ EventManager::sendNotificationAvailableEvent(user->getId());
}
/*
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp
index ed59380..cf438d0 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp
@@ -27,6 +27,7 @@ Date:19-May-2026
#include "DataStoreLockGuard.h"
#include "Utility.h"
#include "DataStoreLockGuard.h"
+#include "EventManager.h"
/*
Function: purchaseService
@@ -199,6 +200,7 @@ void ServiceManagementService::sendNotification(User* user, const std::string& t
auto& trackedNotificationsMap = m_dataStore.getNotifications();
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications();
+ EventManager::sendNotificationAvailableEvent(user->getId());
}
/*
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp
index e923e1c..ab85936 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp
@@ -22,6 +22,7 @@ Date:19-May-2026
#include "Utility.h"
#include "TrackedRecord.h"
#include "DataStoreLockGuard.h"
+#include "EventManager.h"
/*
Function: ensureAdminExists
@@ -267,30 +268,38 @@ void UserManagementService::removeUser(const std::string& userID)
InventoryManagementService inventoryManagementService;
PaymentManagementService paymentManagementService;
ServiceManagementService serviceManagementService;
- DataStoreLockGuard lock(m_dataStore);
- auto& trackedUsersMap = m_dataStore.getUsers();
- int index = trackedUsersMap.find(userID);
- if (index != -1)
+ std::string removedUserID;
{
- User* user = trackedUsersMap.getValueAt(index).data;
- if (user != nullptr)
+ DataStoreLockGuard lock(m_dataStore);
+ auto& trackedUsersMap = m_dataStore.getUsers();
+ int index = trackedUsersMap.find(userID);
+ if (index != -1)
{
- if (user->getUserType() == util::UserType::CUSTOMER)
+ User* user = trackedUsersMap.getValueAt(index).data;
+ if (user != nullptr)
{
- serviceManagementService.cancelCustomerServiceBookings(userID);
+ if (user->getUserType() == util::UserType::CUSTOMER)
+ {
+ serviceManagementService.cancelCustomerServiceBookings(userID);
+ }
+ if (user->getUserType() == util::UserType::TECHNICIAN)
+ {
+ serviceManagementService.cancelTechnicianJobs(userID);
+ }
+ inventoryManagementService.detach(user);
+ paymentManagementService.detach(user);
+ serviceManagementService.detach(user);
+ user->setState(util::State::INACTIVE);
+ trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED;
+ removedUserID = user->getId();
+ m_dataStore.saveUsers();
}
- if (user->getUserType() == util::UserType::TECHNICIAN)
- {
- serviceManagementService.cancelTechnicianJobs(userID);
- }
- inventoryManagementService.detach(user);
- paymentManagementService.detach(user);
- serviceManagementService.detach(user);
- user->setState(util::State::INACTIVE);
- trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED;
- m_dataStore.saveUsers();
}
}
+ if (!removedUserID.empty())
+ {
+ EventManager::sendUserDisabledEvent(removedUserID);
+ }
}
/*
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp
index 76a1901..68ec663 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp
@@ -30,10 +30,16 @@ Return type: void
*/
void AdminMenu::showMenu()
{
+ startEventListener();
while (true)
{
try
{
+ if (!m_isMenuActive)
+ {
+ logout();
+ break;
+ }
int choice;
util::clear();
std::cout << "Admin Menu"
@@ -68,6 +74,7 @@ void AdminMenu::showMenu()
util::pressEnter();
}
}
+ stopEventListener();
}
/*
@@ -78,6 +85,11 @@ Return type: bool - true if menu continues, false if logout
*/
bool AdminMenu::handleOperation(int choice)
{
+ if (!m_isMenuActive)
+ {
+ logout();
+ return false;
+ }
switch (choice)
{
case 1:
@@ -141,6 +153,19 @@ bool AdminMenu::handleOperation(int choice)
return true;
}
+/*
+Function: handleNotificationEvent
+Description: Retrieves and displays the latest notification for the
+ currently logged in admin.
+Parameter: None
+Return type: void
+*/
+void AdminMenu::handleNotificationEvent()
+{
+ auto notifications = m_controller.getNotifications();
+ displayNewNotification(notifications);
+}
+
/*
Function: logout
Description: Logs out the currently authenticated admin user.
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h
index bdffcb6..f9aa415 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h
@@ -9,12 +9,13 @@ Date:19-May-2026
#pragma once
#include "Controller.h"
+#include "Menu.h"
-class AdminMenu
+class AdminMenu : public Menu
{
private:
- Controller m_controller;
bool handleOperation(int choice);
+ void handleNotificationEvent() override;
public:
void showMenu();
void logout();
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp
index 0d60f97..3932fba 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp
@@ -32,10 +32,17 @@ Return type: void
*/
void CustomerMenu::showMenu()
{
+
+ startEventListener();
while (true)
{
try
{
+ if (!m_isMenuActive)
+ {
+ logout();
+ break;
+ }
int choice;
util::clear();
std::cout << "Customer Menu"
@@ -62,6 +69,7 @@ void CustomerMenu::showMenu()
util::pressEnter();
}
}
+ stopEventListener();
}
/*
@@ -72,6 +80,11 @@ Return type: bool - true if menu continues, false if logout
*/
bool CustomerMenu::handleOperation(int choice)
{
+ if (!m_isMenuActive)
+ {
+ logout();
+ return false;
+ }
switch (choice)
{
case 1:
@@ -111,6 +124,19 @@ bool CustomerMenu::handleOperation(int choice)
return true;
}
+/*
+Function: handleNotificationEvent
+Description: Retrieves and displays the latest notification for the
+ currently logged in admin.
+Parameter: None
+Return type: void
+*/
+void CustomerMenu::handleNotificationEvent()
+{
+ auto notifications = m_controller.getNotifications();
+ displayNewNotification(notifications);
+}
+
/*
Function: logout
Description: Logs out the currently authenticated customer user.
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h
index d491720..c619107 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h
@@ -9,13 +9,14 @@ Date:19-May-2026
*/
#pragma once
+#include "Menu.h"
#include "Controller.h"
-class CustomerMenu
+class CustomerMenu : public Menu
{
private:
- Controller m_controller;
bool handleOperation(int choice);
+ void handleNotificationEvent();
public:
void showMenu();
void logout();
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp
new file mode 100644
index 0000000..2573c0e
--- /dev/null
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp
@@ -0,0 +1,144 @@
+/*
+File: Menu.cpp
+Description: Implementation file containing common menu event listener
+ functionality, account disable handling, and notification
+ event dispatching for all menu types.
+Author: Trenser
+Date:16-Jun-2026
+*/
+
+#include "Menu.h"
+
+/*
+Function: Menu
+Description: Constructs a Menu object and initializes event handles
+ and menu state.
+Parameter: None
+Return type: None
+*/
+Menu::Menu()
+ :
+ m_isMenuActive(false),
+ m_accountDisabledEvent(NULL),
+ m_notificationAvailableEvent(NULL),
+ m_shutdownEvent(NULL) {}
+
+/*
+Function: ~Menu
+Description: Destroys the Menu object and performs event listener
+ cleanup.
+Parameter: None
+Return type: None
+*/
+Menu::~Menu()
+{
+ stopEventListener();
+}
+
+/*
+Function: startEventListener
+Description: Creates menu event handles, registers them with the
+ authentication service, and starts the event listener
+ thread.
+Parameter: None
+Return type: void
+*/
+void Menu::startEventListener()
+{
+ if (m_isMenuActive.load())
+ {
+ return;
+ }
+ m_isMenuActive.store(true);
+ m_accountDisabledEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+ m_notificationAvailableEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+ m_shutdownEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+ m_controller.registerEvents(m_accountDisabledEvent, m_notificationAvailableEvent);
+ m_eventListenerThread = std::thread(&Menu::eventListenerLoop, this);
+}
+
+/*
+Function: eventListenerLoop
+Description: Waits for account disabled, notification available,
+ and shutdown events and dispatches them to the
+ appropriate handlers.
+Parameter: None
+Return type: void
+*/
+void Menu::eventListenerLoop()
+{
+ HANDLE handles[3];
+ handles[0] = m_accountDisabledEvent;
+ handles[1] = m_notificationAvailableEvent;
+ handles[2] = m_shutdownEvent;
+ while (m_isMenuActive.load())
+ {
+ DWORD result = WaitForMultipleObjects(3, handles, FALSE, INFINITE);
+ switch (result)
+ {
+ case WAIT_OBJECT_0:
+ handleAccountDisabledEvent();
+ break;
+ case WAIT_OBJECT_0 + 1:
+ handleNotificationEvent();
+ break;
+ case WAIT_OBJECT_0 + 2:
+ return;
+ }
+ }
+}
+
+/*
+Function: stopEventListener
+Description: Stops the event listener thread and releases all
+ associated event handles.
+Parameter: None
+Return type: void
+*/
+void Menu::stopEventListener()
+{
+ m_isMenuActive.store(false);
+ if (m_shutdownEvent)
+ {
+ SetEvent(m_shutdownEvent);
+ }
+ if (m_eventListenerThread.joinable())
+ {
+ m_eventListenerThread.join();
+ }
+ if (m_accountDisabledEvent)
+ {
+ CloseHandle(m_accountDisabledEvent);
+ }
+ if (m_notificationAvailableEvent)
+ {
+ CloseHandle(m_notificationAvailableEvent);
+ }
+ if (m_shutdownEvent)
+ {
+ CloseHandle(m_shutdownEvent);
+ }
+ m_accountDisabledEvent = NULL;
+ m_notificationAvailableEvent = NULL;
+ m_shutdownEvent = NULL;
+}
+
+/*
+Function: handleAccountDisabledEvent
+Description: Handles an account disabled event by marking the menu
+ inactive and notifying the user.
+Parameter: None
+Return type: void
+*/
+void Menu::handleAccountDisabledEvent()
+{
+ m_isMenuActive.store(false);
+ MessageBoxA(
+ GetConsoleWindow(),
+ "Your account has been disabled.",
+ "Account Disabled",
+ MB_OK |
+ MB_ICONWARNING |
+ MB_SETFOREGROUND |
+ MB_TOPMOST);
+}
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.h
new file mode 100644
index 0000000..146efa8
--- /dev/null
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.h
@@ -0,0 +1,33 @@
+/*
+File: Menu.h
+Description: Base class providing common event listener functionality
+ for all menu implementations.
+Author: Trenser
+Date:16-Jun-2026
+*/
+
+#pragma once
+
+#include
+#include
+#include
+#include "Controller.h"
+
+class Menu
+{
+protected:
+ Controller m_controller;
+ std::atomic m_isMenuActive;
+ HANDLE m_accountDisabledEvent;
+ HANDLE m_notificationAvailableEvent;
+ HANDLE m_shutdownEvent;
+ std::thread m_eventListenerThread;
+ void startEventListener();
+ void stopEventListener();
+ void eventListenerLoop();
+ void handleAccountDisabledEvent();
+ virtual void handleNotificationEvent() = 0;
+public:
+ Menu();
+ virtual ~Menu();
+};
\ No newline at end of file
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h
index c6ebaa6..0d0f695 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h
@@ -1407,4 +1407,38 @@ inline std::string selectComboPackage(util::Map notifications -
+ collection of notifications
+Return type: void
+*/
+inline void displayNewNotification(util::Vector notifications)
+{
+ const Notification* notification = nullptr;
+ size_t numberOfNotifications = notifications.getSize();
+ for (int index = 0; index < numberOfNotifications; index++)
+ {
+ if (!notification)
+ {
+ notification = notifications[index];
+ }
+ else
+ {
+ if (notification->getId() < notifications[index]->getId())
+ {
+ notification = notifications[index];
+ }
+ }
+ }
+ MessageBoxA(
+ GetConsoleWindow(),
+ notification->getMessage().c_str(),
+ notification->getTitle().c_str(),
+ MB_OK |
+ MB_ICONINFORMATION);
}
\ No newline at end of file
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp
index 8ff3e12..4b090d8 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp
@@ -27,10 +27,16 @@ Returns:
*/
void TechnicianMenu::showMenu()
{
+ startEventListener();
while (true)
{
try
{
+ if (!m_isMenuActive)
+ {
+ logout();
+ break;
+ }
int choice;
util::clear();
std::cout << "Technician Menu"
@@ -52,6 +58,7 @@ void TechnicianMenu::showMenu()
util::pressEnter();
}
}
+ stopEventListener();
}
/*
@@ -62,6 +69,11 @@ Return type: bool - true if menu continues, false if logout
*/
bool TechnicianMenu::handleOperation(int choice)
{
+ if (!m_isMenuActive)
+ {
+ logout();
+ return false;
+ }
switch (choice)
{
case 1:
@@ -86,6 +98,19 @@ bool TechnicianMenu::handleOperation(int choice)
return true;
}
+/*
+Function: handleNotificationEvent
+Description: Retrieves and displays the latest notification for the
+ currently logged in admin.
+Parameter: None
+Return type: void
+*/
+void TechnicianMenu::handleNotificationEvent()
+{
+ auto notifications = m_controller.getNotifications();
+ displayNewNotification(notifications);
+}
+
/*
Function: displayJobs
Description: Displays all Jobs assigned to a Technician
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h
index 2d118a0..b00c1f3 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h
@@ -9,12 +9,13 @@ Date:19-May-2026
#pragma once
#include "Controller.h"
+#include "Menu.h"
-class TechnicianMenu
+class TechnicianMenu : public Menu
{
private:
- Controller m_controller;
bool handleOperation(int choice);
+ void handleNotificationEvent();
public:
void showMenu();
void displayJobs();