Compare commits
	
		
			2 Commits
		
	
	
		
			7bc51e3a0e
			...
			6a8478f8a6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						6a8478f8a6
	
				 | 
					
					
						|||
| 
						
						
							
						
						be26769efb
	
				 | 
					
					
						
@@ -71,7 +71,7 @@ const img_name=recipe.short_name + ".webp?v=" + recipe.dateModified
 | 
				
			|||||||
	font-size: 1.5em;
 | 
						font-size: 1.5em;
 | 
				
			||||||
	box-shadow: 0em 0em 1em 0.1em rgba(0, 0, 0, 0.6);
 | 
						box-shadow: 0em 0em 1em 0.1em rgba(0, 0, 0, 0.6);
 | 
				
			||||||
	transition: 100ms;
 | 
						transition: 100ms;
 | 
				
			||||||
	z-index: 10;
 | 
						z-index: 5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#image{
 | 
					#image{
 | 
				
			||||||
	width: 300px;
 | 
						width: 300px;
 | 
				
			||||||
@@ -197,8 +197,8 @@ const img_name=recipe.short_name + ".webp?v=" + recipe.dateModified
 | 
				
			|||||||
.favorite-indicator{
 | 
					.favorite-indicator{
 | 
				
			||||||
	position: absolute;
 | 
						position: absolute;
 | 
				
			||||||
	font-size: 2rem;
 | 
						font-size: 2rem;
 | 
				
			||||||
	top: -0.5em;
 | 
						top: 0.1em;
 | 
				
			||||||
	left: -0.5em;
 | 
						left: 0.1em;
 | 
				
			||||||
	filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.8));
 | 
						filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.8));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,42 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import { browser } from '$app/environment';
 | 
				
			||||||
 | 
					  import { enhance } from '$app/forms';
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  export let recipeId: string;
 | 
					  export let recipeId: string;
 | 
				
			||||||
  export let isFavorite: boolean = false;
 | 
					  export let isFavorite: boolean = false;
 | 
				
			||||||
  export let isLoggedIn: boolean = false;
 | 
					  export let isLoggedIn: boolean = false;
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  let isLoading = false;
 | 
					  let isLoading = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async function toggleFavorite() {
 | 
					  async function toggleFavorite(event: Event) {
 | 
				
			||||||
    if (!isLoggedIn || isLoading) return;
 | 
					    // If JavaScript is available, prevent form submission and handle client-side
 | 
				
			||||||
    
 | 
					    if (browser) {
 | 
				
			||||||
    isLoading = true;
 | 
					      event.preventDefault();
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      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) {
 | 
					      if (!isLoggedIn || isLoading) return;
 | 
				
			||||||
        isFavorite = !isFavorite;
 | 
					      
 | 
				
			||||||
 | 
					      isLoading = true;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      console.error('Failed to toggle favorite:', error);
 | 
					 | 
				
			||||||
    } finally {
 | 
					 | 
				
			||||||
      isLoading = false;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // If no JS, form will submit normally
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,12 +64,17 @@
 | 
				
			|||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#if isLoggedIn}
 | 
					{#if isLoggedIn}
 | 
				
			||||||
  <button 
 | 
					  <form method="post" action="?/toggleFavorite" style="display: inline;" use:enhance>
 | 
				
			||||||
    class="favorite-button"
 | 
					    <input type="hidden" name="recipeId" value={recipeId} />
 | 
				
			||||||
    disabled={isLoading}
 | 
					    <input type="hidden" name="isFavorite" value={isFavorite} />
 | 
				
			||||||
    on:click={toggleFavorite}
 | 
					    <button 
 | 
				
			||||||
    title={isFavorite ? 'Favorit entfernen' : 'Als Favorit speichern'}
 | 
					      type="submit"
 | 
				
			||||||
  >
 | 
					      class="favorite-button"
 | 
				
			||||||
    {isFavorite ? '❤️' : '🖤'}
 | 
					      disabled={isLoading}
 | 
				
			||||||
  </button>
 | 
					      on:click={toggleFavorite}
 | 
				
			||||||
 | 
					      title={isFavorite ? 'Favorit entfernen' : 'Als Favorit speichern'}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {isFavorite ? '❤️' : '🖤'}
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					  </form>
 | 
				
			||||||
{/if}
 | 
					{/if}
 | 
				
			||||||
@@ -1,6 +1,50 @@
 | 
				
			|||||||
import { redirect } from '@sveltejs/kit';
 | 
					import { redirect, error } from '@sveltejs/kit';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const actions = {
 | 
					export const actions = {
 | 
				
			||||||
 | 
					    toggleFavorite: async ({ request, locals, url, fetch }) => {
 | 
				
			||||||
 | 
					        const session = await locals.auth();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (!session?.user?.nickname) {
 | 
				
			||||||
 | 
					            throw error(401, 'Authentication required');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        const formData = await request.formData();
 | 
				
			||||||
 | 
					        const recipeId = formData.get('recipeId') as string;
 | 
				
			||||||
 | 
					        const isFavorite = formData.get('isFavorite') === 'true';
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (!recipeId) {
 | 
				
			||||||
 | 
					            throw error(400, 'Recipe ID required');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // Use the existing API endpoint
 | 
				
			||||||
 | 
					            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) {
 | 
				
			||||||
 | 
					                const errorData = await response.text();
 | 
				
			||||||
 | 
					                console.error('API error:', response.status, errorData);
 | 
				
			||||||
 | 
					                throw error(response.status, `Failed to toggle favorite: ${errorData}`);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Redirect back to the same page to refresh the state
 | 
				
			||||||
 | 
					            throw redirect(303, url.pathname);
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            // If it's a redirect, let it through
 | 
				
			||||||
 | 
					            if (e && typeof e === 'object' && 'status' in e && e.status === 303) {
 | 
				
			||||||
 | 
					                throw e;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            console.error('Favorite toggle error:', e);
 | 
				
			||||||
 | 
					            throw error(500, 'Failed to toggle favorite');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    swapYeast: async ({ request, url }) => {
 | 
					    swapYeast: async ({ request, url }) => {
 | 
				
			||||||
        const formData = await request.formData();
 | 
					        const formData = await request.formData();
 | 
				
			||||||
        const yeastId = parseInt(formData.get('yeastId') as string);
 | 
					        const yeastId = parseInt(formData.get('yeastId') as string);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user