diff --git a/frontend/src/components/shared/AvailabilityStatusBadge.test.tsx b/frontend/src/components/shared/AvailabilityStatusBadge.test.tsx index 6ce0f47..f903cc2 100644 --- a/frontend/src/components/shared/AvailabilityStatusBadge.test.tsx +++ b/frontend/src/components/shared/AvailabilityStatusBadge.test.tsx @@ -34,7 +34,23 @@ describe('AvailabilityStatusBadge', () => { expect(badge.querySelector('.bg-red-100')).toBeTruthy(); }); - it('shows message subtitle when message is non-empty', () => { + it('Available always shows the default translated message, ignoring any backend message', () => { + renderWithProviders(); + + expect(screen.getByTestId('availability-message')).toHaveTextContent( + 'System is running normally.', + ); + }); + + it('Available shows the default translated message when no message is provided', () => { + renderWithProviders(); + + expect(screen.getByTestId('availability-message')).toHaveTextContent( + 'System is running normally.', + ); + }); + + it('Maintenance shows a custom reason when provided', () => { renderWithProviders( , ); @@ -44,16 +60,30 @@ describe('AvailabilityStatusBadge', () => { ); }); - it('hides message element when message is empty string', () => { - renderWithProviders(); + it('Maintenance falls back to default translated message when no reason is provided', () => { + renderWithProviders(); - expect(screen.queryByTestId('availability-message')).toBeNull(); + expect(screen.getByTestId('availability-message')).toHaveTextContent( + 'System is undergoing scheduled maintenance.', + ); }); - it('hides message element when message prop is omitted', () => { - renderWithProviders(); + it('Unavailable shows a custom reason when provided', () => { + renderWithProviders( + , + ); - expect(screen.queryByTestId('availability-message')).toBeNull(); + expect(screen.getByTestId('availability-message')).toHaveTextContent( + 'Emergency shutdown in progress', + ); + }); + + it('Unavailable falls back to default translated message when no reason is provided', () => { + renderWithProviders(); + + expect(screen.getByTestId('availability-message')).toHaveTextContent( + 'System is currently unavailable.', + ); }); it('shows stale indicator when stale={true}', () => { diff --git a/frontend/src/components/shared/AvailabilityStatusBadge.tsx b/frontend/src/components/shared/AvailabilityStatusBadge.tsx index cae3f66..c43f0b7 100644 --- a/frontend/src/components/shared/AvailabilityStatusBadge.tsx +++ b/frontend/src/components/shared/AvailabilityStatusBadge.tsx @@ -10,24 +10,34 @@ interface AvailabilityStatusBadgeProps { const STATUS_CONFIG: Record< AvailabilityStatus, - { labelKey: string; colorClass: string; Icon: React.ComponentType<{ className?: string }> } + { + labelKey: string; + defaultMessageKey: string; + /** When true the default translated message is always shown, ignoring any backend message. */ + alwaysDefault: boolean; + colorClass: string; + Icon: React.ComponentType<{ className?: string }>; + } > = { Available: { labelKey: 'availability.available', - colorClass: - 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200', + defaultMessageKey: 'availability.messageAvailable', + alwaysDefault: true, + colorClass: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200', Icon: CheckCircle, }, Maintenance: { labelKey: 'availability.maintenance', - colorClass: - 'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200', + defaultMessageKey: 'availability.messageMaintenance', + alwaysDefault: false, + colorClass: 'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200', Icon: AlertTriangle, }, Unavailable: { labelKey: 'availability.unavailable', - colorClass: - 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200', + defaultMessageKey: 'availability.messageUnavailable', + alwaysDefault: false, + colorClass: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200', Icon: XCircle, }, }; @@ -38,7 +48,8 @@ export function AvailabilityStatusBadge({ stale = false, }: AvailabilityStatusBadgeProps) { const { t } = useTranslation(); - const { labelKey, colorClass, Icon } = STATUS_CONFIG[status]; + const { labelKey, defaultMessageKey, alwaysDefault, colorClass, Icon } = STATUS_CONFIG[status]; + const displayMessage = alwaysDefault ? t(defaultMessageKey) : (message || t(defaultMessageKey)); return (
{t(labelKey)}
- {message && message.length > 0 && ( -

- {message} -

- )} +

+ {displayMessage} +

{stale && (
+/// Status en optionele admin-melding van de systeembeschikbaarheid. +/// +public record AvailabilityStatusDetails(AvailabilityStatus Status, string? Message); diff --git a/src/SlpModularCms.Core/Availability/IAvailabilityService.cs b/src/SlpModularCms.Core/Availability/IAvailabilityService.cs index 3860c2c..149fe0e 100644 --- a/src/SlpModularCms.Core/Availability/IAvailabilityService.cs +++ b/src/SlpModularCms.Core/Availability/IAvailabilityService.cs @@ -10,4 +10,9 @@ public interface IAvailabilityService /// /// De huidige . Task IsAvailableAsync(); + + /// + /// Geeft de huidige status inclusief de optionele admin-melding terug. + /// + Task GetStatusDetailsAsync(); } diff --git a/src/SlpModularCms.Modules.Availability/Controllers/AvailabilityController.cs b/src/SlpModularCms.Modules.Availability/Controllers/AvailabilityController.cs index 71284c0..533ca6b 100644 --- a/src/SlpModularCms.Modules.Availability/Controllers/AvailabilityController.cs +++ b/src/SlpModularCms.Modules.Availability/Controllers/AvailabilityController.cs @@ -20,12 +20,12 @@ public class AvailabilityController : ControllerBase [AllowAnonymous] public async Task GetStatus() { - var status = await _availabilityService.IsAvailableAsync(); + var details = await _availabilityService.GetStatusDetailsAsync(); return Ok(new { - Status = status.ToString(), + Status = details.Status.ToString(), CheckedAt = DateTimeOffset.UtcNow, - Message = string.Empty, + Message = details.Message ?? string.Empty, }); } diff --git a/src/SlpModularCms.Modules.Availability/Services/PersistentAvailabilityService.cs b/src/SlpModularCms.Modules.Availability/Services/PersistentAvailabilityService.cs index 57ec202..4ec129e 100644 --- a/src/SlpModularCms.Modules.Availability/Services/PersistentAvailabilityService.cs +++ b/src/SlpModularCms.Modules.Availability/Services/PersistentAvailabilityService.cs @@ -54,6 +54,24 @@ public class PersistentAvailabilityService : IAvailabilityService } } + public async Task GetStatusDetailsAsync() + { + try + { + var state = await _context.AvailabilityStates.FirstOrDefaultAsync(); + if (state == null) + return new AvailabilityStatusDetails(AvailabilityStatus.Available, null); + + return new AvailabilityStatusDetails(state.Status, state.Message); + } + catch (Exception) + { + _lastErrorTime = DateTimeOffset.UtcNow; + _cachedStatus = AvailabilityStatus.Available; + return new AvailabilityStatusDetails(_cachedStatus, null); + } + } + /// /// Update de globale systeemstatus. ///