Refactor useAuth hook, settings components, and docs for formatting and readability improvements

- Consolidated multi-line arguments into single lines where appropriate in `useAuth`.
- Improved spacing and readability in data processing across components (`ProfileSettingsForm`, `PasswordChangeForm`, `SessionCard`).
- Applied consistent table and markdown formatting in design system docs (e.g., `README.md`, `08-ai-guidelines.md`, `00-quick-start.md`).
- Updated code snippets to ensure adherence to Prettier rules and streamlined JSX structures.
This commit is contained in:
2025-11-10 11:03:45 +01:00
parent 464a6140c4
commit 96df7edf88
208 changed files with 4056 additions and 4556 deletions

View File

@@ -9,13 +9,13 @@
* Design: Context handles dependency injection, Zustand handles state management
*/
"use client";
'use client';
import { createContext, useContext } from "react";
import type { ReactNode } from "react";
import { createContext, useContext } from 'react';
import type { ReactNode } from 'react';
// eslint-disable-next-line no-restricted-imports -- This is the DI boundary, needs real store for production
import { useAuthStore as useAuthStoreImpl } from "@/lib/stores/authStore";
import type { User } from "@/lib/stores/authStore";
import { useAuthStore as useAuthStoreImpl } from '@/lib/stores/authStore';
import type { User } from '@/lib/stores/authStore';
/**
* Authentication state shape
@@ -31,7 +31,12 @@ interface AuthState {
tokenExpiresAt: number | null;
// Actions
setAuth: (user: User, accessToken: string, refreshToken: string, expiresIn?: number) => Promise<void>;
setAuth: (
user: User,
accessToken: string,
refreshToken: string,
expiresIn?: number
) => Promise<void>;
setTokens: (accessToken: string, refreshToken: string, expiresIn?: number) => Promise<void>;
setUser: (user: User) => void;
clearAuth: () => Promise<void>;
@@ -120,7 +125,7 @@ export function useAuth<T>(selector?: (state: AuthState) => T): AuthState | T {
const storeHook = useContext(AuthContext);
if (!storeHook) {
throw new Error("useAuth must be used within AuthProvider");
throw new Error('useAuth must be used within AuthProvider');
}
// Call the Zustand hook internally (follows React Rules of Hooks)

View File

@@ -34,13 +34,10 @@ async function getEncryptionKey(): Promise<CryptoKey> {
if (storedKey) {
try {
const keyData = JSON.parse(storedKey);
return await crypto.subtle.importKey(
'jwk',
keyData,
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
return await crypto.subtle.importKey('jwk', keyData, { name: 'AES-GCM', length: 256 }, true, [
'encrypt',
'decrypt',
]);
} catch (error) {
// Corrupted key, regenerate
console.warn('Failed to import stored key, generating new key:', error);
@@ -49,11 +46,10 @@ async function getEncryptionKey(): Promise<CryptoKey> {
}
// Generate new key
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, [
'encrypt',
'decrypt',
]);
// Store key in sessionStorage
try {
@@ -86,11 +82,7 @@ export async function encryptData(data: string): Promise<string> {
const encoder = new TextEncoder();
const encodedData = encoder.encode(data);
const encryptedData = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
encodedData
);
const encryptedData = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encodedData);
// Combine IV and encrypted data
const combined = new Uint8Array(iv.length + encryptedData.byteLength);
@@ -122,17 +114,13 @@ export async function decryptData(encryptedData: string): Promise<string> {
const key = await getEncryptionKey();
// Decode from base64
const combined = Uint8Array.from(atob(encryptedData), c => c.charCodeAt(0));
const combined = Uint8Array.from(atob(encryptedData), (c) => c.charCodeAt(0));
// Extract IV and encrypted data
const iv = combined.slice(0, 12);
const data = combined.slice(12);
const decryptedData = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
data
);
const decryptedData = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, data);
const decoder = new TextDecoder();
return decoder.decode(decryptedData);

View File

@@ -1,11 +1,7 @@
// Authentication utilities
// Examples: Token management, auth helpers, session utilities, etc.
export {
encryptData,
decryptData,
clearEncryptionKey,
} from './crypto';
export { encryptData, decryptData, clearEncryptionKey } from './crypto';
export {
saveTokens,

View File

@@ -25,7 +25,10 @@ export type StorageMethod = 'cookie' | 'localStorage';
* This flag is set by E2E tests to skip encryption for easier testing
*/
function isE2ETestMode(): boolean {
return typeof window !== 'undefined' && (window as { __PLAYWRIGHT_TEST__?: boolean }).__PLAYWRIGHT_TEST__ === true;
return (
typeof window !== 'undefined' &&
(window as { __PLAYWRIGHT_TEST__?: boolean }).__PLAYWRIGHT_TEST__ === true
);
}
/**
@@ -162,10 +165,14 @@ export async function getTokens(): Promise<TokenStorage | null> {
const parsed = JSON.parse(stored);
// Validate structure - must have required fields
if (!parsed || typeof parsed !== 'object' ||
!('accessToken' in parsed) || !('refreshToken' in parsed) ||
(parsed.accessToken !== null && typeof parsed.accessToken !== 'string') ||
(parsed.refreshToken !== null && typeof parsed.refreshToken !== 'string')) {
if (
!parsed ||
typeof parsed !== 'object' ||
!('accessToken' in parsed) ||
!('refreshToken' in parsed) ||
(parsed.accessToken !== null && typeof parsed.accessToken !== 'string') ||
(parsed.refreshToken !== null && typeof parsed.refreshToken !== 'string')
) {
throw new Error('Invalid token structure');
}
@@ -177,10 +184,14 @@ export async function getTokens(): Promise<TokenStorage | null> {
const parsed = JSON.parse(decrypted);
// Validate structure - must have required fields
if (!parsed || typeof parsed !== 'object' ||
!('accessToken' in parsed) || !('refreshToken' in parsed) ||
(parsed.accessToken !== null && typeof parsed.accessToken !== 'string') ||
(parsed.refreshToken !== null && typeof parsed.refreshToken !== 'string')) {
if (
!parsed ||
typeof parsed !== 'object' ||
!('accessToken' in parsed) ||
!('refreshToken' in parsed) ||
(parsed.accessToken !== null && typeof parsed.accessToken !== 'string') ||
(parsed.refreshToken !== null && typeof parsed.refreshToken !== 'string')
) {
/* istanbul ignore next - Validation error path */
throw new Error('Invalid token structure');
}