fix: login loading overlay, deduplicate getCookieDomain (F-18, F-11)

- Login page shows LoadingOverlay during redirect instead of blank screen
- Extract getCookieDomain() to shared lib/utils/cookies.ts
This commit is contained in:
Usman Baig
2026-03-01 21:02:28 +01:00
parent dfa887147a
commit b7426d6128
5 changed files with 24 additions and 19 deletions

View File

@@ -8,6 +8,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
### Improved ### Improved
- **Login page now shows a loading screen while redirecting.** Previously, the login page briefly showed a blank white screen before redirecting you to the sign-in page. You'll now see the Pulse logo and a "Redirecting to log in..." message, matching the signup page experience.
- **Team members can now view real-time visitor data.** Previously, only the person who originally created a site could see live visitors and session details. Now any team member in the same organization can access real-time data for all their shared sites — the same way the rest of the dashboard already works.
- **More reliable duplicate detection for goals.** When creating or updating a goal with a name that already exists, Pulse now uses the database's built-in error codes instead of checking error message text. This means duplicate goal detection works reliably regardless of database version or language settings.
- **More consistent builds across environments.** The backend Docker image now uses a pinned operating system version instead of "latest," so builds produce identical results whether run today or months from now.
- **Cleaner internal code for cookie handling.** Cookie domain logic that was duplicated in two places is now shared, reducing the chance of the two copies drifting out of sync during future changes.
- **Smoother navigation across the app.** Switching pages, changing organizations, or signing in no longer triggers unnecessary background checks. Previously, an internal effect re-ran on every navigation because it watched the entire user object for changes — now it only reacts when your authentication state or organization actually changes. This makes page transitions faster and reduces redundant network requests. - **Smoother navigation across the app.** Switching pages, changing organizations, or signing in no longer triggers unnecessary background checks. Previously, an internal effect re-ran on every navigation because it watched the entire user object for changes — now it only reacts when your authentication state or organization actually changes. This makes page transitions faster and reduces redundant network requests.
- **Faster uptime data cleanup under heavy usage.** Old uptime check records are now removed in small batches instead of all at once. Previously, a single large deletion could briefly slow down database performance when months of monitoring data had accumulated. Cleanup now runs incrementally so your dashboard stays responsive throughout. - **Faster uptime data cleanup under heavy usage.** Old uptime check records are now removed in small batches instead of all at once. Previously, a single large deletion could briefly slow down database performance when months of monitoring data had accumulated. Cleanup now runs incrementally so your dashboard stays responsive throughout.
- **More reliable automated testing.** Backend tests that verify authentication and billing no longer rely on a fragile internal shortcut that could mask real bugs. If a code change accidentally reaches the database during a test, it now fails gracefully with a clear error instead of crashing silently. - **More reliable automated testing.** Backend tests that verify authentication and billing no longer rely on a fragile internal shortcut that could mask real bugs. If a code change accidentally reaches the database during a test, it now fails gracefully with a clear error instead of crashing silently.

View File

@@ -2,19 +2,10 @@
import { cookies } from 'next/headers' import { cookies } from 'next/headers'
import { logger } from '@/lib/utils/logger' import { logger } from '@/lib/utils/logger'
import { getCookieDomain } from '@/lib/utils/cookies'
const AUTH_API_URL = process.env.NEXT_PUBLIC_AUTH_API_URL || process.env.NEXT_PUBLIC_AUTH_URL || 'http://localhost:8081' const AUTH_API_URL = process.env.NEXT_PUBLIC_AUTH_API_URL || process.env.NEXT_PUBLIC_AUTH_URL || 'http://localhost:8081'
// * Determine cookie domain dynamically
// * In production (on ciphera.net), we want to share cookies with subdomains (e.g. pulse-api.ciphera.net)
// * In local dev (localhost), we don't set a domain
const getCookieDomain = () => {
if (process.env.NODE_ENV === 'production') {
return '.ciphera.net'
}
return undefined
}
interface AuthResponse { interface AuthResponse {
access_token: string access_token: string
refresh_token: string refresh_token: string

View File

@@ -1,16 +1,9 @@
import { cookies } from 'next/headers' import { cookies } from 'next/headers'
import { NextResponse } from 'next/server' import { NextResponse } from 'next/server'
import { getCookieDomain } from '@/lib/utils/cookies'
const AUTH_API_URL = process.env.NEXT_PUBLIC_AUTH_API_URL || process.env.NEXT_PUBLIC_AUTH_URL || 'http://localhost:8081' const AUTH_API_URL = process.env.NEXT_PUBLIC_AUTH_API_URL || process.env.NEXT_PUBLIC_AUTH_URL || 'http://localhost:8081'
// * Determine cookie domain dynamically
const getCookieDomain = () => {
if (process.env.NODE_ENV === 'production') {
return '.ciphera.net'
}
return undefined
}
export async function POST() { export async function POST() {
const cookieStore = await cookies() const cookieStore = await cookies()
const refreshToken = cookieStore.get('refresh_token')?.value const refreshToken = cookieStore.get('refresh_token')?.value

View File

@@ -2,6 +2,7 @@
import { useEffect } from 'react' import { useEffect } from 'react'
import { initiateOAuthFlow } from '@/lib/api/oauth' import { initiateOAuthFlow } from '@/lib/api/oauth'
import { LoadingOverlay } from '@ciphera-net/ui'
export default function LoginPage() { export default function LoginPage() {
useEffect(() => { useEffect(() => {
@@ -9,5 +10,10 @@ export default function LoginPage() {
initiateOAuthFlow() initiateOAuthFlow()
}, []) }, [])
return null return (
<LoadingOverlay
logoSrc="/pulse_icon_no_margins.png"
title="Redirecting to log in..."
/>
)
} }

9
lib/utils/cookies.ts Normal file
View File

@@ -0,0 +1,9 @@
// * Determine cookie domain dynamically.
// * In production (on ciphera.net), we share cookies across subdomains.
// * In local dev (localhost), we don't set a domain.
export const getCookieDomain = (): string | undefined => {
if (process.env.NODE_ENV === 'production') {
return '.ciphera.net'
}
return undefined
}