Skip to content

Commit

Permalink
feat: add list of area's routes to route page (#1064)
Browse files Browse the repository at this point in the history
* feat: add list of area's routes to route page
  • Loading branch information
btmccord authored Jan 9, 2024
1 parent 493e70a commit f40f3b2
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 61 deletions.
36 changes: 24 additions & 12 deletions src/app/editArea/[slug]/general/components/climb/ClimbListForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { removeTypenameFromDisciplines, climbLeftRightIndexComparator } from '@/
import Grade, { GradeContexts } from '@/js/grades/Grade'
import { ClimbListMiniToolbar } from '../../../manageClimbs/components/ClimbListMiniToolbar'

export const ClimbList: React.FC<{ gradeContext: GradeContexts, climbs: ClimbType[], areaMetadata: AreaMetadataType, editMode: boolean }> = ({ gradeContext, climbs, areaMetadata, editMode }) => {
export const ClimbList: React.FC<{ gradeContext: GradeContexts, climbs: ClimbType[], areaMetadata: AreaMetadataType, editMode: boolean, routePageId?: string }> = ({ gradeContext, climbs, areaMetadata, editMode, routePageId }) => {
const sortedClimbs = [...climbs].sort(climbLeftRightIndexComparator)
return (
<div>
Expand All @@ -16,8 +16,9 @@ export const ClimbList: React.FC<{ gradeContext: GradeContexts, climbs: ClimbTyp
: <NoClimbsCTA areaId={areaMetadata.areaId} />
)
: null}
<ol className={clx(climbs.length < 5 ? 'block max-w-sm' : 'three-column-table', 'divide-y divide-base-200')}>
<ol className={routePageId === undefined ? clx(climbs.length < 5 ? 'block max-w-sm' : 'three-column-table', 'divide-y divide-base-200') : ''}>
{sortedClimbs.map((climb, index) => {
const isThisRoute = climb.id === routePageId
return (
<ClimbRow
key={climb.id}
Expand All @@ -26,6 +27,7 @@ export const ClimbList: React.FC<{ gradeContext: GradeContexts, climbs: ClimbTyp
{...climb}
index={index + 1}
editMode={editMode}
isThisRoute={isThisRoute}
/>
)
})}
Expand All @@ -34,7 +36,7 @@ export const ClimbList: React.FC<{ gradeContext: GradeContexts, climbs: ClimbTyp
)
}

const ClimbRow: React.FC<ClimbType & { index: number, gradeContext: GradeContexts, areaMetadata: AreaMetadataType, editMode?: boolean }> = ({ id, name, type: disciplines, index, gradeContext, grades, areaMetadata, editMode = false }) => {
export const ClimbRow: React.FC<ClimbType & { index: number, gradeContext: GradeContexts, areaMetadata: AreaMetadataType, editMode?: boolean, isThisRoute: boolean }> = ({ id, name, type: disciplines, index, gradeContext, grades, areaMetadata, editMode = false, isThisRoute }) => {
const sanitizedDisciplines = removeTypenameFromDisciplines(disciplines)
const gradeStr = new Grade(
gradeContext,
Expand All @@ -44,18 +46,20 @@ const ClimbRow: React.FC<ClimbType & { index: number, gradeContext: GradeContext
).toString()
const url = `/climbs/${id}`
return (
<li className='py-2 break-inside-avoid-column break-inside-avoid'>
<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' : '')}>
<a href={url} className='flex gap-x-4 flex-nowrap w-full'>
<ListBullet index={index} disciplines={disciplines} />
<div className='w-full'>
<div className='flex justify-between'>
<div className='text-base font-semibold uppercase tracking-tight hover:underline'>{name}</div>
<div>{gradeStr}</div>
<LinkWrapper isThisRoute={isThisRoute} url={url}>
<div className='flex gap-x-4 flex-nowrap w-full'>
<ListBullet index={index} disciplines={disciplines} />
<div className='w-full'>
<div className='flex justify-between'>
<div className={clx('text-base font-semibold uppercase tracking-tight', isThisRoute ? '' : 'hover:underline')}>{name}</div>
<div>{gradeStr}</div>
</div>
<div><DisciplinesInfo disciplines={disciplines} /></div>
</div>
<div><DisciplinesInfo disciplines={disciplines} /></div>
</div>
</a>
</LinkWrapper>
</div>
{editMode &&
<ClimbListMiniToolbar climbId={id} parentAreaId={areaMetadata.areaId} climbName={name} />}
Expand Down Expand Up @@ -101,3 +105,11 @@ const NoClimbsCTA: React.FC<{ areaId: string }> = ({ areaId }) => (
</a>
</div>
)

const LinkWrapper: React.FC<{ isThisRoute: boolean, url: string, children: React.ReactNode }> = ({ isThisRoute, url, children }) => {
return (
<>
{isThisRoute ? <>{children} </> : <a href={url}>{children}</a>}
</>
)
}
69 changes: 21 additions & 48 deletions src/pages/climbs/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from 'react'
import { GetStaticProps, NextPage } from 'next'
import { useRouter } from 'next/router'
import { gql } from '@apollo/client'
import { useForm, FormProvider } from 'react-hook-form'
import { useSession } from 'next-auth/react'
import dynamic from 'next/dynamic'
Expand All @@ -11,7 +10,6 @@ import { useSwipeable } from 'react-swipeable'
import { toast } from 'react-toastify'
import ArrowVertical from '../../assets/icons/arrow-vertical.svg'

import { graphqlClient } from '../../js/graphql/Client'
import Layout from '../../components/layout'
import { AreaType, ClimbDisciplineRecord, ClimbType, RulesType } from '../../js/types'
import SeoTags from '../../components/SeoTags'
Expand All @@ -33,6 +31,9 @@ import { TotalLengthInput } from '../../components/edit/form/TotalLengthInput'
import { LegacyFAInput } from '../../components/edit/form/LegacyFAInput'
import { getClimbById } from '../../js/graphql/api'
import { GraphQLError } from 'graphql/error/GraphQLError'
import { ClimbList } from '@/app/editArea/[slug]/general/components/climb/ClimbListForm'
import { getArea } from '@/js/graphql/getArea'
import { climbLeftRightIndexComparator } from '@/js/utils'

export const CLIMB_DESCRIPTION_FORM_VALIDATION_RULES: RulesType = {
maxLength: {
Expand All @@ -59,6 +60,7 @@ interface ClimbPageProps {
leftClimb: ClimbType | null
rightClimb: ClimbType | null
showSkeleton?: boolean
parentArea: AreaType
}

const ClimbPage: NextPage<ClimbPageProps> = (props: ClimbPageProps) => {
Expand Down Expand Up @@ -102,7 +104,7 @@ export interface ClimbEditFormProps {
length?: number
}

const Body = ({ climb, leftClimb, rightClimb }: ClimbPageProps): JSX.Element => {
const Body = ({ climb, leftClimb, rightClimb, parentArea }: ClimbPageProps): JSX.Element => {
const {
id, name, fa: legacyFA, length, yds, grades, type, content, safety, metadata, ancestors, pathTokens, authorMetadata,
parent
Expand Down Expand Up @@ -295,7 +297,7 @@ const Body = ({ climb, leftClimb, rightClimb }: ClimbPageProps): JSX.Element =>
</div>
</div>

<div className='area-climb-page-summary-right'>
<div className='area-climb-page-summary-right col-start-2 col-end-4 row-start-1 row-end-3'>
<div className='mb-3 flex justify-between items-center'>
<h3>Description</h3>
</div>
Expand Down Expand Up @@ -344,6 +346,11 @@ const Body = ({ climb, leftClimb, rightClimb }: ClimbPageProps): JSX.Element =>
{FormAction}
</div>
</div>
<div className='col-start-1 col-end-2'>
<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' />
{!editMode && <ClimbList gradeContext={parentArea.gradeContext} climbs={parentArea.climbs} areaMetadata={parentArea.metadata} editMode={editMode} routePageId={climbId} />}
</div>
</div>
</form>
</FormProvider>
Expand Down Expand Up @@ -378,14 +385,18 @@ export const getStaticProps: GetStaticProps<ClimbPageProps, { id: string }> = as
}
}

const sortedClimbsInArea = await fetchSortedClimbsInArea(climb.ancestors[climb.ancestors.length - 1])
const parentAreaData = await getArea(climb.ancestors[climb.ancestors.length - 1], 'cache-first')
let leftClimb: ClimbType | null = null
let rightClimb: ClimbType | null = null

for (const [index, climb] of sortedClimbsInArea.entries()) {
const parentArea = parentAreaData.area

const sortedClimbs = [...parentArea.climbs].sort(climbLeftRightIndexComparator)

for (const [index, climb] of sortedClimbs.entries()) {
if (climb.id === params.id) {
leftClimb = (sortedClimbsInArea[index - 1] != null) ? sortedClimbsInArea[index - 1] : null
rightClimb = sortedClimbsInArea[index + 1] != null ? sortedClimbsInArea[index + 1] : null
leftClimb = (sortedClimbs[index - 1] != null) ? sortedClimbs[index - 1] : null
rightClimb = sortedClimbs[index + 1] != null ? sortedClimbs[index + 1] : null
}
}

Expand All @@ -395,51 +406,13 @@ export const getStaticProps: GetStaticProps<ClimbPageProps, { id: string }> = as
key: climb.id,
climb,
leftClimb,
rightClimb
rightClimb,
parentArea
},
revalidate: 30
}
}

/**
* Fetch and sort the climbs in the area from left to right
*/
const fetchSortedClimbsInArea = async (uuid: string): Promise<ClimbType[]> => {
const query = gql`query SortedNearbyClimbsByAreaUUID($uuid: ID) {
area(uuid: $uuid) {
uuid,
climbs {
uuid,
id,
metadata {
climbId,
left_right_index
}
}
}
}`

const rs = await graphqlClient.query<{ area: AreaType }>({
query,
variables: {
uuid
}
})

if (rs.data == null || rs.data.area == null) {
return []
}

// Copy readonly array so we can sort
const routes = [...rs.data.area.climbs]

return routes.sort(
(a, b) =>
parseInt(a.metadata.left_right_index, 10) -
parseInt(b.metadata.left_right_index, 10)
)
}

const trimLegacyFA = (s: string): string => {
if (s == null || s.trim() === '') return 'FA Unknown'
if (s.startsWith('FA')) return s
Expand Down
2 changes: 1 addition & 1 deletion src/styles/defaults.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ a:active, a:focus {
}

.area-climb-page-summary-right {
@apply mt-6 lg:mt-0 lg:col-span-2 lg:pl-16 w-full;
@apply mt-6 lg:mt-0 lg:pl-16 w-full;
}

/**
Expand Down

1 comment on commit f40f3b2

@vercel
Copy link

@vercel vercel bot commented on f40f3b2 Jan 9, 2024

Choose a reason for hiding this comment

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

Please sign in to comment.