[Glitch] Add effective date to terms of service

Port cadda2f9571873f0fb245399de7e20901efb5e72 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Eugen Rochko 2025-03-05 10:01:33 +01:00 committed by Claire
parent 71afcd42e1
commit 180e9e5d70
6 changed files with 87 additions and 27 deletions

View File

@ -4,8 +4,12 @@ import type {
ApiPrivacyPolicyJSON, ApiPrivacyPolicyJSON,
} from 'flavours/glitch/api_types/instance'; } from 'flavours/glitch/api_types/instance';
export const apiGetTermsOfService = () => export const apiGetTermsOfService = (version?: string) =>
apiRequestGet<ApiTermsOfServiceJSON>('v1/instance/terms_of_service'); apiRequestGet<ApiTermsOfServiceJSON>(
version
? `v1/instance/terms_of_service/${version}`
: 'v1/instance/terms_of_service',
);
export const apiGetPrivacyPolicy = () => export const apiGetPrivacyPolicy = () =>
apiRequestGet<ApiPrivacyPolicyJSON>('v1/instance/privacy_policy'); apiRequestGet<ApiPrivacyPolicyJSON>('v1/instance/privacy_policy');

View File

@ -1,5 +1,7 @@
export interface ApiTermsOfServiceJSON { export interface ApiTermsOfServiceJSON {
updated_at: string; effective_date: string;
effective: boolean;
succeeded_by: string | null;
content: string; content: string;
} }

View File

@ -8,26 +8,31 @@ import {
} from 'react-intl'; } from 'react-intl';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
import { Link, useParams } from 'react-router-dom';
import { apiGetTermsOfService } from 'flavours/glitch/api/instance'; import { apiGetTermsOfService } from 'flavours/glitch/api/instance';
import type { ApiTermsOfServiceJSON } from 'flavours/glitch/api_types/instance'; import type { ApiTermsOfServiceJSON } from 'flavours/glitch/api_types/instance';
import { Column } from 'flavours/glitch/components/column'; import { Column } from 'flavours/glitch/components/column';
import { Skeleton } from 'flavours/glitch/components/skeleton';
import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error'; import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'terms_of_service.title', defaultMessage: 'Terms of Service' }, title: { id: 'terms_of_service.title', defaultMessage: 'Terms of Service' },
}); });
interface Params {
date?: string;
}
const TermsOfService: React.FC<{ const TermsOfService: React.FC<{
multiColumn: boolean; multiColumn: boolean;
}> = ({ multiColumn }) => { }> = ({ multiColumn }) => {
const intl = useIntl(); const intl = useIntl();
const { date } = useParams<Params>();
const [response, setResponse] = useState<ApiTermsOfServiceJSON>(); const [response, setResponse] = useState<ApiTermsOfServiceJSON>();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
apiGetTermsOfService() apiGetTermsOfService(date)
.then((data) => { .then((data) => {
setResponse(data); setResponse(data);
setLoading(false); setLoading(false);
@ -36,7 +41,7 @@ const TermsOfService: React.FC<{
.catch(() => { .catch(() => {
setLoading(false); setLoading(false);
}); });
}, []); }, [date]);
if (!loading && !response) { if (!loading && !response) {
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />; return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
@ -55,23 +60,60 @@ const TermsOfService: React.FC<{
defaultMessage='Terms of Service' defaultMessage='Terms of Service'
/> />
</h3> </h3>
<p> <p className='prose'>
<FormattedMessage {response?.effective ? (
id='privacy_policy.last_updated' <FormattedMessage
defaultMessage='Last updated {date}' id='privacy_policy.last_updated'
values={{ defaultMessage='Last updated {date}'
date: loading ? ( values={{
<Skeleton width='10ch' /> date: (
) : ( <FormattedDate
<FormattedDate value={response.effective_date}
value={response?.updated_at} year='numeric'
year='numeric' month='short'
month='short' day='2-digit'
day='2-digit' />
),
}}
/>
) : (
<FormattedMessage
id='terms_of_service.effective_as_of'
defaultMessage='Effective as of {date}'
values={{
date: (
<FormattedDate
value={response?.effective_date}
year='numeric'
month='short'
day='2-digit'
/>
),
}}
/>
)}
{response?.succeeded_by && (
<>
{' · '}
<Link to={`/terms-of-service/${response.succeeded_by}`}>
<FormattedMessage
id='terms_of_service.upcoming_changes_on'
defaultMessage='Upcoming changes on {date}'
values={{
date: (
<FormattedDate
value={response.succeeded_by}
year='numeric'
month='short'
day='2-digit'
/>
),
}}
/> />
), </Link>
}} </>
/> )}
</p> </p>
</div> </div>

View File

@ -214,7 +214,7 @@ class SwitchingColumnsArea extends PureComponent {
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} /> <WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/about' component={About} content={children} /> <WrappedRoute path='/about' component={About} content={children} />
<WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} /> <WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} />
<WrappedRoute path='/terms-of-service' component={TermsOfService} content={children} /> <WrappedRoute path='/terms-of-service/:date?' component={TermsOfService} content={children} />
<WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} /> <WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} />
<Redirect from='/timelines/public' to='/public' exact /> <Redirect from='/timelines/public' to='/public' exact />

View File

@ -2010,6 +2010,11 @@ a.sparkline {
line-height: 20px; line-height: 20px;
font-weight: 600; font-weight: 600;
margin-bottom: 16px; margin-bottom: 16px;
a {
color: inherit;
text-decoration: none;
}
} }
} }
} }

View File

@ -341,10 +341,17 @@ code {
columns: unset; columns: unset;
} }
.input.datetime .label_input select { .input.datetime .label_input,
display: inline-block; .input.date .label_input {
width: auto; display: flex;
flex: 0; gap: 4px;
align-items: center;
select {
display: inline-block;
width: auto;
flex: 0;
}
} }
.input.select.select--languages { .input.select.select--languages {