From 6c6debc7c46680a050bc42ea8defe0377c32aa51 Mon Sep 17 00:00:00 2001 From: viet nguyen Date: Sat, 23 Dec 2023 12:29:00 -0800 Subject: [PATCH] Add climb list to manage climbs page --- src/app/area/[[...slug]]/page.tsx | 7 +- .../[[...slug]]/sections/ClimbListSection.tsx | 24 +++---- .../[[...slug]]/sections/SubAreasSection.tsx | 4 +- src/app/editArea/[slug]/SidebarNav.tsx | 20 ++++-- src/app/editArea/[slug]/addClimbs/page.tsx | 16 ----- .../components/climb/ClimbListForm.tsx | 68 ++++++++++++------- src/app/editArea/[slug]/general/page.tsx | 20 +++++- .../components/AddClimbsForm.tsx | 2 +- .../components/ClimbListMiniToolbar.tsx | 35 ++++++++++ .../components/DisciplinesSelection.tsx | 0 .../components/DynamicClimbInputList.tsx | 0 src/app/editArea/[slug]/manageClimbs/page.tsx | 33 +++++++++ src/js/hooks/useUpdateClimbsCmd.tsx | 2 +- 13 files changed, 163 insertions(+), 68 deletions(-) delete mode 100644 src/app/editArea/[slug]/addClimbs/page.tsx rename src/app/editArea/[slug]/{addClimbs => manageClimbs}/components/AddClimbsForm.tsx (97%) create mode 100644 src/app/editArea/[slug]/manageClimbs/components/ClimbListMiniToolbar.tsx rename src/app/editArea/[slug]/{addClimbs => manageClimbs}/components/DisciplinesSelection.tsx (100%) rename src/app/editArea/[slug]/{addClimbs => manageClimbs}/components/DynamicClimbInputList.tsx (100%) create mode 100644 src/app/editArea/[slug]/manageClimbs/page.tsx diff --git a/src/app/area/[[...slug]]/page.tsx b/src/app/area/[[...slug]]/page.tsx index 3a99f38f1..cd7a5c987 100644 --- a/src/app/area/[[...slug]]/page.tsx +++ b/src/app/area/[[...slug]]/page.tsx @@ -123,8 +123,11 @@ export default async function Page ({ params }: PageWithCatchAllUuidProps): Prom - - + {/* An area can only have either subareas or climbs, but not both. */} +
+ + +
) } diff --git a/src/app/area/[[...slug]]/sections/ClimbListSection.tsx b/src/app/area/[[...slug]]/sections/ClimbListSection.tsx index b3a1cc15b..94b09572b 100644 --- a/src/app/area/[[...slug]]/sections/ClimbListSection.tsx +++ b/src/app/area/[[...slug]]/sections/ClimbListSection.tsx @@ -1,30 +1,30 @@ -import Link from 'next/link' import { Plus } from '@phosphor-icons/react/dist/ssr' import { ClimbList } from '@/app/editArea/[slug]/general/components/climb/ClimbListForm' import { AreaType } from '@/js/types' /** - * Sub-areas section + * Climb list section */ -export const ClimbListSection: React.FC<{ area: AreaType }> = ({ area }) => { +export const ClimbListSection: React.FC<{ area: AreaType, editMode?: boolean }> = ({ area, editMode = false }) => { const { uuid, gradeContext, climbs, metadata } = area if (!metadata.leaf) return null return ( -
+

{climbs.length} Climbs

-
- Coming soon: - - New Climbs - -
+ {/* Already in the edit dashboard. Don't show the button */} + {!editMode && + }
-
+
- +
) } diff --git a/src/app/area/[[...slug]]/sections/SubAreasSection.tsx b/src/app/area/[[...slug]]/sections/SubAreasSection.tsx index c862fd370..e6d795bb0 100644 --- a/src/app/area/[[...slug]]/sections/SubAreasSection.tsx +++ b/src/app/area/[[...slug]]/sections/SubAreasSection.tsx @@ -11,7 +11,7 @@ export const SubAreasSection: React.FC<{ area: AreaType } > = ({ area }) => { const { uuid, children, metadata: { leaf } } = area if (leaf) return null return ( -
+

{children.length} Areas

@@ -21,7 +21,7 @@ export const SubAreasSection: React.FC<{ area: AreaType } > = ({ area }) => {
-
+
diff --git a/src/app/editArea/[slug]/SidebarNav.tsx b/src/app/editArea/[slug]/SidebarNav.tsx index 2d3145971..cc606e8ce 100644 --- a/src/app/editArea/[slug]/SidebarNav.tsx +++ b/src/app/editArea/[slug]/SidebarNav.tsx @@ -23,9 +23,9 @@ export const SidebarNav: React.FC<{ slug: string, canAddAreas: boolean, canAddCl
  • Manage climbs @@ -35,17 +35,23 @@ export const SidebarNav: React.FC<{ slug: string, canAddAreas: boolean, canAddCl

    -
    - - +
    diff --git a/src/app/editArea/[slug]/addClimbs/page.tsx b/src/app/editArea/[slug]/addClimbs/page.tsx deleted file mode 100644 index 8f645afa5..000000000 --- a/src/app/editArea/[slug]/addClimbs/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { DashboardPageProps, getPageDataForEdit } from '../general/page' -import { PageContainer, SectionContainer } from '../components/EditAreaContainers' -import { AddClimbsForm } from './components/AddClimbsForm' - -export default async function AddClimbsPage ({ params: { slug } }: DashboardPageProps): Promise { - const { area } = await getPageDataForEdit(slug) - const { areaName, uuid, gradeContext, metadata } = area - const { leaf, isBoulder } = metadata - return ( - - - - - - ) -} diff --git a/src/app/editArea/[slug]/general/components/climb/ClimbListForm.tsx b/src/app/editArea/[slug]/general/components/climb/ClimbListForm.tsx index 0f5a60e7b..b23441d27 100644 --- a/src/app/editArea/[slug]/general/components/climb/ClimbListForm.tsx +++ b/src/app/editArea/[slug]/general/components/climb/ClimbListForm.tsx @@ -1,30 +1,42 @@ -import Link from 'next/link' import clx from 'classnames' import { AreaMetadataType, ClimbDisciplineRecord, ClimbType } from '@/js/types' import { disciplineTypeToDisplay } from '@/js/grades/util' import { removeTypenameFromDisciplines } from '@/js/utils' import Grade, { GradeContexts } from '@/js/grades/Grade' +import { ClimbListMiniToolbar } from '../../../manageClimbs/components/ClimbListMiniToolbar' -export const ClimbList: React.FC<{ gradeContext: GradeContexts, climbs: ClimbType[], areaMetadata: AreaMetadataType }> = ({ gradeContext, climbs, areaMetadata }) => { +const leftRightIndexComparator = (a: ClimbType, b: ClimbType): number => { + const aIndex = a.metadata.leftRightIndex + const bIndex = b.metadata.leftRightIndex + if (aIndex < bIndex) return -1 + else if (aIndex > bIndex) return 1 + return 0 +} + +export const ClimbList: React.FC<{ gradeContext: GradeContexts, climbs: ClimbType[], areaMetadata: AreaMetadataType, editMode: boolean }> = ({ gradeContext, climbs, areaMetadata, editMode }) => { + const sortedClimbs = climbs.sort(leftRightIndexComparator) return ( - // it looks better -
      - {climbs.map((climb, index) => { - return ( - - ) - })} -
    +
    + {climbs.length === 0 &&
    No climbs found. Use the form below to add new climbs.
    } +
      + {sortedClimbs.map((climb, index) => { + return ( + + ) + })} +
    +
    ) } -const ClimbRow: React.FC = ({ id, name, type: disciplines, index, gradeContext, grades, areaMetadata }) => { +const ClimbRow: React.FC = ({ id, name, type: disciplines, index, gradeContext, grades, areaMetadata, editMode = false }) => { const sanitizedDisciplines = removeTypenameFromDisciplines(disciplines) const gradeStr = new Grade( gradeContext, @@ -35,16 +47,20 @@ const ClimbRow: React.FC - - -
    - + {editMode && + }
  • ) } diff --git a/src/app/editArea/[slug]/general/page.tsx b/src/app/editArea/[slug]/general/page.tsx index d342e4fa4..661b03209 100644 --- a/src/app/editArea/[slug]/general/page.tsx +++ b/src/app/editArea/[slug]/general/page.tsx @@ -1,6 +1,8 @@ import { notFound } from 'next/navigation' import { validate } from 'uuid' import { Metadata } from 'next' +import { FetchPolicy } from '@apollo/client' +import { ArrowCircleRight } from '@phosphor-icons/react/dist/ssr' import { AreaPageDataProps, getArea } from '@/js/graphql/getArea' import { AreaNameForm } from './components/AreaNameForm' @@ -9,7 +11,6 @@ import { AreaLatLngForm } from './components/AreaLatLngForm' import { AddAreaForm } from './components/AddAreaForm' import { AreaListForm } from './components/AreaList' import { AreaTypeForm } from './components/AreaTypeForm' -import { FetchPolicy } from '@apollo/client' import { PageContainer, SectionContainer } from '../components/EditAreaContainers' // Opt out of caching for all data requests in the route segment @@ -38,6 +39,8 @@ export default async function AreaEditPage ({ params }: DashboardPageProps): Pro metadata: { lat, lng, leaf } } = area + const canAddClimbs = leaf && children.length === 0 + return ( @@ -70,6 +73,21 @@ export default async function AreaEditPage ({ params }: DashboardPageProps): Pro areas={children} /> } + + +
    +
    +

    Manage Climbs

    + {canAddClimbs + ? ( + + ) + :
    This area contains subareas. Please add climbs to areas designated as crags or boulders.
    } +
    +
    +
    ) } diff --git a/src/app/editArea/[slug]/addClimbs/components/AddClimbsForm.tsx b/src/app/editArea/[slug]/manageClimbs/components/AddClimbsForm.tsx similarity index 97% rename from src/app/editArea/[slug]/addClimbs/components/AddClimbsForm.tsx rename to src/app/editArea/[slug]/manageClimbs/components/AddClimbsForm.tsx index baa653e3a..40503c8fa 100644 --- a/src/app/editArea/[slug]/addClimbs/components/AddClimbsForm.tsx +++ b/src/app/editArea/[slug]/manageClimbs/components/AddClimbsForm.tsx @@ -48,7 +48,7 @@ export const AddClimbsForm: React.FC<{ parentAreaName: string, parentAreaUuid: s : (
    - This area is either a crag or a boulder. Adding a new child area is not allowed. + This area is either a crag or a boulder. Adding new child areas is not allowed.
    )} diff --git a/src/app/editArea/[slug]/manageClimbs/components/ClimbListMiniToolbar.tsx b/src/app/editArea/[slug]/manageClimbs/components/ClimbListMiniToolbar.tsx new file mode 100644 index 000000000..9573aeb27 --- /dev/null +++ b/src/app/editArea/[slug]/manageClimbs/components/ClimbListMiniToolbar.tsx @@ -0,0 +1,35 @@ +'use client' +import { useSession } from 'next-auth/react' +import { useRouter } from 'next/navigation' +import { Trash } from '@phosphor-icons/react/dist/ssr' +import useUpdateClimbsCmd from '@/js/hooks/useUpdateClimbsCmd' +import Confirmation from '@/components/ui/micro/AlertDialogue' + +export const ClimbListMiniToolbar: React.FC<{ parentAreaId: string, climbId: string, climbName: string }> = ({ parentAreaId, climbId, climbName }) => { + const session = useSession({ required: true }) + const router = useRouter() + const { deleteClimbsCmd } = useUpdateClimbsCmd({ parentId: parentAreaId, accessToken: session.data?.accessToken ?? '' }) + const onConfirm = (): void => { + deleteClimbsCmd([climbId]).then((count) => { + router.refresh() + }).catch((error) => { + console.error(error) + }) + } + return ( +
    + + Delete + + } + onConfirm={onConfirm} + > + You're about to delete climb "{climbName}". This cannot be undone. + +
    + ) +} diff --git a/src/app/editArea/[slug]/addClimbs/components/DisciplinesSelection.tsx b/src/app/editArea/[slug]/manageClimbs/components/DisciplinesSelection.tsx similarity index 100% rename from src/app/editArea/[slug]/addClimbs/components/DisciplinesSelection.tsx rename to src/app/editArea/[slug]/manageClimbs/components/DisciplinesSelection.tsx diff --git a/src/app/editArea/[slug]/addClimbs/components/DynamicClimbInputList.tsx b/src/app/editArea/[slug]/manageClimbs/components/DynamicClimbInputList.tsx similarity index 100% rename from src/app/editArea/[slug]/addClimbs/components/DynamicClimbInputList.tsx rename to src/app/editArea/[slug]/manageClimbs/components/DynamicClimbInputList.tsx diff --git a/src/app/editArea/[slug]/manageClimbs/page.tsx b/src/app/editArea/[slug]/manageClimbs/page.tsx new file mode 100644 index 000000000..089433769 --- /dev/null +++ b/src/app/editArea/[slug]/manageClimbs/page.tsx @@ -0,0 +1,33 @@ +import { Metadata } from 'next' +import { DashboardPageProps, getPageDataForEdit } from '../general/page' +import { PageContainer, SectionContainer } from '../components/EditAreaContainers' +import { AddClimbsForm } from './components/AddClimbsForm' +import { ClimbListSection } from '@/app/area/[[...slug]]/sections/ClimbListSection' + +// Opt out of caching for all data requests in the route segment +export const dynamic = 'force-dynamic' +export const fetchCache = 'force-no-store' // opt out of Nextjs version of 'fetch' + +// Page metadata +export async function generateMetadata ({ params }: DashboardPageProps): Promise { + const { area: { areaName } } = await getPageDataForEdit(params.slug, 'cache-first') + return { + title: `Maging climbs in area ${areaName}` + } +} + +export default async function AddClimbsPage ({ params: { slug } }: DashboardPageProps): Promise { + const { area } = await getPageDataForEdit(slug) + const { areaName, uuid, gradeContext, metadata } = area + const { leaf, isBoulder } = metadata + return ( + + + + + + + + + ) +} diff --git a/src/js/hooks/useUpdateClimbsCmd.tsx b/src/js/hooks/useUpdateClimbsCmd.tsx index a0acfa32b..56acfcf58 100644 --- a/src/js/hooks/useUpdateClimbsCmd.tsx +++ b/src/js/hooks/useUpdateClimbsCmd.tsx @@ -87,7 +87,7 @@ export default function useUpdateClimbsCmd ({ parentId, accessToken = '', onUpda MUTATION_DELETE_CLIMBS, { client: graphqlClient, onCompleted: (data) => { - void refreshPage(`/api/revalidate?s=${parentId}`) + void updateAreaPageCache(parentId) toast('Climbs deleted ✔️') if (onDeleteCompleted != null) { onDeleteCompleted(data)