diff --git a/frontend/__tests__/unit/components/SnapshotReleaseSection.test.tsx b/frontend/__tests__/unit/components/SnapshotReleaseSection.test.tsx
new file mode 100644
index 0000000000..269fad7a76
--- /dev/null
+++ b/frontend/__tests__/unit/components/SnapshotReleaseSection.test.tsx
@@ -0,0 +1,37 @@
+import '@testing-library/jest-dom'
+import { render, screen } from '@testing-library/react'
+import { ReleasesSection } from 'components/SnapshotReleaseSection'
+import { MAX_RELEASES_TO_SHOW } from 'utils/constants'
+
+describe('ReleasesSection', () => {
+ const mockReleases = Array.from({ length: MAX_RELEASES_TO_SHOW + 1 }, (_, i) => ({
+ id: `release-${i}`,
+ name: `Release v${i}`,
+ publishedAt: new Date().toISOString(),
+ tagName: `v${i}`,
+ }))
+
+ it('renders only MAX_RELEASES_TO_SHOW items when showAll is false', () => {
+ render()
+
+ const items = screen.getAllByText(/Release v/)
+ expect(items.length).toBe(MAX_RELEASES_TO_SHOW)
+ })
+
+ it('renders all releases when showAll is true', () => {
+ render()
+
+ const items = screen.getAllByText(/Release v/)
+ expect(items.length).toBe(MAX_RELEASES_TO_SHOW + 1)
+ })
+
+ it('button has label `show all` for releases > MAX_RELEASES_TO_SHOW', () => {
+ render()
+ expect(screen.getByRole('button', { name: 'show all' })).toBeInTheDocument()
+ })
+
+ it('button has label `show less` for releases > MAX_RELEASES_TO_SHOW', () => {
+ render()
+ expect(screen.getByRole('button', { name: 'show less' })).toBeInTheDocument()
+ })
+})
diff --git a/frontend/src/app/community/snapshots/[id]/page.tsx b/frontend/src/app/community/snapshots/[id]/page.tsx
index 5da0304710..9ca852d5fd 100644
--- a/frontend/src/app/community/snapshots/[id]/page.tsx
+++ b/frontend/src/app/community/snapshots/[id]/page.tsx
@@ -1,7 +1,7 @@
'use client'
import { useQuery } from '@apollo/client/react'
import { useRouter, useParams } from 'next/navigation'
-import React, { useEffect } from 'react'
+import React, { useEffect, useState } from 'react'
import { FaCalendar, FaRightToBracket } from 'react-icons/fa6'
import { handleAppError, ErrorDisplay } from 'app/global-error'
import { GetSnapshotDetailsDocument } from 'types/__generated__/snapshotQueries.generated'
@@ -14,12 +14,14 @@ import { getFilteredIcons, handleSocialUrls } from 'utils/utility'
import Card from 'components/Card'
import ChapterMapWrapper from 'components/ChapterMapWrapper'
import LoadingSpinner from 'components/LoadingSpinner'
-import Release from 'components/Release'
+import { ReleasesSection } from 'components/SnapshotReleaseSection'
const SnapshotDetailsPage: React.FC = () => {
const { id: snapshotKey } = useParams<{ id: string }>()
const router = useRouter()
+ const [showAllReleases, setShowAllReleases] = useState(false)
+
const {
data,
error: graphQLRequestError,
@@ -29,6 +31,9 @@ const SnapshotDetailsPage: React.FC = () => {
})
const snapshot = data?.snapshot
+ useEffect(() => {
+ setShowAllReleases(false)
+ }, [snapshot])
useEffect(() => {
if (graphQLRequestError) {
@@ -183,21 +188,13 @@ const SnapshotDetailsPage: React.FC = () => {
New Releases
-
- {snapshot.newReleases.map((release, index) => {
- return (
-
- )
- })}
-
+ {
+ setShowAllReleases((p) => !p)}
+ />
+ }
)}
diff --git a/frontend/src/components/SnapshotReleaseSection.tsx b/frontend/src/components/SnapshotReleaseSection.tsx
new file mode 100644
index 0000000000..e1bf6c60cb
--- /dev/null
+++ b/frontend/src/components/SnapshotReleaseSection.tsx
@@ -0,0 +1,44 @@
+import { MAX_RELEASES_TO_SHOW } from 'utils/constants'
+import Release from 'components/Release'
+import type { Release as ReleaseType } from 'types/release'
+
+type ReleasesSectionProps = {
+ releases: ReleaseType[]
+ showAll: boolean
+ onToggle: () => void
+}
+
+export const ReleasesSection = ({ releases, showAll, onToggle }: ReleasesSectionProps) => {
+ const showButton = {
+ label: showAll ? 'show less' : 'show all',
+ classname:
+ 'dark:hover:text-white rounded-md border-1 font-light border-blue-400 p-2 text-blue-400 hover:bg-blue-500 hover:text-white',
+ }
+
+ const visibleReleases = showAll ? releases : releases.slice(0, MAX_RELEASES_TO_SHOW)
+ return (
+ <>
+
+ {visibleReleases.map((release, index) => {
+ return (
+
+ )
+ })}
+
+ {releases.length > MAX_RELEASES_TO_SHOW && (
+
+
+
+ )}
+ >
+ )
+}
diff --git a/frontend/src/utils/constants.ts b/frontend/src/utils/constants.ts
index 01b90cad6d..9316925e29 100644
--- a/frontend/src/utils/constants.ts
+++ b/frontend/src/utils/constants.ts
@@ -119,6 +119,8 @@ export const themeToggleTooltip = {
export const desktopViewMinWidth = 768
+export const MAX_RELEASES_TO_SHOW = 9
+
export const userAuthStatus = {
AUTHENTICATED: 'authenticated',
LOADING: 'loading',