🆙 News windows in UI login update

This commit is contained in:
duckietm
2026-05-06 08:48:17 +02:00
parent 793c260fc5
commit a243640741
3 changed files with 35 additions and 9 deletions
+5
View File
@@ -4,3 +4,8 @@ export function GetConfigurationValue<T = string>(key: string, value: T = null):
{
return GetConfiguration().getValue(key, value);
}
export function GetOptionalConfigurationValue<T = string>(key: string, value: T = null): T
{
return GetConfiguration().definitions.has(key) ? GetConfiguration().getValue(key, value) : value;
}
+5 -4
View File
@@ -1,6 +1,6 @@
import { GetConfiguration } from '@nitrots/nitro-renderer';
import { FC, FormEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ClearRememberLogin, GetConfigurationValue, GetRememberLogin, StoreRememberLoginFromPayload } from '../../api';
import { ClearRememberLogin, GetConfigurationValue, GetOptionalConfigurationValue, GetRememberLogin, StoreRememberLoginFromPayload } from '../../api';
import { configFileUrl } from '../../secure-assets';
import flagBr from '../../assets/images/flag_icon/flag_icon_br.png';
import flagDe from '../../assets/images/flag_icon/flag_icon_de.png';
@@ -237,7 +237,8 @@ export const LoginView: FC<LoginViewProps> = ({ onAuthenticated, isEntering = fa
const loginUrl = GetConfigurationValue<string>('login.endpoint', '/api/auth/login');
const registerUrl = GetConfigurationValue<string>('login.register.endpoint', '/api/auth/register');
const forgotUrl = GetConfigurationValue<string>('login.forgot.endpoint', '/api/auth/forgot-password');
const newsUrl = interpolate(GetConfigurationValue<string>('login.news.url', ''));
const configuredNewsUrl = interpolate(GetOptionalConfigurationValue<string>('login.news.url', ''));
const newsUrl = configuredNewsUrl || configFileUrl('news.json');
const turnstileSiteKey = GetConfigurationValue<string>('login.turnstile.sitekey', '');
const rawTurnstileEnabled = GetConfigurationValue<unknown>('login.turnstile.enabled', false);
const turnstileEnabled = (rawTurnstileEnabled === true
@@ -366,7 +367,7 @@ export const LoginView: FC<LoginViewProps> = ({ onAuthenticated, isEntering = fa
}, []);
const healthUrl = GetConfigurationValue<string>('login.health.endpoint', '');
const healthMethodRaw = GetConfigurationValue<string>('login.health.method', 'GET');
const healthMethodRaw = GetOptionalConfigurationValue<string>('login.health.method', 'GET');
const healthMethod = (healthMethodRaw || 'GET').toUpperCase();
const checkServerReachable = useCallback(async (): Promise<boolean> =>
{
@@ -480,7 +481,7 @@ export const LoginView: FC<LoginViewProps> = ({ onAuthenticated, isEntering = fa
const checkEmailUrl = GetConfigurationValue<string>('login.check-email.endpoint', '/api/auth/check-email');
const checkUsernameUrl = GetConfigurationValue<string>('login.check-username.endpoint', '/api/auth/check-username');
const imagingUrl = GetConfigurationValue<string>('login.register.imaging.url', '');
const imagingUrl = GetOptionalConfigurationValue<string>('login.register.imaging.url', '');
const interpretAvailability = (ok: boolean, status: number, payload: Record<string, unknown>): { available: boolean; error?: string } =>
{
const isTrue = (v: unknown) => v === true || v === 'true' || v === 1 || v === '1';
+25 -5
View File
@@ -1,5 +1,5 @@
import { FC, useEffect, useState } from 'react';
import { t } from '../utils/i18n';
import { interpolate, t } from '../utils/i18n';
import { resolveNewsImage, resolveNewsLink } from '../utils/news';
interface NewsItem
@@ -12,6 +12,26 @@ interface NewsItem
linkUrl: string;
}
interface RawNewsItem
{
id?: number;
title?: string;
body?: string;
image?: string | null;
link?: string;
linkUrl?: string;
linkText?: string;
}
const normalizeNewsItem = (raw: RawNewsItem, fallbackId: number): NewsItem => ({
id: typeof raw.id === 'number' ? raw.id : fallbackId,
title: typeof raw.title === 'string' ? raw.title : '',
body: typeof raw.body === 'string' ? raw.body : '',
image: typeof raw.image === 'string' && raw.image.length ? interpolate(raw.image) : null,
linkText: typeof raw.linkText === 'string' ? raw.linkText : '',
linkUrl: interpolate((typeof raw.linkUrl === 'string' && raw.linkUrl) || (typeof raw.link === 'string' ? raw.link : ''))
});
interface NewsWindowProps { newsUrl: string; }
const NEWS_AUTO_ADVANCE_MS = 10000;
@@ -36,10 +56,10 @@ export const NewsWindow: FC<NewsWindowProps> = ({ newsUrl }) =>
.then((json: unknown) =>
{
if(cancelled) return;
const list = Array.isArray((json as { news?: unknown })?.news)
? (json as { news: NewsItem[] }).news
: [];
setItems(list);
const rawList = Array.isArray((json as { news?: unknown })?.news)
? (json as { news: RawNewsItem[] }).news
: Array.isArray(json) ? (json as RawNewsItem[]) : [];
setItems(rawList.map((raw, idx) => normalizeNewsItem(raw, idx + 1)));
})
.catch(() => { if(!cancelled) setFailed(true); });
return () => { cancelled = true; };