Fixed Build
This commit is contained in:
parent
a62faab6b5
commit
4f05061411
@ -24,7 +24,14 @@ export async function POST(request: Request) {
|
|||||||
let mustChangePassword = false;
|
let mustChangePassword = false;
|
||||||
try {
|
try {
|
||||||
const payload = decodeJwt(token);
|
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) {
|
} catch (err) {
|
||||||
console.error("❌ Failed to decode current JWT:", err);
|
console.error("❌ Failed to decode current JWT:", err);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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";
|
import { cookies } from "next/headers";
|
||||||
|
|
||||||
const BE_BASE_URL = process.env.BE_BASE_URL || "http://localhost:8583";
|
const BE_BASE_URL = process.env.BE_BASE_URL || "http://localhost:8583";
|
||||||
const COOKIE_NAME = "auth_token";
|
const COOKIE_NAME = "auth_token";
|
||||||
|
|
||||||
export async function PUT(
|
export async function PUT(
|
||||||
request: Request,
|
request: NextRequest,
|
||||||
{ params }: { params: { id: string } }
|
context: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const { id } = params;
|
const { id } = await context.params;
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@ -39,15 +41,14 @@ export async function PUT(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Attempt to parse JSON; fall back to status-only response
|
let data;
|
||||||
let data: unknown = null;
|
|
||||||
try {
|
try {
|
||||||
data = await resp.json();
|
data = await resp.json();
|
||||||
} catch {
|
} catch {
|
||||||
data = { success: resp.ok };
|
data = { success: resp.ok };
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json(data ?? { success: resp.ok }, {
|
return NextResponse.json(data, {
|
||||||
status: resp.status,
|
status: resp.status,
|
||||||
});
|
});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
|||||||
@ -63,10 +63,10 @@ function transformUserUpdateData(updates: Record<string, unknown>): {
|
|||||||
|
|
||||||
export async function PUT(
|
export async function PUT(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: { id: string } }
|
context: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const { id } = await params;
|
const { id } = await context.params;
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
|
|
||||||
// Transform the request body to match backend format
|
// Transform the request body to match backend format
|
||||||
@ -108,10 +108,10 @@ export async function PUT(
|
|||||||
|
|
||||||
export async function DELETE(
|
export async function DELETE(
|
||||||
_request: Request,
|
_request: Request,
|
||||||
{ params }: { params: { id: string } }
|
context: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const { id } = await params;
|
const { id } = await context.params;
|
||||||
const { cookies } = await import("next/headers");
|
const { cookies } = await import("next/headers");
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
const token = cookieStore.get(COOKIE_NAME)?.value;
|
const token = cookieStore.get(COOKIE_NAME)?.value;
|
||||||
|
|||||||
@ -5,10 +5,10 @@ const COOKIE_NAME = "auth_token";
|
|||||||
|
|
||||||
export async function PUT(
|
export async function PUT(
|
||||||
request: NextRequest,
|
request: NextRequest,
|
||||||
{ params }: { params: { id: string } }
|
context: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const { id } = await params;
|
const { id } = await context.params;
|
||||||
const { cookies } = await import("next/headers");
|
const { cookies } = await import("next/headers");
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
const token = cookieStore.get(COOKIE_NAME)?.value;
|
const token = cookieStore.get(COOKIE_NAME)?.value;
|
||||||
|
|||||||
@ -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 }
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ import React from "react";
|
|||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { Button, Box, Typography, Stack } from "@mui/material";
|
import { Button, Box, Typography, Stack } from "@mui/material";
|
||||||
import { AppDispatch } from "@/app/redux/types";
|
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() {
|
export default function TestTokenExpiration() {
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
@ -14,7 +14,7 @@ export default function TestTokenExpiration() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRefreshAuth = () => {
|
const handleRefreshAuth = () => {
|
||||||
dispatch(refreshAuthStatus());
|
dispatch(validateAuth());
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -22,7 +22,6 @@ export default function AllTransactionPage() {
|
|||||||
transactions: TransactionRow[];
|
transactions: TransactionRow[];
|
||||||
total: number;
|
total: number;
|
||||||
}>({ transactions: [], total: 0 });
|
}>({ transactions: [], total: 0 });
|
||||||
const [totalRows, setRowCount] = useState(0);
|
|
||||||
const extraColumns: string[] = []; // static for now
|
const extraColumns: string[] = []; // static for now
|
||||||
|
|
||||||
// Memoize rows to avoid new reference each render
|
// Memoize rows to avoid new reference each render
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const normalizeValue = (input: any): string => {
|
export const normalizeValue = (input: any): string => {
|
||||||
if (input == null) return "";
|
if (input == null) return "";
|
||||||
if (typeof input === "string" || typeof input === "number")
|
if (typeof input === "string" || typeof input === "number")
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"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 { DataGrid, GridPaginationModel } from "@mui/x-data-grid";
|
||||||
import { Box, Paper, Alert } from "@mui/material";
|
import { Box, Paper, Alert } from "@mui/material";
|
||||||
import DataTableHeader from "./DataTableHeader";
|
import DataTableHeader from "./DataTableHeader";
|
||||||
|
|||||||
@ -31,6 +31,8 @@ const SettingsAccountSecurity: React.FC = () => {
|
|||||||
currentPassword: passwordData.currentPassword,
|
currentPassword: passwordData.currentPassword,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
// Error handling is now done by the epic
|
// Error handling is now done by the epic
|
||||||
console.error("Password change error:", err);
|
console.error("Password change error:", err);
|
||||||
|
|||||||
@ -20,11 +20,9 @@ const SettingsPageClient: React.FC = () => {
|
|||||||
<Box sx={{ display: "flex", gap: 3 }}>
|
<Box sx={{ display: "flex", gap: 3 }}>
|
||||||
<SettingsSidebar
|
<SettingsSidebar
|
||||||
active={activeSection}
|
active={activeSection}
|
||||||
onChange={(
|
onChange={(section: "personal" | "account") =>
|
||||||
section:
|
setActiveSection(section)
|
||||||
| string
|
}
|
||||||
| ((prevState: "personal" | "account") => "personal" | "account")
|
|
||||||
) => setActiveSection(section)}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Box sx={{ flex: 1 }}>
|
<Box sx={{ flex: 1 }}>
|
||||||
|
|||||||
@ -47,6 +47,7 @@ const DeleteUser: React.FC<DeleteUserProps> = ({ open, onClose, user }) => {
|
|||||||
(resultAction.payload as string) || "Failed to delete user"
|
(resultAction.payload as string) || "Failed to delete user"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast.error(error.message || "An unexpected error occurred");
|
toast.error(error.message || "An unexpected error occurred");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { initializeAuth } from "./auth/authSlice";
|
import { validateAuth } from "./auth/authSlice";
|
||||||
import { AppDispatch } from "./types";
|
import { AppDispatch } from "./types";
|
||||||
|
|
||||||
export function InitializeAuth() {
|
export function InitializeAuth() {
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(initializeAuth());
|
dispatch(validateAuth());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { store } from "./store";
|
import { store } from "./store";
|
||||||
import { checkAuthStatus } from "./auth/authSlice";
|
import { validateAuth } from "./auth/authSlice";
|
||||||
|
|
||||||
export default function ReduxProvider({
|
export default function ReduxProvider({
|
||||||
children,
|
children,
|
||||||
@ -16,17 +16,17 @@ export default function ReduxProvider({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check authentication status when the ReduxProvider component mounts on the client.
|
// Check authentication status when the ReduxProvider component mounts on the client.
|
||||||
// This ensures your Redux auth state is synced with the server-side token.
|
// 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
|
// Do an additional check after 2 seconds to ensure we have the latest token info
|
||||||
initialCheckRef.current = setTimeout(() => {
|
initialCheckRef.current = setTimeout(() => {
|
||||||
store.dispatch(checkAuthStatus());
|
store.dispatch(validateAuth());
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
// Set up periodic token validation every 5 minutes
|
// Set up periodic token validation every 5 minutes
|
||||||
intervalRef.current = setInterval(
|
intervalRef.current = setInterval(
|
||||||
() => {
|
() => {
|
||||||
store.dispatch(checkAuthStatus());
|
store.dispatch(validateAuth());
|
||||||
},
|
},
|
||||||
5 * 60 * 1000
|
5 * 60 * 1000
|
||||||
); // 5 minutes
|
); // 5 minutes
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import toast from "react-hot-toast";
|
|||||||
import { filter, switchMap } from "rxjs/operators";
|
import { filter, switchMap } from "rxjs/operators";
|
||||||
import { of } from "rxjs";
|
import { of } from "rxjs";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const changePasswordEpic: Epic<any, any, RootState> = action$ =>
|
export const changePasswordEpic: Epic<any, any, RootState> = action$ =>
|
||||||
action$.pipe(
|
action$.pipe(
|
||||||
// Listen for any action related to changePassword (pending, fulfilled, rejected)
|
// Listen for any action related to changePassword (pending, fulfilled, rejected)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user