feat: add operators sunset disclaimer

This commit is contained in:
jinhojang6
2026-07-13 22:49:37 +09:00
committed by Jinho Jang
parent 2a006e7fab
commit 1f4709aa40
8 changed files with 62 additions and 1 deletions
@@ -4,7 +4,7 @@ import { useState } from 'react'
import { LegalMarkdown } from '@/components/sections/shared/legal-markdown'
type OperatorsLegalDocumentKey = 'terms' | 'privacy'
type OperatorsLegalDocumentKey = 'terms' | 'privacy' | 'disclaimer'
interface OperatorsLegalDocument {
label: string
@@ -14,6 +14,7 @@ interface OperatorsLegalDocument {
interface OperatorsLegalTabsProps {
terms: OperatorsLegalDocument
privacy: OperatorsLegalDocument
disclaimer: OperatorsLegalDocument
}
const documentButtons: ReadonlyArray<{
@@ -22,9 +23,11 @@ const documentButtons: ReadonlyArray<{
}> = [
{ key: 'terms', panelId: 'operators-terms-panel' },
{ key: 'privacy', panelId: 'operators-privacy-panel' },
{ key: 'disclaimer', panelId: 'operators-disclaimer-panel' },
]
export function OperatorsLegalTabs({
disclaimer,
privacy,
terms,
}: OperatorsLegalTabsProps) {
@@ -34,6 +37,7 @@ export function OperatorsLegalTabs({
const documents: Record<OperatorsLegalDocumentKey, OperatorsLegalDocument> = {
terms,
privacy,
disclaimer,
}
const activeDocument =
activeDocumentKey === null ? null : documents[activeDocumentKey]
+5
View File
@@ -36,6 +36,7 @@ export default async function OperatorsPage({ params }: OperatorsPageProps) {
)
const terms = getLegalDoc(data.documents.terms.slug)
const privacy = getLegalDoc(data.documents.privacy.slug)
const disclaimer = getLegalDoc(data.documents.disclaimer.slug)
return (
<main className="bg-brand-off-white text-brand-dark-green">
@@ -57,6 +58,10 @@ export default async function OperatorsPage({ params }: OperatorsPageProps) {
<OperatorsLegalTabs
terms={{ label: data.documents.terms.label, body: terms.body }}
privacy={{ label: data.documents.privacy.label, body: privacy.body }}
disclaimer={{
label: data.documents.disclaimer.label,
body: disclaimer.body,
}}
/>
</main>
)
@@ -20,6 +20,10 @@ type OperatorsCopySection = {
label: string
slug: string
}
disclaimer: {
label: string
slug: string
}
}
}
@@ -53,5 +57,9 @@ describe('operators page contract', () => {
label: 'Privacy Policy',
slug: 'operators-privacy-policy',
})
expect(section.documents.disclaimer).toEqual({
label: 'Disclaimer',
slug: 'operators-disclaimer',
})
})
})
@@ -0,0 +1,23 @@
---
title: 'Disclaimer - Sunset of Logos Operators | Logos'
description: 'Disclaimer and privacy policy addendum for the sunset of Logos Operators.'
heading: 'Disclaimer - Sunset of Logos Operators'
---
# Disclaimer - Sunset of Logos Operators
## Disclaimer
By claiming a reward, you acknowledge that any allocation of rewards is determined by Logos in good faith and at its sole discretion, based on its assessment of participant contributions during the Operators programme. You understand that XP did not constitute any guarantee, promise, or enforceable claim against Logos, and that Logos retained the right to determine, modify, or discontinue the manner and criteria by which XP was awarded. Any reward provided is intended as a full and final recognition of your participation in the Logos Operators programme, and no further claims or entitlements will arise in connection with it. You also confirm that you are not subject to sanctions or restrictive measures under the laws of the United Kingdom, United States, European Union, or Switzerland, and agree to provide reasonable information if required to verify this.
## Privacy policy addendum
As part of administering any distribution of rewards, we will need to process certain personal data including the following:
1. Name;
2. Address; and
3. Discord handle.
We have a legitimate interest in processing this data for the purposes of verifying eligibility, administering and delivering rewards, and ensuring compliance with applicable legal and regulatory obligations; such processing will be limited to what is necessary for these purposes and handled in accordance with applicable data protection laws.
We will process such personal data in accordance with our privacy policy set out here: [https://logos.co/privacy-policy](https://logos.co/privacy-policy)
+12
View File
@@ -30,6 +30,7 @@ describe('getLegalDoc', () => {
'security',
'operators-terms-of-use',
'operators-privacy-policy',
'operators-disclaimer',
]) {
const doc = getLegalDoc(slug)
expect(doc.title).toContain('| Logos')
@@ -58,6 +59,17 @@ describe('getLegalDoc', () => {
expect(privacy.body).not.toContain('1) ### **Who we are**')
})
it('loads the operator sunset disclaimer as markdown', () => {
const disclaimer = getLegalDoc('operators-disclaimer')
expect(disclaimer.body).toContain(
'# Disclaimer - Sunset of Logos Operators'
)
expect(disclaimer.body).toContain('## Privacy policy addendum')
expect(disclaimer.body).toContain('1. Name;')
expect(disclaimer.body).toContain('https://logos.co/privacy-policy')
})
it('throws a descriptive error when the document is missing', () => {
expect(() => getLegalDoc('does-not-exist')).toThrow(
/failed to read legal document "does-not-exist"/
+4
View File
@@ -20,6 +20,10 @@
"privacy": {
"label": "Privacy Policy",
"slug": "operators-privacy-policy"
},
"disclaimer": {
"label": "Disclaimer",
"slug": "operators-disclaimer"
}
}
}
@@ -137,6 +137,7 @@ test('operatorsCopy parses a minimal valid value and routes through the union',
documents: {
terms: { label: 'Terms of Use', slug: 'operators-terms-of-use' },
privacy: { label: 'Privacy Policy', slug: 'operators-privacy-policy' },
disclaimer: { label: 'Disclaimer', slug: 'operators-disclaimer' },
},
}
assert.equal(operatorsCopySectionSchema.parse(value).componentType, 'operatorsCopy')
@@ -355,6 +355,10 @@ export const operatorsCopySectionSchema = z.object({
label: z.string().min(1),
slug: z.string().min(1),
}),
disclaimer: z.object({
label: z.string().min(1),
slug: z.string().min(1),
}),
}),
})
export type OperatorsCopySection = z.infer<typeof operatorsCopySectionSchema>