Skip to content

feat: DR-7746 legal pages (terms, SLA, privacy, code of conduct, partner TOS)#7712

Open
AmanVarshney01 wants to merge 3 commits intomainfrom
dr-7746-terms
Open

feat: DR-7746 legal pages (terms, SLA, privacy, code of conduct, partner TOS)#7712
AmanVarshney01 wants to merge 3 commits intomainfrom
dr-7746-terms

Conversation

@AmanVarshney01
Copy link
Member

@AmanVarshney01 AmanVarshney01 commented Mar 26, 2026

Summary

  • Adds /terms, /sla, /privacy, /event-code-of-conduct, and /partners/tos pages to apps/site
  • Migrated from the old website with static content, no Sanity dependency
  • Shared LegalAccordion component in @/components/legal-accordion.tsx with expand all / collapse all / print controls
  • Sticky sidebar controls on desktop, horizontal on mobile
  • Dark indigo gradient hero with fixed height for consistency across pages

Summary by CodeRabbit

  • New Features
    • Added dedicated pages for Terms of Service, Privacy Policy, Event Code of Conduct, Partners Terms of Service, and Service Level Agreement, each rendering structured legal content.
    • Added an accordion component to present legal sections with expand/collapse, expand-all, and print controls for easier reading and printing.
  • Style
    • Added a decorative hero gradient background (light/dark variants) for legal pages.

Add static terms of service page to apps/site migrated from the old
website. Uses Eclipse accordion UI primitives with expand all / print
controls in a sticky sidebar layout matching the original design.
@vercel
Copy link

vercel bot commented Mar 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
blog Ready Ready Preview, Comment Mar 26, 2026 8:10pm
docs Ready Ready Preview, Comment Mar 26, 2026 8:10pm
eclipse Ready Ready Preview, Comment Mar 26, 2026 8:10pm
site Ready Ready Preview, Comment Mar 26, 2026 8:10pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4daf8463-5fc0-40f1-9fbf-22cceaa710d0

📥 Commits

Reviewing files that changed from the base of the PR and between bb3c236 and 050ffe0.

📒 Files selected for processing (6)
  • apps/site/src/app/event-code-of-conduct/page.tsx
  • apps/site/src/app/global.css
  • apps/site/src/app/partners/tos/page.tsx
  • apps/site/src/app/privacy/page.tsx
  • apps/site/src/app/sla/page.tsx
  • apps/site/src/app/terms/page.tsx
✅ Files skipped from review due to trivial changes (3)
  • apps/site/src/app/privacy/page.tsx
  • apps/site/src/app/event-code-of-conduct/page.tsx
  • apps/site/src/app/global.css
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/site/src/app/terms/page.tsx
  • apps/site/src/app/sla/page.tsx
  • apps/site/src/app/partners/tos/page.tsx

Walkthrough

Adds five Next.js legal pages, five corresponding data modules containing static JSX legal content, a new client-side LegalAccordion component, and a CSS gradient rule for legal hero backgrounds. All pages export metadata and default page components that render headings, "Last updated" lines, and LegalAccordion with the appropriate sections.

Changes

Cohort / File(s) Summary
Legal Page Components
apps/site/src/app/terms/page.tsx, apps/site/src/app/privacy/page.tsx, apps/site/src/app/sla/page.tsx, apps/site/src/app/event-code-of-conduct/page.tsx, apps/site/src/app/partners/tos/page.tsx
Added five Next.js App Router pages. Each exports metadata (title/description) and a default page component that renders a hero with heading and "Last updated", a separator, and LegalAccordion fed with corresponding sections.
Legal Content Data Modules
apps/site/src/data/terms.tsx, apps/site/src/data/privacy.tsx, apps/site/src/data/sla.tsx, apps/site/src/data/event-code-of-conduct.tsx, apps/site/src/data/partners-tos.tsx
Added five data modules exporting *LastUpdated strings and typed sections arrays ({ title: string; content: ReactNode }[]) containing static JSX legal content (paragraphs, lists, links). No runtime logic.
Accordion Component
apps/site/src/components/legal-accordion.tsx
New client-side LegalAccordion component managing open state via Set<number>, individual toggles, expand/collapse-all controls, stable id anchors, ARIA attributes, and a print helper that expands all sections before calling window.print().
Global CSS
apps/site/src/app/global.css
Added .legal-hero-gradient::before and .dark .legal-hero-gradient::before rules to render a top gradient background overlay for legal hero sections.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the primary change: adding multiple legal pages (terms, SLA, privacy, code of conduct, partner TOS) to the site, with clear reference to the ticket (DR-7746).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/site/src/data/terms.tsx (1)

5-8: Consider exporting TermsSection type for reuse.

The TermsSection type is duplicated in terms-accordion.tsx as Section. Exporting it from here would establish a single source of truth and ensure the accordion component stays in sync with the data structure.

♻️ Proposed change
-type TermsSection = {
+export type TermsSection = {
   title: string;
   content: ReactNode;
 };

Then in terms-accordion.tsx, import and use TermsSection instead of defining a local Section type.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/data/terms.tsx` around lines 5 - 8, Export the existing
TermsSection type so it can be reused by the accordion component; change the
declaration of TermsSection (type TermsSection = { title: string; content:
ReactNode; };) to an exported type and update the consumer file (where a local
Section type is defined in terms-accordion.tsx) to import and use TermsSection
instead of its local Section definition to remove duplication and keep a single
source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/site/src/app/terms/_components/terms-accordion.tsx`:
- Around line 68-71: The printPage function currently sets expandAll then uses a
50ms timeout which is a race; instead update printPage to only call
setExpandAll(true) and move the window.print() call into a useEffect that
watches expandAll so printing occurs after React commits the state change;
locate printPage and the expandAll state (setExpandAll, expandAll) in
terms-accordion.tsx and implement a useEffect that triggers window.print() when
expandAll becomes true, then reset expandAll if needed.
- Around line 25-45: The toggle button (onToggle, aria-expanded={isOpen}) needs
an aria-controls that points to the content panel id and the content panel needs
a matching id so screen readers can link them; create a stable panelId (e.g.,
derived from section.id or a generated string) and set aria-controls={panelId}
on the button and id={panelId} on the content div, render the panel always (do
not remove it from the DOM) and hide it when closed using a CSS utility like
hidden or aria-hidden to preserve the relationship, and ensure you update
aria-hidden to reflect isOpen.

In `@apps/site/src/app/terms/page.tsx`:
- Line 13: Replace the hardcoded hex in the main element's className in the
Terms page (the <main> with className containing
bg-[linear-gradient(180deg,`#171937_0`%,transparent_20%)]) with a theme-aware
gradient that uses the app's CSS custom property (e.g.
var(--color-background-default)) or Tailwind dark: utilities so it adapts to
light/dark themes; update the gradient to reference
var(--color-background-default) (or a dark: variant) instead of `#171937` so the
background matches ThemeProvider-driven colors and remains legible in both
modes.

---

Nitpick comments:
In `@apps/site/src/data/terms.tsx`:
- Around line 5-8: Export the existing TermsSection type so it can be reused by
the accordion component; change the declaration of TermsSection (type
TermsSection = { title: string; content: ReactNode; };) to an exported type and
update the consumer file (where a local Section type is defined in
terms-accordion.tsx) to import and use TermsSection instead of its local Section
definition to remove duplication and keep a single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 21307fcf-d120-4ef4-8d0d-9c47ad4c4907

📥 Commits

Reviewing files that changed from the base of the PR and between 6f79795 and 9f309d3.

📒 Files selected for processing (3)
  • apps/site/src/app/terms/_components/terms-accordion.tsx
  • apps/site/src/app/terms/page.tsx
  • apps/site/src/data/terms.tsx

Comment on lines +25 to +45
<button
type="button"
className="flex w-full items-center justify-between py-3 text-left cursor-pointer"
onClick={onToggle}
aria-expanded={isOpen}
>
<span className="text-lg font-bold leading-[25px] text-foreground-neutral">
{section.title}
</span>
<i
className={cn(
"fa-regular text-foreground-neutral-weaker text-lg",
isOpen ? "fa-chevron-up" : "fa-chevron-down",
)}
/>
</button>
{isOpen && (
<div className="pb-4 text-foreground-neutral-weak text-left [&_p]:my-4 [&_a]:underline [&_a]:transition-colors [&_a]:duration-150 hover:[&_a]:text-foreground-neutral [&_ul]:list-revert [&_ul]:m-revert [&_ul]:p-revert [&_ol]:list-revert [&_ol]:m-revert [&_ol]:p-revert [&_li]:my-2 print:text-foreground-neutral">
{section.content}
</div>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Accessibility: Add aria-controls and content panel id for screen reader support.

The button has aria-expanded (good!), but it's missing aria-controls to indicate which element it controls. Additionally, the content panel needs an id that matches. This helps screen reader users understand the relationship between the toggle and the content.

♿ Proposed fix
 function AccordionItem({
   section,
   isOpen,
   onToggle,
+  index,
 }: {
   section: Section;
   isOpen: boolean;
   onToggle: () => void;
+  index: number;
 }) {
   const anchorId = section.title.trim().toLowerCase().replace(/\s+/g, "-");
+  const contentId = `${anchorId}-content`;

   return (
     <div className="scroll-mt-16 md:scroll-mt-24 border-t border-stroke-neutral" id={anchorId}>
       <button
         type="button"
         className="flex w-full items-center justify-between py-3 text-left cursor-pointer"
         onClick={onToggle}
         aria-expanded={isOpen}
+        aria-controls={contentId}
       >
         <span className="text-lg font-bold leading-[25px] text-foreground-neutral">
           {section.title}
         </span>
         <i
           className={cn(
             "fa-regular text-foreground-neutral-weaker text-lg",
             isOpen ? "fa-chevron-up" : "fa-chevron-down",
           )}
         />
       </button>
-      {isOpen && (
-        <div className="pb-4 text-foreground-neutral-weak ...">
+      <div
+        id={contentId}
+        className="pb-4 text-foreground-neutral-weak ..."
+        hidden={!isOpen}
+      >
           {section.content}
-        </div>
-      )}
+      </div>
     </div>
   );
 }

Using hidden instead of conditional rendering keeps the element in the DOM for aria-controls to reference while still hiding it visually and from assistive tech.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/app/terms/_components/terms-accordion.tsx` around lines 25 -
45, The toggle button (onToggle, aria-expanded={isOpen}) needs an aria-controls
that points to the content panel id and the content panel needs a matching id so
screen readers can link them; create a stable panelId (e.g., derived from
section.id or a generated string) and set aria-controls={panelId} on the button
and id={panelId} on the content div, render the panel always (do not remove it
from the DOM) and hide it when closed using a CSS utility like hidden or
aria-hidden to preserve the relationship, and ensure you update aria-hidden to
reflect isOpen.

Comment on lines +68 to +71
const printPage = () => {
setExpandAll(true);
setTimeout(() => window.print(), 50);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

The 50ms timeout before printing is a race condition.

React's state update and subsequent re-render aren't guaranteed to complete within 50ms, especially on slower devices. This could result in printing with sections still collapsed.

🔧 Proposed fix using useEffect
+import { useState, useEffect } from "react";
+
 export function TermsAccordion({ sections }: { sections: Section[] }) {
   const [expandAll, setExpandAll] = useState(false);
   const [selected, setSelected] = useState(0);
+  const [isPrinting, setIsPrinting] = useState(false);
+
+  useEffect(() => {
+    if (isPrinting && expandAll) {
+      window.print();
+      setIsPrinting(false);
+    }
+  }, [isPrinting, expandAll]);

   const printPage = () => {
     setExpandAll(true);
-    setTimeout(() => window.print(), 50);
+    setIsPrinting(true);
   };

This ensures window.print() is called only after React has committed the state change where expandAll is true.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/app/terms/_components/terms-accordion.tsx` around lines 68 -
71, The printPage function currently sets expandAll then uses a 50ms timeout
which is a race; instead update printPage to only call setExpandAll(true) and
move the window.print() call into a useEffect that watches expandAll so printing
occurs after React commits the state change; locate printPage and the expandAll
state (setExpandAll, expandAll) in terms-accordion.tsx and implement a useEffect
that triggers window.print() when expandAll becomes true, then reset expandAll
if needed.

@argos-ci
Copy link

argos-ci bot commented Mar 26, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Mar 26, 2026, 8:15 PM

- Extract shared accordion into @/components/legal-accordion
- Fix accordion state to track individual items via Set<number>
- Add fixed-height gradient for consistent look across pages
- All pages start collapsed by default
- /sla, /privacy, /event-code-of-conduct, /partners/tos
@AmanVarshney01 AmanVarshney01 changed the title feat: DR-7746 terms of service page feat: DR-7746 legal pages (terms, SLA, privacy, code of conduct, partner TOS) Mar 26, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apps/site/src/app/privacy/page.tsx (1)

11-35: Consider extracting a shared layout component.

The page structure (hero with title/last-updated, separator, content grid) is nearly identical across /privacy, /sla, /terms, and /event-code-of-conduct. A shared LegalPageLayout component accepting title, lastUpdated, description?, and children would reduce duplication and ensure consistency.

💡 Example abstraction
// apps/site/src/components/legal-page-layout.tsx
export function LegalPageLayout({
  title,
  lastUpdated,
  description,
  children,
}: {
  title: string;
  lastUpdated: string;
  description?: ReactNode;
  children: ReactNode;
}) {
  return (
    <main className="flex-1 w-full z-1 -mt-24 pt-24 relative before:absolute ...">
      <div className="text-center py-16">
        <h1 className="text-5xl font-bold ...">{title}</h1>
        {description && <p className="...">{description}</p>}
        <p className="..."><b>Last updated:</b> {lastUpdated}</p>
      </div>
      <div className="max-w-[1248px] mx-auto ...">
        <hr className="border-stroke-neutral" />
      </div>
      <div className="mx-auto w-full max-w-[1248px] ...">
        {children}
      </div>
    </main>
  );
}

Then pages become:

export default function PrivacyPage() {
  return (
    <LegalPageLayout title="Privacy Policy" lastUpdated={privacyLastUpdated}>
      <LegalAccordion sections={privacySections} />
    </LegalPageLayout>
  );
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/app/privacy/page.tsx` around lines 11 - 35, The PrivacyPage
repeats shared layout markup used by other legal pages; extract a new reusable
component (e.g., LegalPageLayout) that accepts props title, lastUpdated,
optional description, and children, move the hero / separator / container markup
into that component, then update PrivacyPage (replace the current main JSX) to
render <LegalPageLayout title="Privacy Policy"
lastUpdated={privacyLastUpdated}>{/* body */}</LegalPageLayout> and pass the
existing body (LegalAccordion with privacySections) as children; ensure
references to privacyLastUpdated and privacySections remain unchanged and other
legal pages (SLA, Terms, EventCodeOfConduct) are refactored to use the same
LegalPageLayout for consistency.
apps/site/src/components/legal-accordion.tsx (1)

21-21: Consider a more robust anchor ID generation.

The current approach retains characters like periods and colons (e.g., "1.-commitment-to-service"). While technically valid, a more thorough sanitization could improve URL fragment aesthetics and prevent potential edge cases:

- const anchorId = section.title.trim().toLowerCase().replace(/\s+/g, "-");
+ const anchorId = section.title
+   .trim()
+   .toLowerCase()
+   .replace(/[^\w\s-]/g, "")  // Remove special chars
+   .replace(/\s+/g, "-");

Alternatively, accept an explicit id in the Section type for full control.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/components/legal-accordion.tsx` at line 21, The anchor
generation using const anchorId =
section.title.trim().toLowerCase().replace(/\s+/g, "-") is fragile; update
legal-accordion to prefer an explicit section.id if provided on the Section type
and otherwise generate a robust slug from section.title by: lowercasing,
replacing all non-alphanumeric characters with hyphens, collapsing multiple
hyphens into one, and trimming leading/trailing hyphens (e.g., use a regex to
replace [^a-z0-9]+ -> "-" then .replace(/-+/g,"-") and .replace(/^-|-$/g,"")).
Modify the Section type to include an optional id, change the anchorId
computation in legal-accordion.tsx to use section.id ?? generatedSlug, and
ensure any consumers that create Section objects can pass explicit ids when
needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/site/src/app/privacy/page.tsx`:
- Around line 11-35: The PrivacyPage repeats shared layout markup used by other
legal pages; extract a new reusable component (e.g., LegalPageLayout) that
accepts props title, lastUpdated, optional description, and children, move the
hero / separator / container markup into that component, then update PrivacyPage
(replace the current main JSX) to render <LegalPageLayout title="Privacy Policy"
lastUpdated={privacyLastUpdated}>{/* body */}</LegalPageLayout> and pass the
existing body (LegalAccordion with privacySections) as children; ensure
references to privacyLastUpdated and privacySections remain unchanged and other
legal pages (SLA, Terms, EventCodeOfConduct) are refactored to use the same
LegalPageLayout for consistency.

In `@apps/site/src/components/legal-accordion.tsx`:
- Line 21: The anchor generation using const anchorId =
section.title.trim().toLowerCase().replace(/\s+/g, "-") is fragile; update
legal-accordion to prefer an explicit section.id if provided on the Section type
and otherwise generate a robust slug from section.title by: lowercasing,
replacing all non-alphanumeric characters with hyphens, collapsing multiple
hyphens into one, and trimming leading/trailing hyphens (e.g., use a regex to
replace [^a-z0-9]+ -> "-" then .replace(/-+/g,"-") and .replace(/^-|-$/g,"")).
Modify the Section type to include an optional id, change the anchorId
computation in legal-accordion.tsx to use section.id ?? generatedSlug, and
ensure any consumers that create Section objects can pass explicit ids when
needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6ea6e71d-085f-4925-921e-d72a0deeaabf

📥 Commits

Reviewing files that changed from the base of the PR and between 9f309d3 and bb3c236.

📒 Files selected for processing (10)
  • apps/site/src/app/event-code-of-conduct/page.tsx
  • apps/site/src/app/partners/tos/page.tsx
  • apps/site/src/app/privacy/page.tsx
  • apps/site/src/app/sla/page.tsx
  • apps/site/src/app/terms/page.tsx
  • apps/site/src/components/legal-accordion.tsx
  • apps/site/src/data/event-code-of-conduct.tsx
  • apps/site/src/data/partners-tos.tsx
  • apps/site/src/data/privacy.tsx
  • apps/site/src/data/sla.tsx
✅ Files skipped from review due to trivial changes (4)
  • apps/site/src/app/partners/tos/page.tsx
  • apps/site/src/data/event-code-of-conduct.tsx
  • apps/site/src/data/partners-tos.tsx
  • apps/site/src/data/privacy.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/site/src/app/terms/page.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant