diff --git a/app/common/src/main/java/stirling/software/common/util/RequestUriUtils.java b/app/common/src/main/java/stirling/software/common/util/RequestUriUtils.java index 0dfdfa69e3..2dd3d420a5 100644 --- a/app/common/src/main/java/stirling/software/common/util/RequestUriUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/RequestUriUtils.java @@ -159,6 +159,8 @@ public class RequestUriUtils { || trimmedUri.startsWith( "/api/v1/proprietary/ui-data/login") // Login page config (SSO providers + // enableLogin) + || trimmedUri.startsWith( + "/api/v1/ui-data/footer-info") // Public footer configuration || trimmedUri.startsWith("/v1/api-docs") || trimmedUri.startsWith("/api/v1/invite/validate") || trimmedUri.startsWith("/api/v1/invite/accept") diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java index ad2fead019..18445d7da4 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java @@ -58,6 +58,21 @@ public class UIDataController { this.runtimePathConfig = runtimePathConfig; } + @GetMapping("/footer-info") + @Operation(summary = "Get public footer configuration data") + public ResponseEntity getFooterData() { + FooterData data = new FooterData(); + data.setAnalyticsEnabled(applicationProperties.getSystem().getEnableAnalytics()); + data.setTermsAndConditions(applicationProperties.getLegal().getTermsAndConditions()); + data.setPrivacyPolicy(applicationProperties.getLegal().getPrivacyPolicy()); + data.setAccessibilityStatement( + applicationProperties.getLegal().getAccessibilityStatement()); + data.setCookiePolicy(applicationProperties.getLegal().getCookiePolicy()); + data.setImpressum(applicationProperties.getLegal().getImpressum()); + + return ResponseEntity.ok(data); + } + @GetMapping("/home") @Operation(summary = "Get home page data") public ResponseEntity getHomeData() { @@ -237,6 +252,16 @@ public class UIDataController { } // Data classes + @Data + public static class FooterData { + private Boolean analyticsEnabled; + private String termsAndConditions; + private String privacyPolicy; + private String accessibilityStatement; + private String cookiePolicy; + private String impressum; + } + @Data public static class HomeData { private boolean showSurveyFromDocker; diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java index 3e8bb275c0..d335eb9c25 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java @@ -150,7 +150,6 @@ public class ProprietaryUIDataController { data.setFirstTimeSetup(isFirstTimeSetup); data.setShowDefaultCredentials(showDefaultCredentials); - data.setEnableAnalytics(applicationProperties.getSystem().getEnableAnalytics()); OAUTH2 oauth = securityProps.getOauth2(); @@ -492,7 +491,6 @@ public class ProprietaryUIDataController { private boolean altLogin; private boolean firstTimeSetup; private boolean showDefaultCredentials; - private Boolean enableAnalytics; } @Data diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java index 896801ce8e..fe57b39975 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java @@ -299,7 +299,8 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { contextPath + "/api/v1/auth/refresh", contextPath + "/api/v1/auth/me", contextPath + "/api/v1/invite/validate", - contextPath + "/api/v1/invite/accept" + contextPath + "/api/v1/invite/accept", + contextPath + "/api/v1/ui-data/footer-info" }; for (String pattern : publicApiPatterns) { diff --git a/frontend/public/css/cookieconsentCustomisation.css b/frontend/public/css/cookieconsentCustomisation.css index 857e3d81ec..ec360c20be 100644 --- a/frontend/public/css/cookieconsentCustomisation.css +++ b/frontend/public/css/cookieconsentCustomisation.css @@ -54,17 +54,17 @@ --cc-secondary-color: #b0b0b0; --cc-btn-primary-bg: #4dabf7; - --cc-btn-primary-color: #2d2d2d; + --cc-btn-primary-color: #ffffff; --cc-btn-primary-border-color: #4dabf7; --cc-btn-primary-hover-bg: #3d3d3d; - --cc-btn-primary-hover-color: #e5e5e5; + --cc-btn-primary-hover-color: #ffffff; --cc-btn-primary-hover-border-color: #3d3d3d; --cc-btn-secondary-bg: #3d3d3d; - --cc-btn-secondary-color: #e5e5e5; + --cc-btn-secondary-color: #ffffff; --cc-btn-secondary-border-color: #3d3d3d; --cc-btn-secondary-hover-bg: #4dabf7; - --cc-btn-secondary-hover-color: #2d2d2d; + --cc-btn-secondary-hover-color: #ffffff; --cc-btn-secondary-hover-border-color: #4dabf7; --cc-separator-border-color: #555555; @@ -196,10 +196,6 @@ color: var(--cc-primary-color) !important; } -#cc-main .cm__btn { - color: var(--cc-btn-primary-color) !important; -} - #cc-main .cm__footer { color: var(--cc-primary-color) !important; } diff --git a/frontend/src/core/components/shared/Footer.tsx b/frontend/src/core/components/shared/Footer.tsx index b3ba0f7a7a..172861d1bb 100644 --- a/frontend/src/core/components/shared/Footer.tsx +++ b/frontend/src/core/components/shared/Footer.tsx @@ -1,6 +1,7 @@ import { Flex } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import { useCookieConsent } from '@app/hooks/useCookieConsent'; +import { useFooterInfo } from '@app/hooks/useFooterInfo'; interface FooterProps { privacyPolicy?: string; @@ -18,11 +19,26 @@ export default function Footer({ accessibilityStatement, cookiePolicy, impressum, - analyticsEnabled = false, + analyticsEnabled, forceLightMode = false }: FooterProps) { const { t } = useTranslation(); - const { showCookiePreferences } = useCookieConsent({ analyticsEnabled, forceLightMode }); + const { footerInfo } = useFooterInfo(); + + console.log('[Footer] Props analyticsEnabled:', analyticsEnabled); + console.log('[Footer] Fetched footerInfo:', footerInfo); + + // Use props if provided, otherwise fall back to fetched footer info + const finalAnalyticsEnabled = analyticsEnabled ?? footerInfo?.analyticsEnabled ?? false; + const finalPrivacyPolicy = privacyPolicy ?? footerInfo?.privacyPolicy; + const finalTermsAndConditions = termsAndConditions ?? footerInfo?.termsAndConditions; + const finalAccessibilityStatement = accessibilityStatement ?? footerInfo?.accessibilityStatement; + const finalCookiePolicy = cookiePolicy ?? footerInfo?.cookiePolicy; + const finalImpressum = impressum ?? footerInfo?.impressum; + + console.log('[Footer] Final analyticsEnabled:', finalAnalyticsEnabled); + + const { showCookiePreferences } = useCookieConsent({ analyticsEnabled: finalAnalyticsEnabled, forceLightMode }); // Default URLs const defaultTermsUrl = "https://www.stirling.com/legal/terms-of-service"; @@ -30,9 +46,9 @@ export default function Footer({ const defaultAccessibilityUrl = "https://www.stirling.com/accessibility"; // Use provided URLs or fall back to defaults - const finalTermsUrl = termsAndConditions || defaultTermsUrl; - const finalPrivacyUrl = privacyPolicy || defaultPrivacyUrl; - const finalAccessibilityUrl = accessibilityStatement || defaultAccessibilityUrl; + const finalTermsUrl = finalTermsAndConditions || defaultTermsUrl; + const finalPrivacyUrl = finalPrivacyPolicy || defaultPrivacyUrl; + const finalAccessibilityUrl = finalAccessibilityStatement || defaultAccessibilityUrl; // Helper to check if a value is valid (not null/undefined/empty string) const isValidLink = (link?: string) => link && link.trim().length > 0; @@ -87,27 +103,27 @@ export default function Footer({ > {t('legal.accessibility', 'Accessibility')} - {isValidLink(cookiePolicy) && ( + {isValidLink(finalCookiePolicy) && ( {t('legal.cookie', 'Cookie Policy')} )} - {isValidLink(impressum) && ( + {isValidLink(finalImpressum) && ( {t('legal.impressum', 'Impressum')} )} - {analyticsEnabled && ( + {finalAnalyticsEnabled && (