fix: resolve all 1008 svelte-check type errors across codebase
CI / update (push) Successful in 1m54s
CI / update (push) Successful in 1m54s
Add type annotations, JSDoc types, null checks, and proper generics to eliminate all svelte-check errors. Key changes include: - Type $state(null) variables to avoid 'never' inference - Add JSDoc typedefs for plain <script> components - Fix mongoose model typing with Model<any> to avoid union complexity - Add App.Error/App.PageState interfaces in app.d.ts - Fix tuple types to array types in types.ts - Type catch block errors and API handler params - Add null safety for DOM queries and optional chaining - Add standard line-clamp property alongside -webkit- prefix
This commit is contained in:
@@ -23,7 +23,7 @@ export const POST: RequestHandler = async ({request, cookies, locals}) => {
|
||||
// Invalidate recipe caches after successful creation
|
||||
await invalidateRecipeCaches();
|
||||
} catch(e){
|
||||
throw error(400, e)
|
||||
throw error(400, e instanceof Error ? e.message : String(e))
|
||||
}
|
||||
return new Response(JSON.stringify({msg: "Added recipe successfully"}),{
|
||||
status: 200,
|
||||
|
||||
@@ -34,7 +34,7 @@ export const POST: RequestHandler = async ({request, locals}) => {
|
||||
for (const depRecipe of referencingRecipes) {
|
||||
// Expand ingredient references
|
||||
if (depRecipe.ingredients) {
|
||||
depRecipe.ingredients = depRecipe.ingredients.flatMap((item: any) => {
|
||||
(depRecipe as any).ingredients = depRecipe.ingredients.flatMap((item: any) => {
|
||||
if (item.type === 'reference' && item.baseRecipeRef && item.baseRecipeRef.equals(recipe._id)) {
|
||||
if (item.includeIngredients && recipe.ingredients) {
|
||||
return recipe.ingredients.filter((i: any) => i.type === 'section' || !i.type);
|
||||
@@ -47,7 +47,7 @@ export const POST: RequestHandler = async ({request, locals}) => {
|
||||
|
||||
// Expand instruction references
|
||||
if (depRecipe.instructions) {
|
||||
depRecipe.instructions = depRecipe.instructions.flatMap((item: any) => {
|
||||
(depRecipe as any).instructions = depRecipe.instructions.flatMap((item: any) => {
|
||||
if (item.type === 'reference' && item.baseRecipeRef && item.baseRecipeRef.equals(recipe._id)) {
|
||||
if (item.includeInstructions && recipe.instructions) {
|
||||
return recipe.instructions.filter((i: any) => i.type === 'section' || !i.type);
|
||||
|
||||
@@ -24,31 +24,33 @@ export const GET: RequestHandler = async ({ params, locals }) => {
|
||||
return json([]);
|
||||
}
|
||||
|
||||
const { approvalFilter } = briefQueryConfig(params.recipeLang);
|
||||
const en = isEnglish(params.recipeLang);
|
||||
const { approvalFilter } = briefQueryConfig(params.recipeLang!);
|
||||
const en = isEnglish(params.recipeLang!);
|
||||
|
||||
let recipes = await Recipe.find({
|
||||
_id: { $in: userFavorites.favorites },
|
||||
...approvalFilter
|
||||
}).lean() as RecipeModelType[];
|
||||
}).lean() as unknown as RecipeModelType[];
|
||||
|
||||
if (en) {
|
||||
const englishRecipes = recipes.map(recipe => ({
|
||||
const englishRecipes = recipes.map(recipe => {
|
||||
const t = recipe.translations?.en;
|
||||
return {
|
||||
_id: recipe._id,
|
||||
short_name: recipe.translations.en.short_name,
|
||||
name: recipe.translations.en.name,
|
||||
category: recipe.translations.en.category,
|
||||
short_name: t?.short_name,
|
||||
name: t?.name,
|
||||
category: t?.category,
|
||||
icon: recipe.icon,
|
||||
dateCreated: recipe.dateCreated,
|
||||
dateModified: recipe.dateModified,
|
||||
images: recipe.images?.map((img, idx) => ({
|
||||
mediapath: img.mediapath,
|
||||
alt: recipe.translations.en.images?.[idx]?.alt || img.alt,
|
||||
caption: recipe.translations.en.images?.[idx]?.caption || img.caption,
|
||||
alt: t?.images?.[idx]?.alt || img.alt,
|
||||
caption: t?.images?.[idx]?.caption || img.caption,
|
||||
})),
|
||||
description: recipe.translations.en.description,
|
||||
note: recipe.translations.en.note,
|
||||
tags: recipe.translations.en.tags || [],
|
||||
description: t?.description,
|
||||
note: t?.note,
|
||||
tags: t?.tags || [],
|
||||
season: recipe.season,
|
||||
baking: recipe.baking,
|
||||
preparation: recipe.preparation,
|
||||
@@ -56,13 +58,13 @@ export const GET: RequestHandler = async ({ params, locals }) => {
|
||||
portions: recipe.portions,
|
||||
cooking: recipe.cooking,
|
||||
total_time: recipe.total_time,
|
||||
ingredients: recipe.translations.en.ingredients || [],
|
||||
instructions: recipe.translations.en.instructions || [],
|
||||
preamble: recipe.translations.en.preamble,
|
||||
addendum: recipe.translations.en.addendum,
|
||||
ingredients: t?.ingredients || [],
|
||||
instructions: t?.instructions || [],
|
||||
preamble: t?.preamble,
|
||||
addendum: t?.addendum,
|
||||
germanShortName: recipe.short_name,
|
||||
translationStatus: recipe.translations.en.translationStatus
|
||||
}));
|
||||
translationStatus: t?.translationStatus
|
||||
}});
|
||||
return json(JSON.parse(JSON.stringify(englishRecipes)));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ function mapBaseRecipeRefs(items: any[]): any[] {
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
await dbConnect();
|
||||
const en = isEnglish(params.recipeLang);
|
||||
const en = isEnglish(params.recipeLang!);
|
||||
|
||||
const query = en
|
||||
? { 'translations.en.short_name': params.name }
|
||||
@@ -84,7 +84,7 @@ export const GET: RequestHandler = async ({ params }) => {
|
||||
}
|
||||
];
|
||||
|
||||
let dbQuery = Recipe.findOne(query);
|
||||
let dbQuery: any = Recipe.findOne(query);
|
||||
for (const p of populatePaths) {
|
||||
dbQuery = dbQuery.populate(p);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import cache from '$lib/server/cache';
|
||||
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang);
|
||||
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang!);
|
||||
const cacheKey = `recipes:${params.recipeLang}:all_brief`;
|
||||
|
||||
let recipes: BriefRecipeType[] | null = null;
|
||||
@@ -17,10 +17,10 @@ export const GET: RequestHandler = async ({ params }) => {
|
||||
recipes = JSON.parse(cached);
|
||||
} else {
|
||||
await dbConnect();
|
||||
const dbRecipes = await Recipe.find(approvalFilter, projection).lean();
|
||||
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang));
|
||||
const dbRecipes: any[] = await Recipe.find(approvalFilter, projection).lean();
|
||||
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang!));
|
||||
await cache.set(cacheKey, JSON.stringify(recipes), 3600);
|
||||
}
|
||||
|
||||
return json(JSON.parse(JSON.stringify(rand_array(recipes))));
|
||||
return json(JSON.parse(JSON.stringify(rand_array(recipes!))));
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import { dbConnect } from '$utils/db';
|
||||
import { isEnglish, briefQueryConfig } from '$lib/server/recipeHelpers';
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const { approvalFilter, prefix } = briefQueryConfig(params.recipeLang);
|
||||
const { approvalFilter, prefix } = briefQueryConfig(params.recipeLang!);
|
||||
await dbConnect();
|
||||
|
||||
const field = `${prefix}category`;
|
||||
|
||||
@@ -5,14 +5,14 @@ import { rand_array } from '$lib/js/randomize';
|
||||
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang);
|
||||
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang!);
|
||||
await dbConnect();
|
||||
|
||||
const dbRecipes = await Recipe.find(
|
||||
const dbRecipes: any[] = await Recipe.find(
|
||||
{ [`${prefix}category`]: params.category, ...approvalFilter },
|
||||
projection
|
||||
).lean();
|
||||
|
||||
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang)));
|
||||
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang!)));
|
||||
return json(JSON.parse(JSON.stringify(recipes)));
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import { rand_array } from '$lib/js/randomize';
|
||||
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang);
|
||||
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang!);
|
||||
await dbConnect();
|
||||
|
||||
const dbRecipes = await Recipe.find(
|
||||
@@ -13,6 +13,6 @@ export const GET: RequestHandler = async ({ params }) => {
|
||||
projection
|
||||
).lean();
|
||||
|
||||
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang)));
|
||||
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang!)));
|
||||
return json(JSON.parse(JSON.stringify(recipes)));
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import cache from '$lib/server/cache';
|
||||
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang);
|
||||
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang!);
|
||||
const cacheKey = `recipes:${params.recipeLang}:in_season:${params.month}`;
|
||||
|
||||
let recipes = null;
|
||||
@@ -20,7 +20,7 @@ export const GET: RequestHandler = async ({ params }) => {
|
||||
{ season: params.month, icon: { $ne: "🍽️" }, ...approvalFilter },
|
||||
projection
|
||||
).lean();
|
||||
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang));
|
||||
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang!));
|
||||
await cache.set(cacheKey, JSON.stringify(recipes), 3600);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import { dbConnect } from '$utils/db';
|
||||
import { isEnglish, briefQueryConfig } from '$lib/server/recipeHelpers';
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const { approvalFilter } = briefQueryConfig(params.recipeLang);
|
||||
const { approvalFilter } = briefQueryConfig(params.recipeLang!);
|
||||
await dbConnect();
|
||||
|
||||
if (isEnglish(params.recipeLang)) {
|
||||
if (isEnglish(params.recipeLang!)) {
|
||||
const recipes = await Recipe.find(approvalFilter, 'translations.en.tags').lean();
|
||||
const tagsSet = new Set<string>();
|
||||
recipes.forEach(recipe => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import cache from '$lib/server/cache';
|
||||
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
|
||||
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang);
|
||||
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang!);
|
||||
const cacheKey = `recipes:${params.recipeLang}:tag:${params.tag}`;
|
||||
|
||||
let recipes = null;
|
||||
@@ -20,7 +20,7 @@ export const GET: RequestHandler = async ({ params }) => {
|
||||
{ [`${prefix}tags`]: params.tag, ...approvalFilter },
|
||||
projection
|
||||
).lean();
|
||||
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang));
|
||||
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang!));
|
||||
await cache.set(cacheKey, JSON.stringify(recipes), 3600);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { error } from '@sveltejs/kit';
|
||||
|
||||
export const GET: RequestHandler = async ({ params, setHeaders }) => {
|
||||
await dbConnect();
|
||||
let recipe = (await Recipe.findOne({ short_name: params.name }).lean()) as RecipeModelType;
|
||||
let recipe = (await Recipe.findOne({ short_name: params.name }).lean()) as unknown as RecipeModelType;
|
||||
|
||||
recipe = JSON.parse(JSON.stringify(recipe));
|
||||
if (recipe == null) {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const GET: RequestHandler = async () => {
|
||||
const briefRecipes = await Recipe.find(
|
||||
{},
|
||||
'name short_name tags category icon description season dateModified images translations'
|
||||
).lean() as BriefRecipeType[];
|
||||
).lean() as unknown as BriefRecipeType[];
|
||||
|
||||
// Fetch full recipes with populated base recipe references
|
||||
const fullRecipes = await Recipe.find({})
|
||||
@@ -39,7 +39,7 @@ export const GET: RequestHandler = async () => {
|
||||
}
|
||||
}
|
||||
})
|
||||
.lean() as RecipeModelType[];
|
||||
.lean() as unknown as RecipeModelType[];
|
||||
|
||||
// Map populated refs to resolvedRecipe field (same as individual item endpoint)
|
||||
function mapBaseRecipeRefs(items: any[]): any[] {
|
||||
|
||||
@@ -7,8 +7,8 @@ import { isEnglish, briefQueryConfig, toBrief } from '$lib/server/recipeHelpers'
|
||||
export const GET: RequestHandler = async ({ url, params, locals }) => {
|
||||
await dbConnect();
|
||||
|
||||
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang);
|
||||
const en = isEnglish(params.recipeLang);
|
||||
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang!);
|
||||
const en = isEnglish(params.recipeLang!);
|
||||
|
||||
const query = url.searchParams.get('q')?.toLowerCase().trim() || '';
|
||||
const category = url.searchParams.get('category');
|
||||
@@ -46,12 +46,12 @@ export const GET: RequestHandler = async ({ url, params, locals }) => {
|
||||
}
|
||||
|
||||
const dbRecipes = await Recipe.find(dbQuery, projection).lean();
|
||||
let recipes: BriefRecipeType[] = dbRecipes.map(r => toBrief(r, params.recipeLang));
|
||||
let recipes: BriefRecipeType[] = dbRecipes.map(r => toBrief(r, params.recipeLang!));
|
||||
|
||||
// Handle favorites filter
|
||||
if (favoritesOnly && locals.session?.user) {
|
||||
if (favoritesOnly && (locals as any).session?.user) {
|
||||
const { UserFavorites } = await import('$models/UserFavorites');
|
||||
const userFavorites = await UserFavorites.findOne({ username: locals.session.user.username });
|
||||
const userFavorites = await UserFavorites.findOne({ username: (locals as any).session.user.username });
|
||||
if (userFavorites?.favorites) {
|
||||
const favoriteIds = userFavorites.favorites;
|
||||
recipes = recipes.filter(recipe => favoriteIds.some(id => id.toString() === recipe._id?.toString()));
|
||||
|
||||
@@ -42,7 +42,7 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
.lean();
|
||||
|
||||
// Get all other users who have splits with payments involving the current user
|
||||
const paymentIds = userSplits.map(split => split.paymentId._id);
|
||||
const paymentIds = userSplits.map(split => (split.paymentId as any)._id);
|
||||
const allRelatedSplits = await PaymentSplit.find({
|
||||
paymentId: { $in: paymentIds },
|
||||
username: { $ne: currentUser }
|
||||
@@ -60,7 +60,7 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
|
||||
// Find other participants in this payment
|
||||
const otherSplits = allRelatedSplits.filter(s =>
|
||||
s.paymentId._id.toString() === split.paymentId._id.toString()
|
||||
(s.paymentId as any)._id.toString() === (split.paymentId as any)._id.toString()
|
||||
);
|
||||
|
||||
for (const otherSplit of otherSplits) {
|
||||
|
||||
@@ -76,7 +76,7 @@ export const GET: RequestHandler = async ({ url, locals }) => {
|
||||
}
|
||||
];
|
||||
|
||||
const results = await Payment.aggregate(pipeline);
|
||||
const results = await Payment.aggregate(pipeline as any);
|
||||
|
||||
// Transform data into chart-friendly format
|
||||
const monthsMap = new Map();
|
||||
@@ -106,13 +106,13 @@ export const GET: RequestHandler = async ({ url, locals }) => {
|
||||
|
||||
// Convert to arrays for Chart.js
|
||||
const allMonths = Array.from(monthsMap.keys()).sort();
|
||||
const categoryList = Array.from(categories).sort();
|
||||
const categoryList = Array.from(categories).sort() as string[];
|
||||
|
||||
// Find the first month with any data and trim empty months from the start
|
||||
let firstMonthWithData = 0;
|
||||
for (let i = 0; i < allMonths.length; i++) {
|
||||
const monthData = monthsMap.get(allMonths[i]);
|
||||
const hasData = Object.values(monthData).some(value => value > 0);
|
||||
const hasData = Object.values(monthData).some((value: any) => value > 0);
|
||||
if (hasData) {
|
||||
firstMonthWithData = i;
|
||||
break;
|
||||
|
||||
@@ -102,7 +102,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
exchangeRate = conversion.exchangeRate;
|
||||
} catch (e) {
|
||||
console.error('Currency conversion error:', e);
|
||||
throw error(400, `Failed to convert ${inputCurrency} to CHF: ${e.message}`);
|
||||
throw error(400, `Failed to convert ${inputCurrency} to CHF: ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
};
|
||||
});
|
||||
|
||||
const splitPromises = convertedSplits.map((split) => {
|
||||
const splitPromises = convertedSplits.map((split: any) => {
|
||||
return PaymentSplit.create(split);
|
||||
});
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export const GET: RequestHandler = async ({ params, locals }) => {
|
||||
await cache.set(cacheKey, JSON.stringify(result), 1800);
|
||||
|
||||
return json(result);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (e.status === 404) throw e;
|
||||
throw error(500, 'Failed to fetch payment');
|
||||
} finally {
|
||||
@@ -108,7 +108,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
|
||||
await invalidateCospendCaches(allAffectedUsers, id);
|
||||
|
||||
return json({ success: true, payment: updatedPayment });
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (e.status) throw e;
|
||||
throw error(500, 'Failed to update payment');
|
||||
} finally {
|
||||
@@ -148,7 +148,7 @@ export const DELETE: RequestHandler = async ({ params, locals }) => {
|
||||
await invalidateCospendCaches(affectedUsernames, id);
|
||||
|
||||
return json({ success: true });
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (e.status) throw e;
|
||||
throw error(500, 'Failed to delete payment');
|
||||
} finally {
|
||||
|
||||
@@ -55,7 +55,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
path: publicPath
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.status) throw err;
|
||||
console.error('Upload error:', err);
|
||||
throw error(500, 'Failed to upload file');
|
||||
|
||||
@@ -90,22 +90,22 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
|
||||
// Ensure translations.en.images array exists
|
||||
if (!recipe.translations) {
|
||||
recipe.translations = { en: { images: [] } };
|
||||
(recipe as any).translations = { en: { images: [] } };
|
||||
}
|
||||
if (!recipe.translations.en) {
|
||||
recipe.translations.en = { images: [] };
|
||||
if (!recipe.translations!.en) {
|
||||
(recipe.translations as any).en = { images: [] };
|
||||
}
|
||||
if (!recipe.translations.en.images) {
|
||||
recipe.translations.en.images = [];
|
||||
if (!recipe.translations!.en!.images) {
|
||||
(recipe.translations!.en as any).images = [];
|
||||
}
|
||||
|
||||
// Ensure array has enough entries
|
||||
while (recipe.translations.en.images.length <= i) {
|
||||
recipe.translations.en.images.push({ alt: '', caption: '' });
|
||||
while (recipe.translations!.en!.images!.length <= i) {
|
||||
recipe.translations!.en!.images!.push({ alt: '', caption: '' } as any);
|
||||
}
|
||||
|
||||
// Update English alt text
|
||||
recipe.translations.en.images[i].alt = altTextResult.en;
|
||||
recipe.translations!.en!.images![i].alt = altTextResult.en;
|
||||
|
||||
processed++;
|
||||
} catch (err) {
|
||||
|
||||
@@ -57,22 +57,22 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
|
||||
// Ensure translations.en.images array exists and has the right length
|
||||
if (!recipe.translations) {
|
||||
recipe.translations = { en: { images: [] } };
|
||||
(recipe as any).translations = { en: { images: [] } };
|
||||
}
|
||||
if (!recipe.translations.en) {
|
||||
recipe.translations.en = { images: [] };
|
||||
if (!recipe.translations!.en) {
|
||||
(recipe.translations as any).en = { images: [] };
|
||||
}
|
||||
if (!recipe.translations.en.images) {
|
||||
recipe.translations.en.images = [];
|
||||
if (!recipe.translations!.en!.images) {
|
||||
(recipe.translations!.en as any).images = [];
|
||||
}
|
||||
|
||||
// Ensure the en.images array has entries for all images
|
||||
while (recipe.translations.en.images.length <= imageIndex) {
|
||||
recipe.translations.en.images.push({ alt: '', caption: '' });
|
||||
while (recipe.translations!.en!.images!.length <= imageIndex) {
|
||||
recipe.translations!.en!.images!.push({ alt: '', caption: '' } as any);
|
||||
}
|
||||
|
||||
// Update English alt text
|
||||
recipe.translations.en.images[imageIndex].alt = altTextResult.en;
|
||||
recipe.translations!.en!.images![imageIndex].alt = altTextResult.en;
|
||||
|
||||
// Save to database
|
||||
await recipe.save();
|
||||
|
||||
@@ -14,7 +14,7 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
try {
|
||||
const streak = await RosaryStreak.findOne({
|
||||
username: session.user.nickname
|
||||
}).lean();
|
||||
}).lean() as any;
|
||||
|
||||
return json({
|
||||
length: streak?.length ?? 0,
|
||||
@@ -49,11 +49,11 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
{ username: session.user.nickname },
|
||||
{ length, lastPrayed },
|
||||
{ upsert: true, new: true }
|
||||
).lean();
|
||||
).lean() as any;
|
||||
|
||||
return json({
|
||||
length: updated.length,
|
||||
lastPrayed: updated.lastPrayed
|
||||
length: updated?.length ?? 0,
|
||||
lastPrayed: updated?.lastPrayed ?? null
|
||||
});
|
||||
} catch (e) {
|
||||
throw error(500, 'Failed to update rosary streak');
|
||||
|
||||
@@ -4,6 +4,20 @@ import { dbConnect } from '$utils/db';
|
||||
import { MarioKartTournament } from '$models/MarioKartTournament';
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
interface BracketMatch {
|
||||
_id: string;
|
||||
contestantIds: string[];
|
||||
rounds: any[];
|
||||
completed: boolean;
|
||||
winnerId?: string;
|
||||
}
|
||||
|
||||
interface BracketRound {
|
||||
roundNumber: number;
|
||||
name: string;
|
||||
matches: BracketMatch[];
|
||||
}
|
||||
|
||||
// POST /api/mario-kart/tournaments/[id]/bracket - Generate tournament bracket
|
||||
export const POST: RequestHandler = async ({ params, request }) => {
|
||||
try {
|
||||
@@ -31,18 +45,18 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
return json({ error: `Group ${group.name} has no standings yet` }, { status: 400 });
|
||||
}
|
||||
|
||||
const sortedStandings = group.standings.sort((a, b) => a.position - b.position);
|
||||
const sortedStandings = group.standings.sort((a: any, b: any) => a.position - b.position);
|
||||
|
||||
// Top N qualify for main bracket
|
||||
const topContestants = sortedStandings
|
||||
.slice(0, topNFromEachGroup)
|
||||
.map(s => s.contestantId);
|
||||
.map((s: any) => s.contestantId);
|
||||
qualifiedContestants.push(...topContestants);
|
||||
|
||||
// Remaining contestants go to consolation bracket
|
||||
const remainingContestants = sortedStandings
|
||||
.slice(topNFromEachGroup)
|
||||
.map(s => s.contestantId);
|
||||
.map((s: any) => s.contestantId);
|
||||
nonQualifiedContestants.push(...remainingContestants);
|
||||
}
|
||||
|
||||
@@ -57,7 +71,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
const bracketSize = Math.pow(matchSize, Math.ceil(Math.log(qualifiedContestants.length) / Math.log(matchSize)));
|
||||
|
||||
// Generate bracket rounds
|
||||
const rounds = [];
|
||||
const rounds: BracketRound[] = [];
|
||||
let currentContestants = bracketSize;
|
||||
let roundNumber = 1;
|
||||
|
||||
@@ -141,7 +155,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
};
|
||||
|
||||
// Create consolation bracket for non-qualifiers
|
||||
const runnersUpRounds = [];
|
||||
const runnersUpRounds: BracketRound[] = [];
|
||||
if (nonQualifiedContestants.length >= matchSize) {
|
||||
// Calculate consolation bracket size
|
||||
const consolationBracketSize = Math.pow(matchSize, Math.ceil(Math.log(nonQualifiedContestants.length) / Math.log(matchSize)));
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
console.error(`Round ${i} has no matches array:`, round);
|
||||
continue;
|
||||
}
|
||||
const foundMatch = round.matches.find(m => m._id?.toString() === params.matchId);
|
||||
const foundMatch = round.matches.find((m: any) => m._id?.toString() === params.matchId);
|
||||
if (foundMatch) {
|
||||
match = foundMatch;
|
||||
matchRound = round;
|
||||
@@ -59,7 +59,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
isRunnersUp = true;
|
||||
for (let i = 0; i < bracket.rounds.length; i++) {
|
||||
const round = bracket.rounds[i];
|
||||
const foundMatch = round.matches.find(m => m._id?.toString() === params.matchId);
|
||||
const foundMatch = round.matches.find((m: any) => m._id?.toString() === params.matchId);
|
||||
if (foundMatch) {
|
||||
match = foundMatch;
|
||||
matchRound = round;
|
||||
|
||||
@@ -23,7 +23,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
}
|
||||
|
||||
// Check for duplicate names
|
||||
if (tournament.contestants.some(c => c.name === name)) {
|
||||
if (tournament.contestants.some((c: any) => c.name === name)) {
|
||||
return json({ error: 'Contestant with this name already exists' }, { status: 400 });
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export const DELETE: RequestHandler = async ({ params, url }) => {
|
||||
}
|
||||
|
||||
tournament.contestants = tournament.contestants.filter(
|
||||
c => c._id?.toString() !== contestantId
|
||||
(c: any) => c._id?.toString() !== contestantId
|
||||
);
|
||||
|
||||
await tournament.save();
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ export const PATCH: RequestHandler = async ({ params, request }) => {
|
||||
|
||||
// Find the contestant in the contestants array
|
||||
const contestant = tournament.contestants.find(
|
||||
c => c._id?.toString() === params.contestantId
|
||||
(c: any) => c._id?.toString() === params.contestantId
|
||||
);
|
||||
|
||||
if (!contestant) {
|
||||
|
||||
@@ -21,18 +21,18 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
return json({ error: 'Tournament not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const group = tournament.groups.find(g => g._id?.toString() === params.groupId);
|
||||
const group = tournament.groups.find((g: any) => g._id?.toString() === params.groupId);
|
||||
if (!group) {
|
||||
return json({ error: 'Group not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const match = group.matches.find(m => m._id?.toString() === matchId);
|
||||
const match = group.matches.find((m: any) => m._id?.toString() === matchId);
|
||||
if (!match) {
|
||||
return json({ error: 'Match not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// Add or update round
|
||||
const existingRoundIndex = match.rounds.findIndex(r => r.roundNumber === roundNumber);
|
||||
const existingRoundIndex = match.rounds.findIndex((r: any) => r.roundNumber === roundNumber);
|
||||
const scoresMap = new Map(Object.entries(scores));
|
||||
|
||||
if (existingRoundIndex >= 0) {
|
||||
|
||||
Reference in New Issue
Block a user