Skip to content

Commit 76a0eeb

Browse files
authored
APPT-2128 Back link redirects to incorrect mya url after session timeout (#1618)
# Description This fixes an issue where the back link would redirect to an incorrect or truncated URL following a session timeout. When a session timed out, the middleware was capturing the current URL as a returnUrl but failing to correctly handle nested query parameters (specifically for the Day, Week, and Month views). Characters like & were being interpreted by the browser as part of the login redirect rather than part of the destination path, causing the return URL to be cut short. Updated middleware to use encodeURIComponent() when constructing the redirect URL. his ensures that the entire original path—including all query parameters (e.g., ?date=...&page=...) Fixes # (issue) # Checklist: - [ ] My work is behind a feature toggle (if appropriate) - [ ] If my work is behind a feature toggle, I've added a full suite of tests for both the ON and OFF state - [ ] The ticket number is in the Pull Request title, with format "APPT-XXX: My Title Here" - [ ] I have ran npm tsc / lint (in the future these will be ran automatically) - [ ] My code generates no new .NET warnings (in the future these will be treated as errors) - [ ] If I've added a new Function, it is disabled in all but one of the terraform groups (e.g. http_functions) - [ ] If I've added a new Function, it has both unit and integration tests. Any request body validators have unit tests also - [ ] If I've made UI changes, I've added appropriate Playwright and Jest tests - [ ] If I've added/updated an end-point, I've added the appropriate annotations and tested the Swagger documentation reflects the change
1 parent 420b65f commit 76a0eeb

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { render, screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
3+
import { useRouter, useSearchParams } from 'next/navigation';
4+
import { ReportsPage } from './reports-page';
5+
6+
jest.mock('next/navigation', () => ({
7+
useRouter: jest.fn(),
8+
useSearchParams: jest.fn(),
9+
}));
10+
11+
describe('ReportsPage', () => {
12+
const mockPush = jest.fn();
13+
14+
beforeEach(() => {
15+
jest.clearAllMocks();
16+
(useRouter as jest.Mock).mockReturnValue({ push: mockPush });
17+
18+
Object.defineProperty(document, 'referrer', {
19+
value: 'http://localhost/internal-path',
20+
configurable: true,
21+
});
22+
});
23+
24+
it('navigates to the encoded returnUrl when Back is clicked', async () => {
25+
const complexUrl = '/daily-appointments?date=2026-04-15&page=1';
26+
27+
(useSearchParams as jest.Mock).mockReturnValue({
28+
get: (key: string) => (key === 'returnUrl' ? complexUrl : null),
29+
});
30+
31+
const user = userEvent.setup();
32+
render(<ReportsPage />);
33+
34+
const backLink = screen.getByRole('link', { name: /Back/i });
35+
await user.click(backLink);
36+
37+
expect(mockPush).toHaveBeenCalledWith(complexUrl);
38+
});
39+
40+
it('defaults to /sites when no returnUrl is available', async () => {
41+
(useSearchParams as jest.Mock).mockReturnValue({
42+
get: () => null,
43+
});
44+
45+
const user = userEvent.setup();
46+
render(<ReportsPage />);
47+
48+
const backLink = screen.getByRole('link', { name: /Back/i });
49+
await user.click(backLink);
50+
51+
expect(mockPush).toHaveBeenCalledWith('/sites');
52+
});
53+
});

src/client/src/middleware.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { NextResponse } from 'next/server';
22
import type { NextRequest } from 'next/server';
33

44
export function middleware(request: NextRequest) {
5-
const pathAndQuery = `${request.nextUrl.pathname}${request.nextUrl.search}`;
5+
// Encode the search params (the ?... part) so that ampersands (&)
6+
// are treated as text, not as separators for the login page parameters.
7+
const pathAndQuery = `${request.nextUrl.pathname}${encodeURIComponent(request.nextUrl.search)}`;
68

79
const shouldHandle = !request.nextUrl.pathname.includes('/api/');
810

0 commit comments

Comments
 (0)