Skip to content

Commit

Permalink
wip: migrate climb page to next13 structure
Browse files Browse the repository at this point in the history
  • Loading branch information
vnugent committed Oct 31, 2024
1 parent e06b801 commit 252d1e2
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 32 deletions.
27 changes: 2 additions & 25 deletions src/app/(default)/area/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { notFound, permanentRedirect } from 'next/navigation'
import Link from 'next/link'
import { Metadata } from 'next'
import { validate } from 'uuid'
import { MapPinLine, Lightbulb, ArrowRight } from '@phosphor-icons/react/dist/ssr'
import Markdown from 'react-markdown'

Expand All @@ -10,7 +9,7 @@ import { getArea } from '@/js/graphql/getArea'
import { StickyHeaderContainer } from '@/app/(default)/components/ui/StickyHeaderContainer'
import { AreaCrumbs } from '@/components/breadcrumbs/AreaCrumbs'
import { ArticleLastUpdate } from '@/components/edit/ArticleLastUpdate'
import { getMapHref, getFriendlySlug, getAreaPageFriendlyUrl, sanitizeName } from '@/js/utils'
import { getMapHref, getFriendlySlug, getAreaPageFriendlyUrl, sanitizeName, parseUuidAsFirstParam } from '@/js/utils'
import { LazyAreaMap } from '@/components/maps/AreaMap'
import { AreaPageContainer } from '@/app/(default)/components/ui/AreaPageContainer'
import { AreaPageActions } from '../../components/AreaPageActions'
Expand All @@ -19,19 +18,13 @@ import { ClimbListSection } from './sections/ClimbListSection'
import { CLIENT_CONFIG } from '@/js/configs/clientConfig'
import { PageBanner as LCOBanner } from '@/components/lco/PageBanner'
import { AuthorMetadata, OrganizationType } from '@/js/types'
import { PageWithCatchAllUuidProps, PageSlugType } from '@/js/types/pages'
/**
* Page cache settings
*/
export const revalidate = 300 // 5 mins
export const fetchCache = 'force-no-store' // opt out of Nextjs version of 'fetch'

interface PageSlugType {
slug: string []
}
export interface PageWithCatchAllUuidProps {
params: PageSlugType
}

/**
* Area/crag page
*/
Expand Down Expand Up @@ -96,22 +89,6 @@ export default async function Page ({ params }: PageWithCatchAllUuidProps): Prom
)
}

/**
* Extract and validate uuid as the first param in a catch-all route
*/
const parseUuidAsFirstParam = ({ params }: PageWithCatchAllUuidProps): string => {
if (params.slug == null || params.slug?.length === 0) {
notFound()
}

const uuid = params.slug[0]
if (!validate(uuid)) {
console.error('Invalid uuid', uuid)
notFound()
}
return uuid
}

const EditDescriptionCTA: React.FC<{ uuid: string }> = ({ uuid }) => (
<div role='alert' className='alert'>
<Lightbulb size={24} />
Expand Down
56 changes: 56 additions & 0 deletions src/app/(default)/climb/[[...slug]]/components/ClimbData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { ArrowsVertical } from '@phosphor-icons/react/dist/ssr'

// import RouteGradeChip from '@/components/ui/RouteGradeChip'
import RouteTypeChips from '@/components/ui/RouteTypeChips'
import { ArticleLastUpdate } from '@/components/edit/ArticleLastUpdate'
import { Climb } from '@/js/types'

export const ClimbData: React.FC<Climb> = (props) => {
const { name, type, safety, length, grades, fa: legacyFA, authorMetadata } = props
console.log(safety, grades)
return (
<>
<h1 className='text-4xl md:text-5xl mr-10'>
{name}
</h1>
<div className='mt-6'>
<div className='flex items-center space-x-2 w-full'>
{/* {gradeStr != null && (
<RouteGradeChip gradeStr={gradeStr} safety={safety} />
)} */}
<RouteTypeChips type={type} />
</div>

{length !== -1 && (
<div className='mt-6 inline-flex items-center justify-left border-2 border-neutral/80 rounded'>
<ArrowsVertical className='h-5 w-5' />
<span className='bg-neutral/80 text-base-100 px-2 text-sm'>{length}m</span>
</div>
)}
{/* {editMode && <TotalLengthInput />} */}

<div className='mt-6'>
<div className='text-sm font-medium text-base-content'>{trimLegacyFA(legacyFA)}</div>
</div>

{(authorMetadata.createdAt != null || authorMetadata.updatedAt != null) && (
<div className='mt-8 border-t border-b'>
<ArticleLastUpdate {...authorMetadata} />
</div>
)}

{/* {!editMode && (
<div className='mt-8'>
<TickButton climbId={climbId} name={name} grade={yds} />
</div>
)} */}
</div>
</>
)
}

const trimLegacyFA = (s: string): string => {
if (s == null || s.trim() === '') return 'FA Unknown'
if (s.startsWith('FA')) return s
return 'FA ' + s
}
26 changes: 26 additions & 0 deletions src/app/(default)/climb/[[...slug]]/components/ContentBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Climb } from '@/js/types'

export const ContentBlock: React.FC<Pick<Climb, 'content'>> = ({ content: { description, location, protection } }) => {
return (
<>
<div className='mb-3 flex justify-between items-center'>
<h3>Description</h3>
</div>
{description}

{(location?.trim() !== '') && (
<>
<h3 className='mb-3 mt-6'>Location</h3>
{location}
</>
)}

{(protection?.trim() !== '') && (
<>
<h3 className='mb-3 mt-6'>Protection</h3>
{protection}
</>
)}
</>
)
}
29 changes: 29 additions & 0 deletions src/app/(default)/climb/[[...slug]]/components/SiblingClimbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ClimbList } from '@/app/(default)/editArea/[slug]/general/components/climb/ClimbListForm'
import { AreaType } from '@/js/types'

/**
* Show sibling climbs
*/
export const SiblingClimbs: React.FC<{ parentArea: AreaType, climbId: string }> = ({
parentArea,
climbId
}) => {
return (
<>
<h4>
Routes in{' '}
{parentArea.areaName.includes(', The')
? 'The '.concat(parentArea.areaName.slice(0, -5))
: parentArea.areaName}
</h4>
<hr className='mt-2 mb-2 border-1 border-base-content' />
<ClimbList
gradeContext={parentArea.gradeContext}
climbs={parentArea.climbs}
areaMetadata={parentArea.metadata}
routePageId={climbId}
editMode={false}
/>
</>
)
}
72 changes: 72 additions & 0 deletions src/app/(default)/climb/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { notFound } from 'next/navigation'

import { AreaCrumbs } from '@/components/breadcrumbs/AreaCrumbs'
import { AreaPageContainer } from '../../components/ui/AreaPageContainer'
import PhotoMontage, { UploadPhotoCTA } from '@/components/media/PhotoMontage'
import { StickyHeaderContainer } from '../../components/ui/StickyHeaderContainer'
import { parseUuidAsFirstParam } from '@/js/utils'
import { PageWithCatchAllUuidProps } from '@/js/types/pages'
import { getClimbById } from '@/js/graphql/api'
import { ClimbData } from './components/ClimbData'
import { ContentBlock } from './components/ContentBlock'
import { Summary } from '../../components/ui/Summary'
import { SiblingClimbs } from './components/SiblingClimbs'
import { LazyAreaMap } from '@/components/maps/AreaMap'

export default async function Page ({ params }: PageWithCatchAllUuidProps): Promise<any> {
const climbId = parseUuidAsFirstParam({ params })
const climb = await getClimbById(climbId)
if (climb == null) {
notFound()
}

const photoList = climb.media

const {
id, ancestors, pathTokens
} = climb
return (
<AreaPageContainer
photoGallery={
photoList.length === 0
? <UploadPhotoCTA />
: <PhotoMontage photoList={photoList} />
}
// pageActions={<AreaPageActions areaName={areaName} uuid={uuid} />}
breadcrumbs={
<StickyHeaderContainer>
<AreaCrumbs pathTokens={pathTokens} ancestors={ancestors} />
</StickyHeaderContainer>
}
summary={{
left: <ClimbData {...climb} />,
right: <ContentBlock content={climb.content} />
}}
map={(
<LazyAreaMap
focused={null}
selected={climb.parent.id}
subAreas={[]}
area={climb.parent}
/>)}
mapContainerClass='block lg:hidden h-[90vh] w-full'
>
<hr className='border-1 my-8' />
<Summary
columns={{
left: <SiblingClimbs parentArea={climb.parent} climbId={id} />,
right: (
<div className='hidden lg:min-h-[500px] lg:h-full lg:block lg:relative'>
<LazyAreaMap
focused={null}
selected={climb.parent.id}
subAreas={[]}
area={climb.parent}
/>
</div>)
}}
/>
<div className='mt-16' />
</AreaPageContainer>
)
}
10 changes: 6 additions & 4 deletions src/app/(default)/components/ui/AreaPageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ export const AreaPageContainer: React.FC<{
breadcrumbs?: React.ReactNode
map?: React.ReactNode
summary?: { left: React.ReactNode, right: React.ReactNode }
mapContainerClass?: string
children?: React.ReactNode
}> = ({ photoGallery, pageActions, breadcrumbs, map, summary, children }) => {
}> = ({ photoGallery, pageActions, breadcrumbs, map, summary, children, mapContainerClass = 'w-full mt-16 relative h-[90vh] border-t' }) => {
return (
<article>
<div className='default-page-margins my-2'>
Expand All @@ -29,9 +30,10 @@ export const AreaPageContainer: React.FC<{
{summary != null && <Summary columns={summary} />}
{children == null ? <ContentSkeleton /> : children}
</div>
<div id='map' className='w-full mt-16 relative h-[90vh] border-t'>
{map != null && map}
</div>
{map != null && (
<div id='map' className={mapContainerClass}>
{map}
</div>)}
</article>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const ClimbRow: React.FC<ClimbType & { index: number, gradeContext: Grade
sanitizedDisciplines,
areaMetadata.isBoulder
).toString()
const url = `/climbs/${id}`
const url = `/climb/${id}`
return (
<li className={clx('py-2 break-inside-avoid-column break-inside-avoid', isThisRoute ? 'opacity-50' : '')}>
<div className={clx('w-full', editMode ? 'card card-compact p-2 card-bordered bg-base-100 shadow' : '')}>
Expand Down
23 changes: 23 additions & 0 deletions src/js/graphql/gql/climbById.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,32 @@ export const QUERY_CLIMB_BY_ID = gql`
climbId
}
parent {
areaName
gradeContext
metadata {
isBoulder
bbox
polygon
}
climbs {
id
name
grades {
...ClimbDisciplineFields
}
safety
type {
sport
bouldering
alpine
tr
trad
mixed
aid
}
metadata {
leftRightIndex
}
}
}
authorMetadata {
Expand Down
7 changes: 7 additions & 0 deletions src/js/types/pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface PageSlugType {
slug: string []
}

export interface PageWithCatchAllUuidProps {
params: PageSlugType
}
21 changes: 19 additions & 2 deletions src/js/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import slugify from 'slugify'

import { ClimbTypeToColor } from './constants'
import { notFound } from 'next/navigation'
import { validate } from 'uuid'
import { formatDistanceToNowStrict, differenceInYears, format } from 'date-fns'

import { ClimbTypeToColor } from './constants'
import { AreaType, ClimbType, ClimbDisciplineRecord, ClimbDiscipline, MediaWithTags, MediaConnection, AreaMetadataType } from './types'
import { PageWithCatchAllUuidProps } from './types/pages'

/**
* Given a path or parent id and the type of the page generate the GitHub URL
Expand Down Expand Up @@ -317,3 +319,18 @@ export const areaLeftRightIndexComparator = (a: SortableAreaType, b: SortableAre
else if (aIndex > bIndex) return 1
return 0
}
/**
* Extract and validate uuid as the first param in a catch-all route
*/
export const parseUuidAsFirstParam = ({ params }: PageWithCatchAllUuidProps): string => {
if (params.slug == null || params.slug?.length === 0) {
notFound()
}

const uuid = params.slug[0]
if (!validate(uuid)) {
console.error('Invalid uuid', uuid)
notFound()
}
return uuid
}

0 comments on commit 252d1e2

Please sign in to comment.