Revert "Implement secure client-side favorites loading to fix nginx 502 issues"
All checks were successful
CI / update (push) Successful in 16s

This reverts commit 48b94e3aef.
This commit is contained in:
2025-09-04 12:26:27 +02:00
parent 48b94e3aef
commit 55a4e6a262
4 changed files with 35 additions and 195 deletions

View File

@@ -1,28 +1,30 @@
<script lang="ts">
import { favorites } from '$lib/stores/favorites';
import { onMount } from 'svelte';
export let recipeId: string; // This will be short_name from the component usage
export let isFavorite: boolean = false; // Initial state from server
export let recipeId: string;
export let isFavorite: boolean = false;
export let isLoggedIn: boolean = false;
let currentIsFavorite = isFavorite;
let isLoading = false;
// Load current favorite status when component mounts
onMount(async () => {
if (isLoggedIn) {
currentIsFavorite = await favorites.isFavoriteByShortName(recipeId);
}
});
async function toggleFavorite() {
if (!isLoggedIn || isLoading) return;
isLoading = true;
try {
await favorites.toggle(recipeId);
currentIsFavorite = !currentIsFavorite;
const method = isFavorite ? 'DELETE' : 'POST';
const response = await fetch('/api/rezepte/favorites', {
method,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ recipeId }),
});
if (response.ok) {
isFavorite = !isFavorite;
}
} catch (error) {
console.error('Failed to toggle favorite:', error);
} finally {
isLoading = false;
}
@@ -57,8 +59,8 @@
class="favorite-button"
disabled={isLoading}
on:click={toggleFavorite}
title={currentIsFavorite ? 'Favorit entfernen' : 'Als Favorit speichern'}
title={isFavorite ? 'Favorit entfernen' : 'Als Favorit speichern'}
>
{currentIsFavorite ? '❤️' : '🖤'}
{isFavorite ? '❤️' : '🖤'}
</button>
{/if}

View File

@@ -1,156 +0,0 @@
import { writable, derived } from 'svelte/store';
import { page } from '$app/stores';
export interface FavoritesState {
favorites: string[]; // Array of ObjectIds
shortNameToObjectId: Map<string, string>; // Mapping from short_name to ObjectId
loading: boolean;
error: string | null;
}
// Create the favorites store
function createFavoritesStore() {
const { subscribe, set, update } = writable<FavoritesState>({
favorites: [],
shortNameToObjectId: new Map(),
loading: false,
error: null
});
return {
subscribe,
// Load user's favorites from API
async load() {
update(state => ({ ...state, loading: true, error: null }));
try {
const response = await fetch('/api/rezepte/favorites', {
credentials: 'include' // Ensure cookies are sent for authentication
});
if (response.ok) {
const data = await response.json();
update(state => ({
...state,
favorites: data.favorites || [],
loading: false
}));
} else if (response.status === 401) {
// User not authenticated, clear favorites
update(state => ({
...state,
favorites: [],
loading: false
}));
} else {
throw new Error(`Failed to load favorites: ${response.status}`);
}
} catch (error) {
console.error('Error loading favorites:', error);
update(state => ({
...state,
loading: false,
error: error instanceof Error ? error.message : 'Failed to load favorites'
}));
}
},
// Add a recipe to favorites
async add(recipeShortName: string) {
try {
const response = await fetch('/api/rezepte/favorites', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ recipeId: recipeShortName }),
credentials: 'include'
});
if (response.ok) {
// Reload favorites to get the updated list with ObjectIds
await this.load();
} else {
throw new Error(`Failed to add favorite: ${response.status}`);
}
} catch (error) {
console.error('Error adding favorite:', error);
update(state => ({
...state,
error: error instanceof Error ? error.message : 'Failed to add favorite'
}));
}
},
// Remove a recipe from favorites
async remove(recipeShortName: string) {
try {
const response = await fetch('/api/rezepte/favorites', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ recipeId: recipeShortName }),
credentials: 'include'
});
if (response.ok) {
// Reload favorites to get the updated list
await this.load();
} else {
throw new Error(`Failed to remove favorite: ${response.status}`);
}
} catch (error) {
console.error('Error removing favorite:', error);
update(state => ({
...state,
error: error instanceof Error ? error.message : 'Failed to remove favorite'
}));
}
},
// Toggle favorite status by short_name
async toggle(recipeShortName: string) {
// Check if favorited by checking the current recipe list for this short_name
const response = await fetch(`/api/rezepte/favorites/check/${recipeShortName}`, {
credentials: 'include'
});
if (response.ok) {
const { isFavorite } = await response.json();
if (isFavorite) {
await this.remove(recipeShortName);
} else {
await this.add(recipeShortName);
}
}
},
// Check if a recipe is favorited by short_name
async isFavoriteByShortName(shortName: string): Promise<boolean> {
try {
const response = await fetch(`/api/rezepte/favorites/check/${shortName}`, {
credentials: 'include'
});
if (response.ok) {
const { isFavorite } = await response.json();
return isFavorite;
}
} catch (error) {
console.error('Error checking favorite status:', error);
}
return false;
}
};
}
export const favorites = createFavoritesStore();
// Helper function to add favorite status to recipes on client-side
export function addFavoriteStatusToRecipes(recipes: any[], userFavorites: string[]): any[] {
return recipes.map(recipe => ({
...recipe,
isFavorite: userFavorites.includes(recipe._id?.toString() || recipe.short_name)
}));
}

View File

@@ -1,14 +1,22 @@
import type { PageServerLoad } from "./$types";
import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favorites";
export async function load({ fetch }) {
export async function load({ fetch, locals }) {
let current_month = new Date().getMonth() + 1
const res_season = await fetch(`/api/rezepte/items/in_season/` + current_month);
const res_all_brief = await fetch(`/api/rezepte/items/all_brief`);
const item_season = await res_season.json();
const item_all_brief = await res_all_brief.json();
// Get user favorites and session
const [userFavorites, session] = await Promise.all([
getUserFavorites(fetch, locals),
locals.auth()
]);
return {
season: item_season,
all_brief: item_all_brief
season: addFavoriteStatusToRecipes(item_season, userFavorites),
all_brief: addFavoriteStatusToRecipes(item_all_brief, userFavorites),
session
};
};

View File

@@ -1,26 +1,12 @@
<script lang="ts">
import type { PageData } from './$types';
import { onMount } from 'svelte';
import { favorites, addFavoriteStatusToRecipes } from '$lib/stores/favorites';
import { page } from '$app/stores';
import MediaScroller from '$lib/components/MediaScroller.svelte';
import AddButton from '$lib/components/AddButton.svelte';
import Card from '$lib/components/Card.svelte';
import Search from '$lib/components/Search.svelte';
export let data: PageData;
export let current_month = new Date().getMonth() + 1
const categories = ["Hauptspeise", "Nudel", "Brot", "Dessert", "Suppe", "Beilage", "Salat", "Kuchen", "Frühstück", "Sauce", "Zutat", "Getränk", "Aufstrich", "Guetzli", "Snack"];
// Load favorites when component mounts and user is authenticated
onMount(() => {
if ($page.data.session?.user) {
favorites.load();
}
});
// Reactively add favorite status to recipes
$: seasonWithFavorites = addFavoriteStatusToRecipes(data.season, $favorites.favorites);
$: allBriefWithFavorites = addFavoriteStatusToRecipes(data.all_brief, $favorites.favorites);
const categories = ["Hauptspeise", "Nudel", "Brot", "Dessert", "Suppe", "Beilage", "Salat", "Kuchen", "Frühstück", "Sauce", "Zutat", "Getränk", "Aufstrich", "Guetzli", "Snack"]
</script>
<style>
h1{
@@ -49,15 +35,15 @@ h1{
<Search></Search>
<MediaScroller title="In Saison">
{#each seasonWithFavorites as recipe}
<Card {recipe} {current_month} loading_strat={"eager"} do_margin_right={true} isFavorite={recipe.isFavorite} showFavoriteIndicator={!!$page.data.session?.user}></Card>
{#each data.season as recipe}
<Card {recipe} {current_month} loading_strat={"eager"} do_margin_right={true} isFavorite={recipe.isFavorite} showFavoriteIndicator={!!data.session?.user}></Card>
{/each}
</MediaScroller>
{#each categories as category}
<MediaScroller title={category}>
{#each allBriefWithFavorites.filter(recipe => recipe.category == category) as recipe}
<Card {recipe} {current_month} do_margin_right={true} isFavorite={recipe.isFavorite} showFavoriteIndicator={!!$page.data.session?.user}></Card>
{#each data.all_brief.filter(recipe => recipe.category == category) as recipe}
<Card {recipe} {current_month} do_margin_right={true} isFavorite={recipe.isFavorite} showFavoriteIndicator={!!data.session?.user}></Card>
{/each}
</MediaScroller>
{/each}