Function bodies 106 total
buildPath function · typescript · L67-L84 (18 LOC)apps/web/src/lib/i18n/paths.ts
export function buildPath(
basePath: string,
lang: Language,
searchParams?: Record<string, string | number | boolean>
): string {
const localizedPath = getLocalizedPath(basePath, lang);
if (!searchParams || Object.keys(searchParams).length === 0) {
return localizedPath;
}
const params = new URLSearchParams();
Object.entries(searchParams).forEach(([key, value]) => {
params.append(key, String(value));
});
return `${localizedPath}?${params.toString()}`;
}logout function · typescript · L12-L40 (29 LOC)apps/web/src/lib/logout.ts
export async function logout(options?: { redirect?: boolean; callbackUrl?: string }) {
// Step 1: Backend logout - Clear backend session cookies (httpOnly accessToken)
try {
const backendUrl = process.env.NEXT_PUBLIC_API_URL;
if (backendUrl) {
const response = await fetch(`${backendUrl}/auth/logout`, {
method: 'POST',
credentials: 'include', // Sends httpOnly cookies to backend
});
if (!response.ok) {
console.warn('[Logout] Backend logout returned error:', response.status);
}
}
} catch (e) {
console.warn('[Logout] Backend logout failed:', e);
// Continue anyway - user still wants to logout from frontend
}
// Step 2: NextAuth signOut
// In NextAuth v5, if redirect is false, we need to call signOut without redirect
if (options?.redirect === false) {
// Call signOut and prevent automatic redirect by catching the redirect
await signOut({ redirect: false } as any);
} else {
// Default behavior:validatePortfolioAnalysis function · typescript · L13-L56 (44 LOC)apps/web/src/lib/portfolio-validation.ts
export function validatePortfolioAnalysis(
items: PortfolioItem[],
dateRange: DateRange,
t: TFunction
): string | null {
// Filter out zero quantities
const nonZeroItems = items.filter((item) => item.quantity > 0);
if (nonZeroItems.length === 0) {
return t('portfolio.builder.validation.no-positive-quantity');
}
// Check if dates are missing
if (!dateRange.startDate || !dateRange.endDate) {
return t('portfolio.builder.analysis.dates-required');
}
// Validate date range order
if (dateRange.startDate >= dateRange.endDate) {
return t('portfolio.builder.validation.start-before-end');
}
// Check for future dates
const endDate = new Date(dateRange.endDate);
const startDate = new Date(dateRange.startDate);
const todayDate = new Date();
todayDate.setHours(0, 0, 0, 0);
if (endDate > todayDate) {
return t('portfolio.builder.validation.end-not-future');
}
if (startDate > todayDate) {
return t('portfolio.builder.validation.start-noisEndDateToday function · typescript · L61-L69 (9 LOC)apps/web/src/lib/portfolio-validation.ts
export function isEndDateToday(dateRange: DateRange): boolean {
if (!dateRange.endDate) return false;
const endDate = new Date(dateRange.endDate);
const todayDate = new Date();
todayDate.setHours(0, 0, 0, 0);
return endDate.getTime() === todayDate.getTime();
}calculatePasswordStrength function · typescript · L25-L72 (48 LOC)apps/web/src/lib/utils/password-strength.ts
export function calculatePasswordStrength(password: string): PasswordStrength {
if (!password) {
return {
score: 0,
label: 'very-weak',
color: 'bg-red-500',
};
}
let score = 0;
// Length bonus
if (password.length >= 8) score++;
if (password.length >= 12) score++;
// Character variety
const hasLower = /[a-z]/.test(password);
const hasUpper = /[A-Z]/.test(password);
const hasNumber = /[0-9]/.test(password);
const hasSpecial = /[^A-Za-z0-9]/.test(password);
if (hasLower && hasUpper) score++;
if (hasNumber) score++;
if (hasSpecial) score++;
// Penalize common patterns
if (/^[a-z]+$/i.test(password)) score--; // Only letters
if (/^[0-9]+$/.test(password)) score--; // Only numbers
if (COMMON_PASSWORDS.includes(password.toLowerCase())) score -= 2;
// Ensure score is within 0-4 range
const finalScore = Math.max(0, Math.min(4, score));
const labels = ['very-weak', 'weak', 'medium', 'strong', 'very-strong'];
const colordetectLanguage function · typescript · L24-L40 (17 LOC)apps/web/src/proxy.ts
function detectLanguage(request: NextRequest): Language {
// Priority 1: Check if we have a saved preference in cookies
const cookieLang = request.cookies.get('NEXT_LOCALE')?.value;
if (cookieLang && SUPPORTED_LANGUAGES.includes(cookieLang as Language)) {
return cookieLang as Language;
}
// Priority 2: Parse Accept-Language header with quality values
const acceptLanguage = request.headers.get('accept-language') || '';
const detectedLang = parseAcceptLanguage(
acceptLanguage,
[...SUPPORTED_LANGUAGES],
DEFAULT_LANGUAGE
);
return detectedLang as Language;
}‹ prevpage 3 / 3