diff --git a/app/api/auth/change-password/route.ts b/app/api/auth/change-password/route.ts index 559d50c..399aaa4 100644 --- a/app/api/auth/change-password/route.ts +++ b/app/api/auth/change-password/route.ts @@ -24,7 +24,14 @@ export async function POST(request: Request) { let mustChangePassword = false; try { const payload = decodeJwt(token); - mustChangePassword = payload.MustChangePassword || false; + const mustChangeClaim = payload.MustChangePassword; + if (typeof mustChangeClaim === "boolean") { + mustChangePassword = mustChangeClaim; + } else if (typeof mustChangeClaim === "string") { + mustChangePassword = mustChangeClaim.toLowerCase() === "true"; + } else { + mustChangePassword = false; + } } catch (err) { console.error("❌ Failed to decode current JWT:", err); } diff --git a/app/api/auth/reset-password/[id]/route.ts b/app/api/auth/reset-password/[id]/route.ts index 8f49468..75c63bd 100644 --- a/app/api/auth/reset-password/[id]/route.ts +++ b/app/api/auth/reset-password/[id]/route.ts @@ -1,15 +1,17 @@ -import { NextResponse } from "next/server"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import { NextResponse, type NextRequest } from "next/server"; import { cookies } from "next/headers"; const BE_BASE_URL = process.env.BE_BASE_URL || "http://localhost:8583"; const COOKIE_NAME = "auth_token"; export async function PUT( - request: Request, - { params }: { params: { id: string } } + request: NextRequest, + context: { params: Promise<{ id: string }> } ) { try { - const { id } = params; + const { id } = await context.params; if (!id) { return NextResponse.json( @@ -39,15 +41,14 @@ export async function PUT( } ); - // Attempt to parse JSON; fall back to status-only response - let data: unknown = null; + let data; try { data = await resp.json(); } catch { data = { success: resp.ok }; } - return NextResponse.json(data ?? { success: resp.ok }, { + return NextResponse.json(data, { status: resp.status, }); } catch (error: unknown) { diff --git a/app/api/dashboard/admin/users/[id]/route.ts b/app/api/dashboard/admin/users/[id]/route.ts index 50f15fc..9a9c5df 100644 --- a/app/api/dashboard/admin/users/[id]/route.ts +++ b/app/api/dashboard/admin/users/[id]/route.ts @@ -63,10 +63,10 @@ function transformUserUpdateData(updates: Record): { export async function PUT( request: Request, - { params }: { params: { id: string } } + context: { params: Promise<{ id: string }> } ) { try { - const { id } = await params; + const { id } = await context.params; const body = await request.json(); // Transform the request body to match backend format @@ -108,10 +108,10 @@ export async function PUT( export async function DELETE( _request: Request, - { params }: { params: { id: string } } + context: { params: Promise<{ id: string }> } ) { try { - const { id } = await params; + const { id } = await context.params; const { cookies } = await import("next/headers"); const cookieStore = await cookies(); const token = cookieStore.get(COOKIE_NAME)?.value; diff --git a/app/api/dashboard/transactions/[id]/route.ts b/app/api/dashboard/transactions/[id]/route.ts index bca9543..2702f90 100644 --- a/app/api/dashboard/transactions/[id]/route.ts +++ b/app/api/dashboard/transactions/[id]/route.ts @@ -5,10 +5,10 @@ const COOKIE_NAME = "auth_token"; export async function PUT( request: NextRequest, - { params }: { params: { id: string } } + context: { params: Promise<{ id: string }> } ) { try { - const { id } = await params; + const { id } = await context.params; const { cookies } = await import("next/headers"); const cookieStore = await cookies(); const token = cookieStore.get(COOKIE_NAME)?.value; diff --git a/app/api/settings/route.ts b/app/api/settings/route.ts index e69de29..89ac520 100644 --- a/app/api/settings/route.ts +++ b/app/api/settings/route.ts @@ -0,0 +1,13 @@ +import { NextResponse } from "next/server"; + +/** + * Placeholder Settings API route. + * Keeps the module valid while the real implementation + * is being built, and makes the intent obvious to clients. + */ +export async function GET() { + return NextResponse.json( + { message: "Settings endpoint not implemented" }, + { status: 501 } + ); +} diff --git a/app/components/TestTokenExpiration.tsx b/app/components/TestTokenExpiration.tsx index f4e67c9..1fdd530 100644 --- a/app/components/TestTokenExpiration.tsx +++ b/app/components/TestTokenExpiration.tsx @@ -4,7 +4,7 @@ import React from "react"; import { useDispatch } from "react-redux"; import { Button, Box, Typography, Stack } from "@mui/material"; import { AppDispatch } from "@/app/redux/types"; -import { autoLogout, refreshAuthStatus } from "@/app/redux/auth/authSlice"; +import { autoLogout, validateAuth } from "@/app/redux/auth/authSlice"; export default function TestTokenExpiration() { const dispatch = useDispatch(); @@ -14,7 +14,7 @@ export default function TestTokenExpiration() { }; const handleRefreshAuth = () => { - dispatch(refreshAuthStatus()); + dispatch(validateAuth()); }; return ( diff --git a/app/dashboard/transactions/all/page.tsx b/app/dashboard/transactions/all/page.tsx index dca5190..637b155 100644 --- a/app/dashboard/transactions/all/page.tsx +++ b/app/dashboard/transactions/all/page.tsx @@ -22,7 +22,6 @@ export default function AllTransactionPage() { transactions: TransactionRow[]; total: number; }>({ transactions: [], total: 0 }); - const [totalRows, setRowCount] = useState(0); const extraColumns: string[] = []; // static for now // Memoize rows to avoid new reference each render diff --git a/app/features/AdvancedSearch/utils/utils.ts b/app/features/AdvancedSearch/utils/utils.ts index 412ed5a..2ea578d 100644 --- a/app/features/AdvancedSearch/utils/utils.ts +++ b/app/features/AdvancedSearch/utils/utils.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export const normalizeValue = (input: any): string => { if (input == null) return ""; if (typeof input === "string" || typeof input === "number") diff --git a/app/features/DataTable/DataTable.tsx b/app/features/DataTable/DataTable.tsx index 86a8b75..1816a8b 100644 --- a/app/features/DataTable/DataTable.tsx +++ b/app/features/DataTable/DataTable.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useState, useEffect, useCallback, useMemo } from "react"; +import React, { useState, useCallback, useMemo } from "react"; import { DataGrid, GridPaginationModel } from "@mui/x-data-grid"; import { Box, Paper, Alert } from "@mui/material"; import DataTableHeader from "./DataTableHeader"; diff --git a/app/features/Pages/Settings/SettingsAccountSecurity.tsx b/app/features/Pages/Settings/SettingsAccountSecurity.tsx index 668cf78..170981f 100644 --- a/app/features/Pages/Settings/SettingsAccountSecurity.tsx +++ b/app/features/Pages/Settings/SettingsAccountSecurity.tsx @@ -31,6 +31,8 @@ const SettingsAccountSecurity: React.FC = () => { currentPassword: passwordData.currentPassword, }) ); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { // Error handling is now done by the epic console.error("Password change error:", err); diff --git a/app/features/Pages/Settings/SettingsPageClient.tsx b/app/features/Pages/Settings/SettingsPageClient.tsx index b3438b6..fe31548 100644 --- a/app/features/Pages/Settings/SettingsPageClient.tsx +++ b/app/features/Pages/Settings/SettingsPageClient.tsx @@ -20,11 +20,9 @@ const SettingsPageClient: React.FC = () => { "personal" | "account") - ) => setActiveSection(section)} + onChange={(section: "personal" | "account") => + setActiveSection(section) + } /> diff --git a/app/features/UserRoles/DeleteUser/DeleteUser.tsx b/app/features/UserRoles/DeleteUser/DeleteUser.tsx index adc585b..3fa929f 100644 --- a/app/features/UserRoles/DeleteUser/DeleteUser.tsx +++ b/app/features/UserRoles/DeleteUser/DeleteUser.tsx @@ -47,6 +47,7 @@ const DeleteUser: React.FC = ({ open, onClose, user }) => { (resultAction.payload as string) || "Failed to delete user" ); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { toast.error(error.message || "An unexpected error occurred"); } diff --git a/app/redux/InitializeAuth.tsx b/app/redux/InitializeAuth.tsx index 7db3d15..f61fba9 100644 --- a/app/redux/InitializeAuth.tsx +++ b/app/redux/InitializeAuth.tsx @@ -2,14 +2,14 @@ import { useEffect } from "react"; import { useDispatch } from "react-redux"; -import { initializeAuth } from "./auth/authSlice"; +import { validateAuth } from "./auth/authSlice"; import { AppDispatch } from "./types"; export function InitializeAuth() { const dispatch = useDispatch(); useEffect(() => { - dispatch(initializeAuth()); + dispatch(validateAuth()); }, [dispatch]); return null; diff --git a/app/redux/ReduxProvider.tsx b/app/redux/ReduxProvider.tsx index 369d925..e393c1a 100644 --- a/app/redux/ReduxProvider.tsx +++ b/app/redux/ReduxProvider.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useRef } from "react"; import { Provider } from "react-redux"; import { store } from "./store"; -import { checkAuthStatus } from "./auth/authSlice"; +import { validateAuth } from "./auth/authSlice"; export default function ReduxProvider({ children, @@ -16,17 +16,17 @@ export default function ReduxProvider({ useEffect(() => { // Check authentication status when the ReduxProvider component mounts on the client. // This ensures your Redux auth state is synced with the server-side token. - store.dispatch(checkAuthStatus()); + store.dispatch(validateAuth()); // Do an additional check after 2 seconds to ensure we have the latest token info initialCheckRef.current = setTimeout(() => { - store.dispatch(checkAuthStatus()); + store.dispatch(validateAuth()); }, 2000); // Set up periodic token validation every 5 minutes intervalRef.current = setInterval( () => { - store.dispatch(checkAuthStatus()); + store.dispatch(validateAuth()); }, 5 * 60 * 1000 ); // 5 minutes diff --git a/app/redux/user/epic.ts b/app/redux/user/epic.ts index 4fda5a8..dfa8d0e 100644 --- a/app/redux/user/epic.ts +++ b/app/redux/user/epic.ts @@ -5,6 +5,7 @@ import toast from "react-hot-toast"; import { filter, switchMap } from "rxjs/operators"; import { of } from "rxjs"; +// eslint-disable-next-line @typescript-eslint/no-explicit-any export const changePasswordEpic: Epic = action$ => action$.pipe( // Listen for any action related to changePassword (pending, fulfilled, rejected)