diff --git a/src/web/Jordnaer/Components/App.razor b/src/web/Jordnaer/Components/App.razor
index 7c171bd7..43a25136 100644
--- a/src/web/Jordnaer/Components/App.razor
+++ b/src/web/Jordnaer/Components/App.razor
@@ -69,7 +69,12 @@
@*TODO: Add loading image*@
-
+
+ @*Start and reconnection logic based on: https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-7.0#automatically-refresh-the-page-when-server-side-reconnection-fails*@
+
+
+
+
diff --git a/src/web/Jordnaer/wwwroot/js/boot.js b/src/web/Jordnaer/wwwroot/js/boot.js
new file mode 100644
index 00000000..e3cbf6ea
--- /dev/null
+++ b/src/web/Jordnaer/wwwroot/js/boot.js
@@ -0,0 +1,59 @@
+(() => {
+ const maximumRetryCount = 3;
+ const retryIntervalMilliseconds = 5000;
+ const reconnectModal = document.getElementById('reconnect-modal');
+
+ const startReconnectionProcess = () => {
+ reconnectModal.style.display = 'block';
+
+ let isCanceled = false;
+
+ (async () => {
+ for (let i = 0; i < maximumRetryCount; i++) {
+ reconnectModal.innerText = `Attempting to reconnect: ${i + 1} of ${maximumRetryCount}`;
+
+ await new Promise(resolve => setTimeout(resolve, retryIntervalMilliseconds));
+
+ if (isCanceled) {
+ return;
+ }
+
+ try {
+ const result = await Blazor.reconnect();
+ if (!result) {
+ // The server was reached, but the connection was rejected; reload the page.
+ location.reload();
+ return;
+ }
+
+ // Successfully reconnected to the server.
+ return;
+ } catch {
+ // Didn't reach the server; try again.
+ }
+ }
+
+ // Retried too many times; reload the page.
+ location.reload();
+ })();
+
+ return {
+ cancel: () => {
+ isCanceled = true;
+ reconnectModal.style.display = 'none';
+ }
+ };
+ };
+
+ let currentReconnectionProcess = null;
+
+ Blazor.start({
+ reconnectionHandler: {
+ onConnectionDown: () => currentReconnectionProcess ??= startReconnectionProcess(),
+ onConnectionUp: () => {
+ currentReconnectionProcess?.cancel();
+ currentReconnectionProcess = null;
+ }
+ }
+ });
+})();
\ No newline at end of file