Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
8 changes: 2 additions & 6 deletions app/components/board-page/back-to-climb-list-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@ import { useQueueContext } from '../queue-control/queue-context';
import { searchParamsToUrlParams, constructClimbListWithSlugs } from '@/app/lib/url-utils';

const BackToClimbList = ({
board_name,
layout_id,
size_id,
set_ids,
angle,
climb_uuid,
boardDetails,
}: ParsedBoardRouteParametersWithUuid & { boardDetails?: BoardDetails }) => {
}: Pick<ParsedBoardRouteParametersWithUuid, 'angle' | 'climb_uuid'> & { boardDetails?: BoardDetails }) => {
const { climbSearchParams } = useQueueContext();

const climbListUrl =
Expand All @@ -27,7 +23,7 @@ const BackToClimbList = ({
boardDetails.set_names,
angle,
)
: `/${board_name}/${layout_id}/${size_id}/${set_ids}/${angle}/list`;
: (() => { throw new Error('Board details are missing required slug information'); })();

return (
<Link href={`${climbListUrl}?${searchParamsToUrlParams(climbSearchParams).toString()}#${climb_uuid}`}>
Expand Down
4 changes: 2 additions & 2 deletions app/components/climb-view/climb-view-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ const ClimbViewActions = ({ climb, boardDetails, auroraAppUrl, angle }: ClimbVie
return constructClimbListWithSlugs(board_name, layout_name, size_name, set_names, angle);
}

// Fallback to numeric format
return `/${board_name}/${boardDetails.layout_id}/${boardDetails.size_id}/${boardDetails.set_ids.join(',')}/${angle}/list`;
// This should not happen as boardDetails should always have the necessary fields
throw new Error('Board details are missing required slug information');
};

// Define menu items for the meatball menu (overflow actions on mobile)
Expand Down
5 changes: 2 additions & 3 deletions app/components/queue-control/next-climb-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ const NextButton = (props: ButtonProps) => (

export default function NextClimbButton({ navigate = false, boardDetails }: NextClimbButtonProps) {
const { setCurrentClimbQueueItem, getNextClimbQueueItem, viewOnlyMode } = useQueueContext(); // Assuming setSuggestedQueue is available
const { board_name, layout_id, size_id, set_ids, angle } =
parseBoardRouteParams(useParams<BoardRouteParametersWithUuid>());
const { angle } = parseBoardRouteParams(useParams<BoardRouteParametersWithUuid>());

const nextClimb = getNextClimbQueueItem();

Expand All @@ -47,7 +46,7 @@ export default function NextClimbButton({ navigate = false, boardDetails }: Next
nextClimb.climb.uuid,
nextClimb.climb.name,
)
: `/${board_name}/${layout_id}/${size_id}/${set_ids}/${angle}/view/${nextClimb.climb.uuid}`;
: (() => { throw new Error('Board details are missing required slug information'); })();

return (
<Link
Expand Down
5 changes: 2 additions & 3 deletions app/components/queue-control/previous-climb-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ const PreviousButton = (props: ButtonProps) => (

export default function PreviousClimbButton({ navigate = false, boardDetails }: PreviousClimbButtonProps) {
const { getPreviousClimbQueueItem, setCurrentClimbQueueItem, viewOnlyMode } = useQueueContext();
const { board_name, layout_id, size_id, set_ids, angle } =
parseBoardRouteParams(useParams<BoardRouteParametersWithUuid>());
const { angle } = parseBoardRouteParams(useParams<BoardRouteParametersWithUuid>());

const previousClimb = getPreviousClimbQueueItem();

Expand All @@ -48,7 +47,7 @@ export default function PreviousClimbButton({ navigate = false, boardDetails }:
previousClimb.climb.uuid,
previousClimb.climb.name,
)
: `/${board_name}/${layout_id}/${size_id}/${set_ids}/${angle}/view/${previousClimb.climb.uuid}`;
: (() => { throw new Error('Board details are missing required slug information'); })();

return (
<Link
Expand Down
16 changes: 6 additions & 10 deletions app/components/setup-wizard/board-config-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,20 @@ export default function BoardConfigPreview({ config, onDelete, boardConfigs }: B
savedAngle,
);
} else {
// Fallback to old URL format
const setsString = config.setIds.join(',');
url = `/${config.board}/${config.layoutId}/${config.sizeId}/${setsString}/${savedAngle}/list`;
// This should not happen as boardDetails should always have the necessary fields
throw new Error('Board details are missing required slug information');
}
} catch (error) {
console.error('Error generating board URL:', error);
// Fallback to old URL format
const setsString = config.setIds.join(',');
url = `/${config.board}/${config.layoutId}/${config.sizeId}/${setsString}/${savedAngle}/list`;
// Re-throw error instead of falling back to old URL format
throw error;
}

setBoardUrl(url);
} catch (error) {
console.error('Failed to load board details for preview:', error);
// Set fallback URL even if loading fails
const setsString = config.setIds.join(',');
const savedAngle = config.angle || 40;
setBoardUrl(`/${config.board}/${config.layoutId}/${config.sizeId}/${setsString}/${savedAngle}/list`);
// Re-throw error instead of falling back to old URL format
throw error;
} finally {
setIsLoading(false);
}
Expand Down
22 changes: 8 additions & 14 deletions app/components/setup-wizard/consolidated-board-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ const ConsolidatedBoardConfig = ({ boardConfigs }: ConsolidatedBoardConfigProps)
setUseAsDefault(defaultConfig.useAsDefault);

// Redirect immediately if there's a default
const setsString = defaultConfig.setIds.join(',');
const savedAngle = defaultConfig.angle || 40;

try {
Expand All @@ -196,17 +195,13 @@ const ConsolidatedBoardConfig = ({ boardConfigs }: ConsolidatedBoardConfigProps)
);
router.push(slugUrl);
} else {
// Fallback to old URL format
router.push(
`/${defaultConfig.board}/${defaultConfig.layoutId}/${defaultConfig.sizeId}/${setsString}/${savedAngle}/list`,
);
// This should not happen as boardDetails should always have the necessary fields
throw new Error('Board details are missing required slug information for default config');
}
} catch (error) {
console.error('Error fetching board details for slug URL:', error);
// Fallback to old URL format
router.push(
`/${defaultConfig.board}/${defaultConfig.layoutId}/${defaultConfig.sizeId}/${setsString}/${savedAngle}/list`,
);
// Re-throw error instead of falling back to old URL format
throw error;
}
}
};
Expand Down Expand Up @@ -357,7 +352,6 @@ const ConsolidatedBoardConfig = ({ boardConfigs }: ConsolidatedBoardConfigProps)
const updatedConfigs = await loadAllConfigurations();
setSavedConfigurations(updatedConfigs);

const setsString = selectedSets.join(',');

try {
// Try to get board details for slug-based URL
Expand All @@ -373,13 +367,13 @@ const ConsolidatedBoardConfig = ({ boardConfigs }: ConsolidatedBoardConfigProps)
);
router.push(slugUrl);
} else {
// Fallback to old URL format
router.push(`/${selectedBoard}/${selectedLayout}/${selectedSize}/${setsString}/${selectedAngle}/list`);
// This should not happen as boardDetails should always have the necessary fields
throw new Error('Board details are missing required slug information');
}
} catch (error) {
console.error('Error fetching board details for slug URL:', error);
// Fallback to old URL format
router.push(`/${selectedBoard}/${selectedLayout}/${selectedSize}/${setsString}/${selectedAngle}/list`);
// Re-throw error instead of falling back to old URL format
throw error;
}
} catch (error) {
console.error('Error starting climbing session:', error);
Expand Down
9 changes: 4 additions & 5 deletions app/components/setup-wizard/start-climbing-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,13 @@ export default function StartClimbingButton({
selectedAngle,
);
} else {
// Fallback to old URL format
return `/${selectedBoard}/${selectedLayout}/${selectedSize}/${setsString}/${selectedAngle}/list`;
// This should not happen as boardDetails should always have the necessary fields
throw new Error('Board details are missing required slug information');
}
} catch (error) {
console.error('Error generating climbing URL:', error);
// Fallback to old URL format
const setsString = selectedSets.join(',');
return `/${selectedBoard}/${selectedLayout}/${selectedSize}/${setsString}/${selectedAngle}/list`;
// Re-throw error instead of falling back to old URL format
throw error;
} finally {
setIsGeneratingUrl(false);
}
Expand Down
9 changes: 6 additions & 3 deletions app/lib/data/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,12 @@ function getImageUrlHoldsMapObjectEntries(
export type LayoutRow = {
id: number;
name: string;
slug: string;
};

export const getLayouts = async (board_name: BoardName) => {
const layouts = await sql`
SELECT id, name
SELECT id, name, slug
FROM ${sql.unsafe(getTableName(board_name, 'layouts'))} layouts
WHERE is_listed = true
AND password IS NULL
Expand All @@ -234,11 +235,12 @@ export type SizeRow = {
id: number;
name: string;
description: string;
slug: string;
};

export const getSizes = async (board_name: BoardName, layout_id: LayoutId) => {
const layouts = await sql`
SELECT product_sizes.id, product_sizes.name, product_sizes.description
SELECT product_sizes.id, product_sizes.name, product_sizes.description, product_sizes.slug
FROM ${sql.unsafe(getTableName(board_name, 'product_sizes'))} product_sizes
INNER JOIN ${sql.unsafe(getTableName(board_name, 'layouts'))} layouts ON product_sizes.product_id = layouts.product_id
WHERE layouts.id = ${layout_id}
Expand All @@ -249,11 +251,12 @@ export const getSizes = async (board_name: BoardName, layout_id: LayoutId) => {
export type SetRow = {
id: number;
name: string;
slug: string;
};

export const getSets = async (board_name: BoardName, layout_id: LayoutId, size_id: Size) => {
const layouts = await sql`
SELECT sets.id, sets.name
SELECT sets.id, sets.name, sets.slug
FROM ${sql.unsafe(getTableName(board_name, 'sets'))} sets
INNER JOIN ${sql.unsafe(getTableName(board_name, 'product_sizes_layouts_sets'))} psls
ON sets.id = psls.set_id
Expand Down
52 changes: 38 additions & 14 deletions app/lib/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,25 @@ export const kilterLayouts = pgTable(
id: integer().primaryKey().notNull(),
productId: integer('product_id'),
name: text(),
slug: text(),
instagramCaption: text('instagram_caption'),
isMirrored: boolean('is_mirrored'),
isListed: boolean('is_listed'),
password: text(),
createdAt: text('created_at'),
},
(table) => [
foreignKey({
(table) => ({
// Indexes
slugIdx: index('kilter_layouts_slug_idx').on(table.slug),
// Foreign Keys
productFk: foreignKey({
columns: [table.productId],
foreignColumns: [kilterProducts.id],
name: 'layouts_product_id_fkey1',
})
.onUpdate('cascade')
.onDelete('cascade'),
],
}),
);

export const kilterAndroidMetadata = pgTable('kilter_android_metadata', {
Expand Down Expand Up @@ -203,20 +207,24 @@ export const kilterProductSizes = pgTable(
edgeBottom: integer('edge_bottom'),
edgeTop: integer('edge_top'),
name: text(),
slug: text(),
description: text(),
imageFilename: text('image_filename'),
position: integer(),
isListed: boolean('is_listed'),
},
(table) => [
foreignKey({
(table) => ({
// Indexes
slugIdx: index('kilter_product_sizes_slug_idx').on(table.slug),
// Foreign Keys
productFk: foreignKey({
columns: [table.productId],
foreignColumns: [kilterProducts.id],
name: 'product_sizes_product_id_fkey1',
})
.onUpdate('cascade')
.onDelete('cascade'),
],
}),
);

export const kilterKits = pgTable('kilter_kits', {
Expand Down Expand Up @@ -452,8 +460,12 @@ export const kilterProducts = pgTable('kilter_products', {
export const kilterSets = pgTable('kilter_sets', {
id: integer().primaryKey().notNull(),
name: text(),
slug: text(),
hsm: integer(),
});
}, (table) => ({
// Indexes
slugIdx: index('kilter_sets_slug_idx').on(table.slug),
}));

export const kilterWalls = pgTable(
'kilter_walls',
Expand Down Expand Up @@ -679,8 +691,12 @@ export const tensionClimbHolds = pgTable(
export const tensionSets = pgTable('tension_sets', {
id: integer().primaryKey().notNull(),
name: text(),
slug: text(),
hsm: integer(),
});
}, (table) => ({
// Indexes
slugIdx: index('tension_sets_slug_idx').on(table.slug),
}));

export const tensionPlacements = pgTable(
'tension_placements',
Expand Down Expand Up @@ -777,21 +793,25 @@ export const tensionLayouts = pgTable(
id: integer().primaryKey().notNull(),
productId: integer('product_id'),
name: text(),
slug: text(),
instagramCaption: text('instagram_caption'),
isMirrored: boolean('is_mirrored'),
isListed: boolean('is_listed'),
password: text(),
createdAt: text('created_at'),
},
(table) => [
foreignKey({
(table) => ({
// Indexes
slugIdx: index('tension_layouts_slug_idx').on(table.slug),
// Foreign Keys
productFk: foreignKey({
columns: [table.productId],
foreignColumns: [tensionProducts.id],
name: 'layouts_product_id_fkey',
})
.onUpdate('cascade')
.onDelete('cascade'),
],
}),
);

export const tensionSharedSyncs = pgTable('tension_shared_syncs', {
Expand Down Expand Up @@ -844,20 +864,24 @@ export const tensionProductSizes = pgTable(
edgeBottom: integer('edge_bottom'),
edgeTop: integer('edge_top'),
name: text(),
slug: text(),
description: text(),
imageFilename: text('image_filename'),
position: integer(),
isListed: boolean('is_listed'),
},
(table) => [
foreignKey({
(table) => ({
// Indexes
slugIdx: index('tension_product_sizes_slug_idx').on(table.slug),
// Foreign Keys
productFk: foreignKey({
columns: [table.productId],
foreignColumns: [tensionProducts.id],
name: 'product_sizes_product_id_fkey',
})
.onUpdate('cascade')
.onDelete('cascade'),
],
}),
);

export const kilterAscents = pgTable(
Expand Down
Loading