diff --git a/client/src/Pages/Auth/Login/Components/EmailStep.jsx b/client/src/Pages/Auth/Login/Components/EmailStep.jsx
index 6615277ba..cea175da3 100644
--- a/client/src/Pages/Auth/Login/Components/EmailStep.jsx
+++ b/client/src/Pages/Auth/Login/Components/EmailStep.jsx
@@ -70,8 +70,17 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => {
color="accent"
type="submit"
disabled={errors.email && true}
+ className="dashboard-style-button"
sx={{
width: "30%",
+ px: theme.spacing(6),
+ borderRadius: `${theme.shape.borderRadius}px !important`,
+ '&.MuiButtonBase-root': {
+ borderRadius: `${theme.shape.borderRadius}px !important`
+ },
+ '&.MuiButton-root': {
+ borderRadius: `${theme.shape.borderRadius}px !important`
+ },
"&.Mui-focusVisible": {
outline: `2px solid ${theme.palette.primary.main}`,
outlineOffset: `2px`,
diff --git a/client/src/Pages/Auth/Login/Components/PasswordStep.jsx b/client/src/Pages/Auth/Login/Components/PasswordStep.jsx
index 0b8142161..a57246e23 100644
--- a/client/src/Pages/Auth/Login/Components/PasswordStep.jsx
+++ b/client/src/Pages/Auth/Login/Components/PasswordStep.jsx
@@ -75,8 +75,16 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
variant="outlined"
color="info"
onClick={onBack}
+ className="dashboard-style-button"
sx={{
px: theme.spacing(5),
+ borderRadius: `${theme.shape.borderRadius}px !important`,
+ '&.MuiButtonBase-root': {
+ borderRadius: `${theme.shape.borderRadius}px !important`
+ },
+ '&.MuiButton-root': {
+ borderRadius: `${theme.shape.borderRadius}px !important`
+ },
"& svg.MuiSvgIcon-root": {
mr: theme.spacing(3),
},
@@ -95,13 +103,22 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
type="submit"
loading={authState.isLoading}
disabled={errors.password && true}
+ className="dashboard-style-button"
sx={{
width: "30%",
+ px: theme.spacing(4),
+ borderRadius: `${theme.shape.borderRadius}px !important`,
+ '&.MuiButtonBase-root': {
+ borderRadius: `${theme.shape.borderRadius}px !important`
+ },
+ '&.MuiButton-root': {
+ borderRadius: `${theme.shape.borderRadius}px !important`
+ },
"&.Mui-focusVisible": {
outline: `2px solid ${theme.palette.primary.main}`,
outlineOffset: `2px`,
- boxShadow: `none`,
},
+ boxShadow: `none`,
}}
>
{t("continue")}
diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx
index aec72167b..8ac831a40 100644
--- a/client/src/Pages/Auth/Login/Login.jsx
+++ b/client/src/Pages/Auth/Login/Login.jsx
@@ -6,11 +6,9 @@ import { credentials } from "../../../Validation/validation";
import { login } from "../../../Features/Auth/authSlice";
import { useDispatch, useSelector } from "react-redux";
import { createToast } from "../../../Utils/toastUtils";
-import { useTranslation } from "react-i18next";
import { networkService } from "../../../main";
import Background from "../../../assets/Images/background-grid.svg?react";
import Logo from "../../../assets/icons/checkmate-icon.svg?react";
-import { logger } from "../../../Utils/Logger";
import "../index.css";
import EmailStep from "./Components/EmailStep";
import PasswordStep from "./Components/PasswordStep";
@@ -45,21 +43,12 @@ const Login = () => {
const [errors, setErrors] = useState({});
const [step, setStep] = useState(0);
+
+
useEffect(() => {
if (authToken) {
navigate("/uptime");
- return;
}
- networkService
- .doesSuperAdminExist()
- .then((response) => {
- if (response.data.data === false) {
- navigate("/register");
- }
- })
- .catch((error) => {
- logger.error(error);
- });
}, [authToken, navigate]);
const handleChange = (event) => {
@@ -238,6 +227,31 @@ const Login = () => {
email={form.email}
errorEmail={errors.email}
/>
+
+ {/* Registration link */}
+
+
+ {t("doNotHaveAccount")}
+
+ navigate("/register")}
+ >
+ {t("registerHere")}
+
+
);
diff --git a/client/src/Pages/ServerUnreachable.jsx b/client/src/Pages/ServerUnreachable.jsx
new file mode 100644
index 000000000..aaa61cbc4
--- /dev/null
+++ b/client/src/Pages/ServerUnreachable.jsx
@@ -0,0 +1,161 @@
+import React, { useState } from "react";
+import { Box, Typography, Button, Stack } from "@mui/material";
+import { useTheme } from "@emotion/react";
+import { useNavigate } from "react-router";
+import { networkService } from "../Utils/NetworkService";
+import Alert from "../Components/Alert";
+import { createToast } from "../Utils/toastUtils";
+import { useTranslation } from "react-i18next";
+import Background from "../assets/Images/background-grid.svg?react";
+import Logo from "../assets/icons/checkmate-icon.svg?react";
+import ThemeSwitch from "../Components/ThemeSwitch";
+import LanguageSelector from "../Components/LanguageSelector";
+
+const ServerUnreachable = () => {
+ const theme = useTheme();
+ const navigate = useNavigate();
+ const { t } = useTranslation();
+
+ // State for tracking connection check status
+ const [isCheckingConnection, setIsCheckingConnection] = useState(false);
+
+ const handleRetry = React.useCallback(async () => {
+ setIsCheckingConnection(true);
+ try {
+ // Try to connect to the backend with a simple API call
+ // We'll use any lightweight endpoint that doesn't require authentication
+ await networkService.axiosInstance.get('/health', { timeout: 5000 });
+
+ // If successful, show toast and navigate to login page
+ createToast({
+ body: t("backendReconnected", "Connection to server restored"),
+ });
+ navigate("/login");
+ } catch (error) {
+ // If still unreachable, stay on this page and show toast
+ createToast({
+ body: t("backendStillUnreachable", "Server is still unreachable"),
+ });
+ } finally {
+ setIsCheckingConnection(false);
+ }
+ }, [navigate, t]);
+
+ return (
+
+
+
+
+
+ {/* Header with logo */}
+
+
+
+ Checkmate
+
+
+
+
+
+
+ .MuiStack-root": {
+ border: 1,
+ borderRadius: theme.spacing(5),
+ borderColor: theme.palette.primary.lowContrast,
+ backgroundColor: theme.palette.primary.main,
+ padding: {
+ xs: theme.spacing(12),
+ sm: theme.spacing(20),
+ },
+ },
+ }}
+ >
+
+
+
+
+
+
+ {t("backendUnreachableMessage", "The Checkmate server is not responding. Please check your deployment configuration or try again later.")}
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ServerUnreachable;
diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx
index f5a1adcae..e334af912 100644
--- a/client/src/Routes/index.jsx
+++ b/client/src/Routes/index.jsx
@@ -36,6 +36,9 @@ import DistributedUptimeDetails from "../Pages/DistributedUptime/Details";
import CreateDistributedUptimeStatus from "../Pages/DistributedUptimeStatus/Create";
import DistributedUptimeStatus from "../Pages/DistributedUptimeStatus/Status";
+// Server Status
+import ServerUnreachable from "../Pages/ServerUnreachable";
+
// Incidents
import Incidents from "../Pages/Incidents";
@@ -285,6 +288,10 @@ const Routes = () => {
element={}
/> */}
+ }
+ />
}
diff --git a/client/src/Utils/NetworkService.js b/client/src/Utils/NetworkService.js
index 76ad659ec..3be13bff9 100644
--- a/client/src/Utils/NetworkService.js
+++ b/client/src/Utils/NetworkService.js
@@ -45,9 +45,16 @@ class NetworkService {
this.axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
+ // Handle network errors (server unreachable)
if (error.code === "ERR_NETWORK") {
- // Do error handling here
+ // Navigate to server unreachable page
+ navigate("/server-unreachable");
+ // Return an empty resolved promise to stop the error propagation
+ return Promise.reject(error);
}
+
+ // Handle authentication errors
+
if (error.response && error.response.status === 401) {
dispatch(clearAuthState());
dispatch(clearUptimeMonitorState());
@@ -508,6 +515,8 @@ class NetworkService {
return this.axiosInstance.get("/auth/users/superadmin");
}
+
+
/**
* ************************************
* Get all users
diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json
index d74df8f3d..a2db25374 100644
--- a/client/src/locales/gb.json
+++ b/client/src/locales/gb.json
@@ -1,5 +1,7 @@
{
"dontHaveAccount": "Don't have account",
+ "doNotHaveAccount": "Do not have an account?",
+ "registerHere": "Register here",
"email": "E-mail",
"forgotPassword": "Forgot Password",
"password": "Password",
@@ -106,6 +108,14 @@
"settingsFailedToAddDemoMonitors": "Failed to add demo monitors",
"settingsMonitorsDeleted": "Successfully deleted all monitors",
"settingsFailedToDeleteMonitors": "Failed to delete all monitors",
+ "backendUnreachable": "Server Connection Error",
+ "backendUnreachableMessage": "We're unable to connect to the server. Please check your internet connection or verify your deployment configuration if the problem persists.",
+ "backendUnreachableError": "Cannot connect to the server. Please try again later.",
+ "retryConnection": "Retry connection",
+ "retryingConnection": "Connecting...",
+ "backendReconnected": "Successfully reconnected to the server.",
+ "backendStillUnreachable": "Server is still unreachable. Please try again later.",
+ "backendConnectionError": "Error connecting to the server. Please check your network connection.",
"starPromptTitle": "Star Checkmate",
"starPromptDescription": "See the latest releases and help grow the community on GitHub",
"https": "HTTPS",
diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json
index 700224b86..5536b5e45 100644
--- a/client/src/locales/ru.json
+++ b/client/src/locales/ru.json
@@ -1,5 +1,7 @@
{
"dontHaveAccount": "Нет аккаунта",
+ "doNotHaveAccount": "У вас нет учетной записи?",
+ "registerHere": "Зарегистрироваться здесь",
"email": "Почта",
"forgotPassword": "Забыли пароль",
"password": "Пароль",
@@ -119,6 +121,14 @@
"settingsFailedToAddDemoMonitors": "Не удалось добавить демонстрационные мониторы",
"settingsMonitorsDeleted": "Успешно удалены все мониторы",
"settingsFailedToDeleteMonitors": "Не удалось удалить все мониторы",
+ "backendUnreachable": "Ошибка подключения к серверу",
+ "backendUnreachableMessage": "Мы не можем подключиться к серверу. Пожалуйста, проверьте ваше интернет-соединение или проверьте конфигурацию развертывания, если проблема не устраняется.",
+ "backendUnreachableError": "Невозможно подключиться к серверу. Пожалуйста, повторите попытку позже.",
+ "retryConnection": "Повторить подключение",
+ "retryingConnection": "Подключение...",
+ "backendReconnected": "Успешно восстановлено подключение к серверу.",
+ "backendStillUnreachable": "Сервер по-прежнему недоступен. Пожалуйста, повторите попытку позже.",
+ "backendConnectionError": "Ошибка подключения к серверу. Пожалуйста, проверьте ваше сетевое подключение.",
"starPromptTitle": "Star Checkmate",
"starPromptDescription": "Ознакомьтесь с последними релизами и помогите развить сообщество на GitHub",
"https": "HTTPS",
diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json
index 2323a54b8..5df644fdd 100644
--- a/client/src/locales/tr.json
+++ b/client/src/locales/tr.json
@@ -1,5 +1,7 @@
{
"dontHaveAccount": "Hesabınız yok mu",
+ "doNotHaveAccount": "Hesabınız yok mu?",
+ "registerHere": "Buradan kayıt olun",
"email": "E-posta",
"forgotPassword": "Parolamı unuttum",
"password": "Parola",
@@ -104,6 +106,14 @@
"settingsFailedToAddDemoMonitors": "Demo monitörler eklenemedi",
"settingsMonitorsDeleted": "Tüm monitörler başarıyla silindi",
"settingsFailedToDeleteMonitors": "Monitörler silinemedi",
+ "backendUnreachable": "Sunucu Bağlantı Hatası",
+ "backendUnreachableMessage": "Sunucuya bağlanamıyoruz. Lütfen internet bağlantınızı kontrol edin veya sorun devam ederse dağıtım yapılandırmanızı doğrulayın.",
+ "backendUnreachableError": "Sunucuya bağlanılamıyor. Lütfen daha sonra tekrar deneyin.",
+ "retryConnection": "Bağlantıyı Yeniden Dene",
+ "retryingConnection": "Bağlanıyor...",
+ "backendReconnected": "Sunucuya başarıyla yeniden bağlandı.",
+ "backendStillUnreachable": "Sunucu hala erişilemez durumda. Lütfen daha sonra tekrar deneyin.",
+ "backendConnectionError": "Sunucuya bağlanırken hata oluştu. Lütfen ağ bağlantınızı kontrol edin.",
"starPromptTitle": "Checkmate yıldızla değerlendirin",
"starPromptDescription": "En son sürümleri görün ve GitHub'daki topluluğun büyümesine yardımcı olun",
"https": "HTTPS",