Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { notFound } from 'next/navigation';
import { BoardRouteParameters } from '@/app/lib/types';
import { getBoardDetails } from '@/app/lib/__generated__/product-sizes-data';
import { parseBoardRouteParams } from '@/app/lib/url-utils';
Expand Down Expand Up @@ -37,49 +38,54 @@ function getMoonBoardHoldSetImages(layoutKey: MoonBoardLayoutKey, setIds: number
}

export default async function CreateClimbPage(props: CreateClimbPageProps) {
const [params, searchParams] = await Promise.all([props.params, props.searchParams]);
try {
const [params, searchParams] = await Promise.all([props.params, props.searchParams]);

// Check if any parameters are in numeric format (old URLs)
const hasNumericParams = [params.layout_id, params.size_id, params.set_ids].some((param) =>
param.includes(',') ? param.split(',').every((id) => /^\d+$/.test(id.trim())) : /^\d+$/.test(param),
);
// Check if any parameters are in numeric format (old URLs)
const hasNumericParams = [params.layout_id, params.size_id, params.set_ids].some((param) =>
param.includes(',') ? param.split(',').every((id) => /^\d+$/.test(id.trim())) : /^\d+$/.test(param),
);

let parsedParams;
let parsedParams;

if (hasNumericParams) {
parsedParams = parseBoardRouteParams(params);
} else {
parsedParams = await parseBoardRouteParamsWithSlugs(params);
}
if (hasNumericParams) {
parsedParams = parseBoardRouteParams(params);
} else {
parsedParams = await parseBoardRouteParamsWithSlugs(params);
}

// Handle MoonBoard separately (no database, different renderer)
if (parsedParams.board_name === 'moonboard') {
const layoutInfo = getMoonBoardLayoutInfo(parsedParams.layout_id);
if (!layoutInfo) {
return <div>Invalid MoonBoard layout</div>;
}

// Handle MoonBoard separately (no database, different renderer)
if (parsedParams.board_name === 'moonboard') {
const layoutInfo = getMoonBoardLayoutInfo(parsedParams.layout_id);
if (!layoutInfo) {
return <div>Invalid MoonBoard layout</div>;
const holdSetImages = getMoonBoardHoldSetImages(layoutInfo.layoutKey, parsedParams.set_ids);

return (
<MoonBoardCreateClimbForm
layoutFolder={layoutInfo.folder}
layoutName={layoutInfo.name}
holdSetImages={holdSetImages}
angle={parsedParams.angle}
/>
);
}

const holdSetImages = getMoonBoardHoldSetImages(layoutInfo.layoutKey, parsedParams.set_ids);
// Aurora boards (kilter, tension) - use database
const boardDetails = await getBoardDetails(parsedParams);

return (
<MoonBoardCreateClimbForm
layoutFolder={layoutInfo.folder}
layoutName={layoutInfo.name}
holdSetImages={holdSetImages}
<CreateClimbForm
boardDetails={boardDetails}
angle={parsedParams.angle}
forkFrames={searchParams.forkFrames}
forkName={searchParams.forkName}
/>
);
} catch (error) {
console.error('Error in create page:', error);
notFound();
}

// Aurora boards (kilter, tension) - use database
const boardDetails = await getBoardDetails(parsedParams);

return (
<CreateClimbForm
boardDetails={boardDetails}
angle={parsedParams.angle}
forkFrames={searchParams.forkFrames}
forkName={searchParams.forkName}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
MoonBoardLayoutKey,
} from '@/app/lib/moonboard-config';
import { Metadata } from 'next';
import { redirect } from 'next/navigation';
import { notFound, redirect } from 'next/navigation';

export const metadata: Metadata = {
title: 'Import Climbs | Boardsesh',
Expand All @@ -35,40 +35,45 @@ function getMoonBoardHoldSetImages(layoutKey: MoonBoardLayoutKey, setIds: number
}

export default async function ImportPage(props: ImportPageProps) {
const params = await props.params;
try {
const params = await props.params;

// Check if any parameters are in numeric format (old URLs)
const hasNumericParams = [params.layout_id, params.size_id, params.set_ids].some((param) =>
param.includes(',') ? param.split(',').every((id) => /^\d+$/.test(id.trim())) : /^\d+$/.test(param),
);
// Check if any parameters are in numeric format (old URLs)
const hasNumericParams = [params.layout_id, params.size_id, params.set_ids].some((param) =>
param.includes(',') ? param.split(',').every((id) => /^\d+$/.test(id.trim())) : /^\d+$/.test(param),
);

let parsedParams;
let parsedParams;

if (hasNumericParams) {
parsedParams = parseBoardRouteParams(params);
} else {
parsedParams = await parseBoardRouteParamsWithSlugs(params);
}
if (hasNumericParams) {
parsedParams = parseBoardRouteParams(params);
} else {
parsedParams = await parseBoardRouteParamsWithSlugs(params);
}

// Only MoonBoard supports bulk import for now
if (parsedParams.board_name !== 'moonboard') {
// Redirect to the board's climb list page
redirect(`/${params.board_name}/${params.layout_id}/${params.size_id}/${params.set_ids}/${params.angle}`);
}
// Only MoonBoard supports bulk import for now
if (parsedParams.board_name !== 'moonboard') {
// Redirect to the board's climb list page
redirect(`/${params.board_name}/${params.layout_id}/${params.size_id}/${params.set_ids}/${params.angle}`);
}

const layoutInfo = getMoonBoardLayoutInfo(parsedParams.layout_id);
if (!layoutInfo) {
return <div>Invalid MoonBoard layout</div>;
}
const layoutInfo = getMoonBoardLayoutInfo(parsedParams.layout_id);
if (!layoutInfo) {
return <div>Invalid MoonBoard layout</div>;
}

const holdSetImages = getMoonBoardHoldSetImages(layoutInfo.layoutKey, parsedParams.set_ids);
const holdSetImages = getMoonBoardHoldSetImages(layoutInfo.layoutKey, parsedParams.set_ids);

return (
<MoonBoardBulkImport
layoutFolder={layoutInfo.folder}
layoutName={layoutInfo.name}
holdSetImages={holdSetImages}
angle={parsedParams.angle}
/>
);
return (
<MoonBoardBulkImport
layoutFolder={layoutInfo.folder}
layoutName={layoutInfo.name}
holdSetImages={holdSetImages}
angle={parsedParams.angle}
/>
);
} catch (error) {
console.error('Error in import page:', error);
notFound();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Affix, Layout } from 'antd';
import { ParsedBoardRouteParameters, BoardRouteParameters, BoardDetails } from '@/app/lib/types';
import { parseBoardRouteParams, constructClimbListWithSlugs } from '@/app/lib/url-utils';
import { parseBoardRouteParamsWithSlugs } from '@/app/lib/url-utils.server';
import { permanentRedirect } from 'next/navigation';
import { notFound, permanentRedirect } from 'next/navigation';
import { Content } from 'antd/es/layout/layout';
import QueueControlBar from '@/app/components/queue-control/queue-control-bar';
import { getBoardDetails } from '@/app/lib/__generated__/product-sizes-data';
Expand Down Expand Up @@ -103,80 +103,85 @@ interface BoardLayoutProps {
}

export default async function BoardLayout(props: PropsWithChildren<BoardLayoutProps>) {
const params = await props.params;
try {
const params = await props.params;

const { children } = props;

// Parse the route parameters
// Check if any parameters are in numeric format (old URLs)
const hasNumericParams = [params.layout_id, params.size_id, params.set_ids].some((param) =>
param.includes(',') ? param.split(',').every((id) => /^\d+$/.test(id.trim())) : /^\d+$/.test(param),
);

const { children } = props;
let parsedParams: ParsedBoardRouteParameters;

// Parse the route parameters
// Check if any parameters are in numeric format (old URLs)
const hasNumericParams = [params.layout_id, params.size_id, params.set_ids].some((param) =>
param.includes(',') ? param.split(',').every((id) => /^\d+$/.test(id.trim())) : /^\d+$/.test(param),
);
if (hasNumericParams) {
// For old URLs, use the simple parsing function first
parsedParams = parseBoardRouteParams(params);

let parsedParams: ParsedBoardRouteParameters;
// Redirect old URLs to new slug format
const boardDetails = getBoardDetailsUniversal(parsedParams);

if (boardDetails.layout_name && boardDetails.size_name && boardDetails.set_names) {
const newUrl = constructClimbListWithSlugs(
boardDetails.board_name,
boardDetails.layout_name,
boardDetails.size_name,
boardDetails.size_description,
boardDetails.set_names,
parsedParams.angle,
);

permanentRedirect(newUrl);
}
} else {
// For new URLs, use the slug parsing function
parsedParams = await parseBoardRouteParamsWithSlugs(params);
}

if (hasNumericParams) {
// For old URLs, use the simple parsing function first
parsedParams = parseBoardRouteParams(params);
const { board_name, angle } = parsedParams;

// Redirect old URLs to new slug format
// Fetch the board details server-side
const boardDetails = getBoardDetailsUniversal(parsedParams);

if (boardDetails.layout_name && boardDetails.size_name && boardDetails.set_names) {
const newUrl = constructClimbListWithSlugs(
boardDetails.board_name,
boardDetails.layout_name,
boardDetails.size_name,
boardDetails.size_description,
boardDetails.set_names,
parsedParams.angle,
);

permanentRedirect(newUrl);
}
} else {
// For new URLs, use the slug parsing function
parsedParams = await parseBoardRouteParamsWithSlugs(params);
return (
<Layout style={{ height: '100dvh', display: 'flex', flexDirection: 'column', padding: 0 }}>
<BoardSessionBridge boardDetails={boardDetails} parsedParams={parsedParams}>
<ConnectionSettingsProvider>
<GraphQLQueueProvider parsedParams={parsedParams} boardDetails={boardDetails}>
<PartyProvider>
<BoardSeshHeader boardDetails={boardDetails} angle={angle} />

<Content
id="content-for-scrollable"
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
overflowY: 'auto',
overflowX: 'hidden',
height: '80vh',
paddingLeft: '10px',
paddingRight: '10px',
}}
>
<Suspense fallback={<BoardPageSkeleton aspectRatio={boardDetails.boardWidth / boardDetails.boardHeight} />}>
{children}
</Suspense>
</Content>

<Affix offsetBottom={0}>
<QueueControlBar board={board_name} boardDetails={boardDetails} angle={angle} />
</Affix>
</PartyProvider>
</GraphQLQueueProvider>
</ConnectionSettingsProvider>
</BoardSessionBridge>
</Layout>
);
} catch (error) {
console.error('Error in board layout:', error);
notFound();
}

const { board_name, angle } = parsedParams;

// Fetch the board details server-side
const boardDetails = getBoardDetailsUniversal(parsedParams);

return (
<Layout style={{ height: '100dvh', display: 'flex', flexDirection: 'column', padding: 0 }}>
<BoardSessionBridge boardDetails={boardDetails} parsedParams={parsedParams}>
<ConnectionSettingsProvider>
<GraphQLQueueProvider parsedParams={parsedParams} boardDetails={boardDetails}>
<PartyProvider>
<BoardSeshHeader boardDetails={boardDetails} angle={angle} />

<Content
id="content-for-scrollable"
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
overflowY: 'auto',
overflowX: 'hidden',
height: '80vh',
paddingLeft: '10px',
paddingRight: '10px',
}}
>
<Suspense fallback={<BoardPageSkeleton aspectRatio={boardDetails.boardWidth / boardDetails.boardHeight} />}>
{children}
</Suspense>
</Content>

<Affix offsetBottom={0}>
<QueueControlBar board={board_name} boardDetails={boardDetails} angle={angle} />
</Affix>
</PartyProvider>
</GraphQLQueueProvider>
</ConnectionSettingsProvider>
</BoardSessionBridge>
</Layout>
);
}
Loading
Loading