(null);
+ const [loading, setLoading] = useState(false);
const navigate = useNavigate();
function toggleMode() {
@@ -21,18 +23,47 @@ export default function Login() {
async function handleSubmit(e: FormEvent) {
e.preventDefault();
setError(null);
+ setLoading(true);
- if (mode === 'signup') {
- if (password !== confirmPassword) {
- setError('Passwords do not match.');
- return;
+ try {
+ if (mode === 'signup') {
+ if (password !== confirmPassword) {
+ setError('Passwords do not match.');
+ setLoading(false);
+ return;
+ }
+ const res = await apiFetch('/api/auth/signup', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ name, email, password }),
+ });
+ const data = await res.json();
+ if (!data.success) {
+ setError(data.message || 'Signup failed.');
+ setLoading(false);
+ return;
+ }
+ } else {
+ const res = await apiFetch('/api/auth/login', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ email, password }),
+ });
+ const data = await res.json();
+ if (!data.success) {
+ setError(data.message || 'Login failed.');
+ setLoading(false);
+ return;
+ }
}
- // await signup(name, email, password);
- } else {
- // await login(email, password);
- }
- navigate('/profile');
+ navigate('/');
+ } catch {
+ // apiFetch automatically triggers server-down navigation on network fault
+ setError('Unable to reach server.');
+ } finally {
+ setLoading(false);
+ }
}
return (
@@ -78,7 +109,9 @@ export default function Login() {
{error && {error}
}
-
+
{mode === 'signin' ? "Don't have an account?" : 'Already have an account?'}{' '}
diff --git a/frontend/src/services/apiClient.ts b/frontend/src/services/apiClient.ts
new file mode 100644
index 0000000..5470c0c
--- /dev/null
+++ b/frontend/src/services/apiClient.ts
@@ -0,0 +1,64 @@
+import { API_BASE_URL } from '../config/api';
+
+export class ServerDownError extends Error {
+ constructor(message = 'Server is unreachable') {
+ super(message);
+ this.name = 'ServerDownError';
+ }
+}
+
+// Global listener for server unreachability / fault
+let onServerDownHandler: (() => void) | null = null;
+
+export function registerServerDownHandler(handler: () => void) {
+ onServerDownHandler = handler;
+}
+
+export function triggerServerDown() {
+ if (onServerDownHandler) {
+ onServerDownHandler();
+ }
+}
+
+/**
+ * Pings the server health/status endpoint.
+ * Returns true if server responds with 2xx status, false otherwise.
+ */
+export async function pingServer(timeoutMs = 3500): Promise {
+ const controller = new AbortController();
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
+
+ try {
+ const res = await fetch(`${API_BASE_URL}/api/auth/status`, {
+ method: 'GET',
+ signal: controller.signal,
+ });
+ clearTimeout(timer);
+ return res.ok;
+ } catch {
+ clearTimeout(timer);
+ return false;
+ }
+}
+
+/**
+ * Global wrapper around fetch for server API communication.
+ * Automatically triggers server-down navigation if the server is unreachable or faults.
+ */
+export async function apiFetch(endpoint: string, options: RequestInit = {}): Promise {
+ const url = endpoint.startsWith('http') ? endpoint : `${API_BASE_URL}${endpoint}`;
+ try {
+ const response = await fetch(url, options);
+ if (response.status >= 500) {
+ triggerServerDown();
+ throw new ServerDownError(`Server error (HTTP ${response.status})`);
+ }
+ return response;
+ } catch (err) {
+ triggerServerDown();
+ if (err instanceof ServerDownError) {
+ throw err;
+ }
+ throw new ServerDownError(err instanceof Error ? err.message : 'Network error');
+ }
+}
diff --git a/frontend/tsconfig.tsbuildinfo b/frontend/tsconfig.tsbuildinfo
index 70a4da1..98ed9a7 100644
--- a/frontend/tsconfig.tsbuildinfo
+++ b/frontend/tsconfig.tsbuildinfo
@@ -1 +1 @@
-{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/context/themecontext.tsx","./src/pages/errorpage/errorpage.tsx","./src/pages/login/login.tsx"],"version":"5.9.3"}
\ No newline at end of file
+{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/config/api.ts","./src/context/themecontext.tsx","./src/pages/errorpage/errorpage.tsx","./src/pages/login/login.tsx","./src/services/apiclient.ts"],"version":"5.9.3"}
\ No newline at end of file