From 3603b87d2c05bf92855d9cf5d66aadc4a116101a Mon Sep 17 00:00:00 2001 From: Jonathan Payne Date: Tue, 13 Oct 2026 14:13:03 -0400 Subject: [PATCH 1/4] OpenConceptLab/ocl_issues#2899 | Link the Terms of Use and Privacy Policy from the footer The footer links the Terms of Use and the Privacy Policy on openconceptlab.org on every page, signed in or not, and each opens in a new tab. Their labels are common.terms_of_use and common.privacy_policy, in the en, es, pt-BR and zh catalogs. Below MUI's md breakpoint the single row no longer fits in every language, so the links take a row of their own and the copyright and versions wrap under them. The footer publishes how much taller than its usual 30 px that makes it (--footer-extra-height), and --app-height subtracts it, so pages end above the footer rather than under it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01SDUDybmzSUtWMPsVozhSz3 --- src/common/constants.js | 2 + src/components/app/Footer.jsx | 60 +++++++++++++++++++++--- src/components/app/Footer.scss | 23 +++++++++ src/i18n/locales/en/translations.json | 2 + src/i18n/locales/es/translations.json | 2 + src/i18n/locales/pt-BR/translations.json | 2 + src/i18n/locales/zh/translations.json | 2 + src/index.scss | 8 ++-- 8 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index a6a432caa..74f11e34d 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -106,3 +106,5 @@ export const ALL = '*'; export const URL_REGISTRY_DOC_LINK = 'https://docs.openconceptlab.org/en/latest/oclapi/apireference/urlregistry.html' export const TBV3_ANNOUNCEMENT_LETTER_URL = 'https://openconceptlab.org/blog/letter-to-the-ocl-community?utm_source=tbv3&utm_medium=banner&utm_campaign=subscription_dates' export const TBV3_ANNOUNCEMENT_PRICING_URL = 'https://openconceptlab.org/pricing?utm_source=tbv3&utm_medium=banner&utm_campaign=subscription_dates' +export const TERMS_OF_USE_URL = 'https://openconceptlab.org/terms-of-use' +export const PRIVACY_POLICY_URL = 'https://openconceptlab.org/privacy-policy' diff --git a/src/components/app/Footer.jsx b/src/components/app/Footer.jsx index a2b3c3eb7..eeb9b4290 100644 --- a/src/components/app/Footer.jsx +++ b/src/components/app/Footer.jsx @@ -1,25 +1,71 @@ import React from 'react'; -import { Divider } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { Divider, Link } from '@mui/material'; import { Copyright as CopyrightIcon } from '@mui/icons-material'; import { get } from 'lodash'; import { getAppliedServerConfig } from '../../common/utils'; +import { TERMS_OF_USE_URL, PRIVACY_POLICY_URL } from '../../common/constants'; import AppVersions from './AppVersions'; import './Footer.scss'; const DEFAULT_FOOTER_TEXT = `${new Date().getFullYear()} Open Concept Lab`; +// On every page, signed in or not: using TBv3 means accepting the Terms of Use. +const LEGAL_LINKS = [ + { labelKey: 'common.terms_of_use', href: TERMS_OF_USE_URL }, + { labelKey: 'common.privacy_policy', href: PRIVACY_POLICY_URL }, +]; + +// The footer's height in Footer.scss while it fits on one row. Narrower +// screens stack it onto more rows, and --app-height in index.scss subtracts +// the extra, so pages end above it. +const ROW_HEIGHT = 30; +const EXTRA_HEIGHT_VAR = '--footer-extra-height'; + const Footer = () => { + const { t } = useTranslation(); + const ref = React.useRef(null); const text = get(getAppliedServerConfig(), 'info.site.footerText', DEFAULT_FOOTER_TEXT); const isDefault = text === DEFAULT_FOOTER_TEXT; + + React.useLayoutEffect(() => { + const el = ref.current; + if (!el) + return; + const root = document.documentElement.style; + const update = () => root.setProperty(EXTRA_HEIGHT_VAR, `${Math.max(0, el.offsetHeight - ROW_HEIGHT)}px`); + update(); + const observer = new ResizeObserver(update); + observer.observe(el); + return () => { + observer.disconnect(); + root.removeProperty(EXTRA_HEIGHT_VAR); + }; + }, []); + return ( -