refactor: abstract dashboard lists into components
This commit is contained in:
157
src/lib/components/dashboard/WishlistSection.svelte
Normal file
157
src/lib/components/dashboard/WishlistSection.svelte
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Button } from '$lib/components/ui/button';
|
||||||
|
import WishlistGrid from '$lib/components/dashboard/WishlistGrid.svelte';
|
||||||
|
import WishlistCard from '$lib/components/dashboard/WishlistCard.svelte';
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
|
import { Star } from 'lucide-svelte';
|
||||||
|
import { languageStore } from '$lib/stores/language.svelte';
|
||||||
|
import SearchBar from '$lib/components/ui/SearchBar.svelte';
|
||||||
|
import UnlockButton from '$lib/components/ui/UnlockButton.svelte';
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
|
type WishlistItem = any; // You can make this more specific based on your types
|
||||||
|
|
||||||
|
let {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
items,
|
||||||
|
emptyMessage,
|
||||||
|
emptyDescription,
|
||||||
|
emptyActionLabel,
|
||||||
|
emptyActionHref,
|
||||||
|
showCreateButton = false,
|
||||||
|
hideIfEmpty = false,
|
||||||
|
actions
|
||||||
|
}: {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
items: WishlistItem[];
|
||||||
|
emptyMessage: string;
|
||||||
|
emptyDescription?: string;
|
||||||
|
emptyActionLabel?: string;
|
||||||
|
emptyActionHref?: string;
|
||||||
|
showCreateButton?: boolean;
|
||||||
|
hideIfEmpty?: boolean;
|
||||||
|
actions: Snippet<[WishlistItem, boolean]>; // item, unlocked
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
const t = $derived(languageStore.t);
|
||||||
|
|
||||||
|
let unlocked = $state(false);
|
||||||
|
let searchQuery = $state('');
|
||||||
|
|
||||||
|
// Filter items based on search query
|
||||||
|
const filteredItems = $derived(() => {
|
||||||
|
if (!searchQuery.trim()) return items;
|
||||||
|
|
||||||
|
return items.filter(item => {
|
||||||
|
const title = item.title || item.wishlist?.title || '';
|
||||||
|
const description = item.description || item.wishlist?.description || '';
|
||||||
|
const query = searchQuery.toLowerCase();
|
||||||
|
|
||||||
|
return title.toLowerCase().includes(query) || description.toLowerCase().includes(query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort items by favorite, end date, then created date
|
||||||
|
const sortedItems = $derived(() => {
|
||||||
|
return [...filteredItems()].sort((a, b) => {
|
||||||
|
// Handle both direct wishlists and saved wishlists
|
||||||
|
const aItem = a.wishlist || a;
|
||||||
|
const bItem = b.wishlist || b;
|
||||||
|
|
||||||
|
// Sort by favorite first
|
||||||
|
if (a.isFavorite && !b.isFavorite) return -1;
|
||||||
|
if (!a.isFavorite && b.isFavorite) return 1;
|
||||||
|
|
||||||
|
// Then by end date
|
||||||
|
const aHasEndDate = !!aItem.endDate;
|
||||||
|
const bHasEndDate = !!bItem.endDate;
|
||||||
|
|
||||||
|
if (aHasEndDate && !bHasEndDate) return -1;
|
||||||
|
if (!aHasEndDate && bHasEndDate) return 1;
|
||||||
|
|
||||||
|
if (aHasEndDate && bHasEndDate) {
|
||||||
|
return new Date(aItem.endDate!).getTime() - new Date(bItem.endDate!).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally by created date (most recent first)
|
||||||
|
const aCreatedAt = a.createdAt || aItem.createdAt;
|
||||||
|
const bCreatedAt = b.createdAt || bItem.createdAt;
|
||||||
|
return new Date(bCreatedAt).getTime() - new Date(aCreatedAt).getTime();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function formatEndDate(date: Date | string | null): string | null {
|
||||||
|
if (!date) return null;
|
||||||
|
const d = new Date(date);
|
||||||
|
return d.toLocaleDateString(languageStore.t.date.format.short, { year: 'numeric', month: 'short', day: 'numeric' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWishlistDescription(item: any): string | null {
|
||||||
|
const wishlist = item.wishlist || item;
|
||||||
|
if (!wishlist) return null;
|
||||||
|
|
||||||
|
const lines: string[] = [];
|
||||||
|
|
||||||
|
const topItems = wishlist.items?.slice(0, 3).map((i: any) => i.title) || [];
|
||||||
|
if (topItems.length > 0) {
|
||||||
|
lines.push(topItems.join(', '));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wishlist.user?.name || wishlist.user?.username) {
|
||||||
|
const ownerName = wishlist.user.name || wishlist.user.username;
|
||||||
|
lines.push(`${t.dashboard.by} ${ownerName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wishlist.endDate) {
|
||||||
|
lines.push(`${t.dashboard.ends}: ${formatEndDate(wishlist.endDate)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.length > 0 ? lines.join('\n') : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide entire section if hideIfEmpty is true and there are no items
|
||||||
|
const shouldShow = $derived(() => {
|
||||||
|
return !hideIfEmpty || items.length > 0;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if shouldShow()}
|
||||||
|
<WishlistGrid
|
||||||
|
{title}
|
||||||
|
{description}
|
||||||
|
items={sortedItems() || []}
|
||||||
|
{emptyMessage}
|
||||||
|
{emptyDescription}
|
||||||
|
{emptyActionLabel}
|
||||||
|
{emptyActionHref}
|
||||||
|
>
|
||||||
|
{#snippet headerAction()}
|
||||||
|
<div class="flex flex-col sm:flex-row gap-2">
|
||||||
|
{#if showCreateButton}
|
||||||
|
<Button onclick={() => (window.location.href = '/')}>{t.dashboard.createNew}</Button>
|
||||||
|
{/if}
|
||||||
|
<UnlockButton bind:unlocked />
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{#snippet searchBar()}
|
||||||
|
{#if items.length > 0}
|
||||||
|
<SearchBar bind:value={searchQuery} />
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{#snippet children(item)}
|
||||||
|
{@const wishlist = item.wishlist || item}
|
||||||
|
<WishlistCard
|
||||||
|
title={wishlist.title}
|
||||||
|
description={getWishlistDescription(item)}
|
||||||
|
itemCount={wishlist.items?.length || 0}
|
||||||
|
color={wishlist.color}
|
||||||
|
>
|
||||||
|
{@render actions(item, unlocked)}
|
||||||
|
</WishlistCard>
|
||||||
|
{/snippet}
|
||||||
|
</WishlistGrid>
|
||||||
|
{/if}
|
||||||
@@ -3,191 +3,51 @@
|
|||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import PageContainer from '$lib/components/layout/PageContainer.svelte';
|
import PageContainer from '$lib/components/layout/PageContainer.svelte';
|
||||||
import DashboardHeader from '$lib/components/layout/DashboardHeader.svelte';
|
import DashboardHeader from '$lib/components/layout/DashboardHeader.svelte';
|
||||||
import WishlistGrid from '$lib/components/dashboard/WishlistGrid.svelte';
|
import WishlistSection from '$lib/components/dashboard/WishlistSection.svelte';
|
||||||
import WishlistCard from '$lib/components/dashboard/WishlistCard.svelte';
|
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
import { Star } from 'lucide-svelte';
|
import { Star } from 'lucide-svelte';
|
||||||
import { languageStore } from '$lib/stores/language.svelte';
|
import { languageStore } from '$lib/stores/language.svelte';
|
||||||
import SearchBar from '$lib/components/ui/SearchBar.svelte';
|
|
||||||
import UnlockButton from '$lib/components/ui/UnlockButton.svelte';
|
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
const t = $derived(languageStore.t);
|
const t = $derived(languageStore.t);
|
||||||
|
|
||||||
let myWishlistsUnlocked = $state(false);
|
// Only owned wishlists for "My Wishlists"
|
||||||
let claimedWishlistsUnlocked = $state(false);
|
const myWishlists = $derived(() => data.wishlists || []);
|
||||||
let savedWishlistsUnlocked = $state(false);
|
|
||||||
let myWishlistsSearch = $state('');
|
|
||||||
let claimedWishlistsSearch = $state('');
|
|
||||||
let savedWishlistsSearch = $state('');
|
|
||||||
|
|
||||||
// Only owned wishlists for "My Wishlists" (exclude claimed)
|
|
||||||
const allMyWishlists = $derived(() => {
|
|
||||||
const owned = data.wishlists || [];
|
|
||||||
return owned;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Claimed wishlists (those with ownerToken, meaning they were claimed via edit link)
|
// Claimed wishlists (those with ownerToken, meaning they were claimed via edit link)
|
||||||
const allClaimedWishlists = $derived(() => {
|
const claimedWishlists = $derived(() => {
|
||||||
const claimed = (data.savedWishlists || [])
|
return (data.savedWishlists || [])
|
||||||
.filter(saved => saved.wishlist?.ownerToken) // Has edit access
|
.filter(saved => saved.wishlist?.ownerToken)
|
||||||
.map(saved => ({
|
.map(saved => ({
|
||||||
...saved.wishlist,
|
...saved.wishlist,
|
||||||
isFavorite: saved.isFavorite,
|
isFavorite: saved.isFavorite,
|
||||||
isClaimed: true,
|
isClaimed: true,
|
||||||
savedId: saved.id
|
savedId: saved.id
|
||||||
}));
|
}));
|
||||||
return claimed;
|
|
||||||
});
|
|
||||||
|
|
||||||
const sortedWishlists = $derived(() => {
|
|
||||||
const filtered = myWishlistsSearch.trim()
|
|
||||||
? allMyWishlists().filter(w =>
|
|
||||||
w.title.toLowerCase().includes(myWishlistsSearch.toLowerCase()) ||
|
|
||||||
w.description?.toLowerCase().includes(myWishlistsSearch.toLowerCase())
|
|
||||||
)
|
|
||||||
: allMyWishlists();
|
|
||||||
|
|
||||||
return [...filtered].sort((a, b) => {
|
|
||||||
if (a.isFavorite && !b.isFavorite) return -1;
|
|
||||||
if (!a.isFavorite && b.isFavorite) return 1;
|
|
||||||
|
|
||||||
const aHasEndDate = !!a.endDate;
|
|
||||||
const bHasEndDate = !!b.endDate;
|
|
||||||
|
|
||||||
if (aHasEndDate && !bHasEndDate) return -1;
|
|
||||||
if (!aHasEndDate && bHasEndDate) return 1;
|
|
||||||
|
|
||||||
if (aHasEndDate && bHasEndDate) {
|
|
||||||
return new Date(a.endDate!).getTime() - new Date(b.endDate!).getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const sortedClaimedWishlists = $derived(() => {
|
|
||||||
const filtered = claimedWishlistsSearch.trim()
|
|
||||||
? allClaimedWishlists().filter(w =>
|
|
||||||
w.title.toLowerCase().includes(claimedWishlistsSearch.toLowerCase()) ||
|
|
||||||
w.description?.toLowerCase().includes(claimedWishlistsSearch.toLowerCase())
|
|
||||||
)
|
|
||||||
: allClaimedWishlists();
|
|
||||||
|
|
||||||
return [...filtered].sort((a, b) => {
|
|
||||||
if (a.isFavorite && !b.isFavorite) return -1;
|
|
||||||
if (!a.isFavorite && b.isFavorite) return 1;
|
|
||||||
|
|
||||||
const aHasEndDate = !!a.endDate;
|
|
||||||
const bHasEndDate = !!b.endDate;
|
|
||||||
|
|
||||||
if (aHasEndDate && !bHasEndDate) return -1;
|
|
||||||
if (!aHasEndDate && bHasEndDate) return 1;
|
|
||||||
|
|
||||||
if (aHasEndDate && bHasEndDate) {
|
|
||||||
return new Date(a.endDate!).getTime() - new Date(b.endDate!).getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Saved wishlists are those WITHOUT ownerToken (saved from public view only)
|
// Saved wishlists are those WITHOUT ownerToken (saved from public view only)
|
||||||
const sortedSavedWishlists = $derived(() => {
|
const savedWishlists = $derived(() => {
|
||||||
const filtered = savedWishlistsSearch.trim()
|
return (data.savedWishlists || []).filter(saved => !saved.wishlist?.ownerToken);
|
||||||
? (data.savedWishlists || [])
|
|
||||||
.filter(saved => !saved.wishlist?.ownerToken) // No edit access
|
|
||||||
.filter(saved =>
|
|
||||||
saved.wishlist?.title.toLowerCase().includes(savedWishlistsSearch.toLowerCase()) ||
|
|
||||||
saved.wishlist?.description?.toLowerCase().includes(savedWishlistsSearch.toLowerCase())
|
|
||||||
)
|
|
||||||
: (data.savedWishlists || []).filter(saved => !saved.wishlist?.ownerToken);
|
|
||||||
|
|
||||||
return [...filtered].sort((a, b) => {
|
|
||||||
if (a.isFavorite && !b.isFavorite) return -1;
|
|
||||||
if (!a.isFavorite && b.isFavorite) return 1;
|
|
||||||
|
|
||||||
const aHasEndDate = !!a.wishlist?.endDate;
|
|
||||||
const bHasEndDate = !!b.wishlist?.endDate;
|
|
||||||
|
|
||||||
if (aHasEndDate && !bHasEndDate) return -1;
|
|
||||||
if (!aHasEndDate && bHasEndDate) return 1;
|
|
||||||
|
|
||||||
if (aHasEndDate && bHasEndDate) {
|
|
||||||
return new Date(a.wishlist.endDate!).getTime() - new Date(b.wishlist.endDate!).getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
function formatEndDate(date: Date | string | null): string | null {
|
|
||||||
if (!date) return null;
|
|
||||||
const d = new Date(date);
|
|
||||||
return d.toLocaleDateString(languageStore.t.date.format.short, { year: 'numeric', month: 'short', day: 'numeric' });
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWishlistDescription(wishlist: any): string | null {
|
|
||||||
if (!wishlist) return null;
|
|
||||||
|
|
||||||
const lines: string[] = [];
|
|
||||||
|
|
||||||
const topItems = wishlist.items?.slice(0, 3).map((item: any) => item.title) || [];
|
|
||||||
if (topItems.length > 0) {
|
|
||||||
lines.push(topItems.join(', '));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wishlist.user?.name || wishlist.user?.username) {
|
|
||||||
const ownerName = wishlist.user.name || wishlist.user.username;
|
|
||||||
lines.push(`${t.dashboard.by} ${ownerName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wishlist.endDate) {
|
|
||||||
lines.push(`${t.dashboard.ends}: ${formatEndDate(wishlist.endDate)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines.length > 0 ? lines.join('\n') : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSavedWishlistDescription(saved: any): string | null {
|
|
||||||
return getWishlistDescription(saved.wishlist);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<DashboardHeader userName={data.user?.name} userEmail={data.user?.email} />
|
<DashboardHeader userName={data.user?.name} userEmail={data.user?.email} />
|
||||||
|
|
||||||
<WishlistGrid
|
<!-- My Wishlists Section -->
|
||||||
|
<WishlistSection
|
||||||
title={t.dashboard.myWishlists}
|
title={t.dashboard.myWishlists}
|
||||||
description={t.dashboard.myWishlistsDescription}
|
description={t.dashboard.myWishlistsDescription}
|
||||||
items={sortedWishlists() || []}
|
items={myWishlists()}
|
||||||
emptyMessage={t.dashboard.emptyWishlists}
|
emptyMessage={t.dashboard.emptyWishlists}
|
||||||
emptyActionLabel={t.dashboard.emptyWishlistsAction}
|
emptyActionLabel={t.dashboard.emptyWishlistsAction}
|
||||||
emptyActionHref="/"
|
emptyActionHref="/"
|
||||||
|
showCreateButton={true}
|
||||||
>
|
>
|
||||||
{#snippet headerAction()}
|
{#snippet actions(wishlist, unlocked)}
|
||||||
<div class="flex flex-col sm:flex-row gap-2">
|
|
||||||
<Button onclick={() => (window.location.href = '/')}>{t.dashboard.createNew}</Button>
|
|
||||||
<UnlockButton bind:unlocked={myWishlistsUnlocked} />
|
|
||||||
</div>
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
{#snippet searchBar()}
|
|
||||||
{#if allMyWishlists().length > 0}
|
|
||||||
<SearchBar bind:value={myWishlistsSearch} />
|
|
||||||
{/if}
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
{#snippet children(wishlist)}
|
|
||||||
<WishlistCard
|
|
||||||
title={wishlist.title}
|
|
||||||
description={getWishlistDescription(wishlist)}
|
|
||||||
itemCount={wishlist.items?.length || 0}
|
|
||||||
color={wishlist.color}
|
|
||||||
>
|
|
||||||
<div class="flex gap-2 flex-wrap">
|
<div class="flex gap-2 flex-wrap">
|
||||||
<!-- For owned wishlists, use regular favorite toggle -->
|
|
||||||
<form method="POST" action="?/toggleFavorite" use:enhance={() => {
|
<form method="POST" action="?/toggleFavorite" use:enhance={() => {
|
||||||
return async ({ update }) => {
|
return async ({ update }) => {
|
||||||
await update({ reset: false });
|
await update({ reset: false });
|
||||||
@@ -216,8 +76,7 @@
|
|||||||
>
|
>
|
||||||
{t.dashboard.copyLink}
|
{t.dashboard.copyLink}
|
||||||
</Button>
|
</Button>
|
||||||
{#if myWishlistsUnlocked}
|
{#if unlocked}
|
||||||
<!-- Add delete button for owned wishlists when unlocked -->
|
|
||||||
<form method="POST" action="?/deleteWishlist" use:enhance={() => {
|
<form method="POST" action="?/deleteWishlist" use:enhance={() => {
|
||||||
return async ({ update }) => {
|
return async ({ update }) => {
|
||||||
await update({ reset: false });
|
await update({ reset: false });
|
||||||
@@ -230,39 +89,20 @@
|
|||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</WishlistCard>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</WishlistGrid>
|
</WishlistSection>
|
||||||
|
|
||||||
{#if allClaimedWishlists().length > 0}
|
<!-- Claimed Wishlists Section -->
|
||||||
<WishlistGrid
|
<WishlistSection
|
||||||
title={t.dashboard.claimedWishlists}
|
title={t.dashboard.claimedWishlists}
|
||||||
description={t.dashboard.claimedWishlistsDescription}
|
description={t.dashboard.claimedWishlistsDescription}
|
||||||
items={sortedClaimedWishlists() || []}
|
items={claimedWishlists()}
|
||||||
emptyMessage={t.dashboard.emptyClaimedWishlists}
|
emptyMessage={t.dashboard.emptyClaimedWishlists}
|
||||||
emptyDescription={t.dashboard.emptyClaimedWishlistsDescription}
|
emptyDescription={t.dashboard.emptyClaimedWishlistsDescription}
|
||||||
|
hideIfEmpty={true}
|
||||||
>
|
>
|
||||||
{#snippet headerAction()}
|
{#snippet actions(wishlist, unlocked)}
|
||||||
<div class="flex flex-col sm:flex-row gap-2">
|
|
||||||
<UnlockButton bind:unlocked={claimedWishlistsUnlocked} />
|
|
||||||
</div>
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
{#snippet searchBar()}
|
|
||||||
{#if allClaimedWishlists().length > 0}
|
|
||||||
<SearchBar bind:value={claimedWishlistsSearch} />
|
|
||||||
{/if}
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
{#snippet children(wishlist)}
|
|
||||||
<WishlistCard
|
|
||||||
title={wishlist.title}
|
|
||||||
description={getWishlistDescription(wishlist)}
|
|
||||||
itemCount={wishlist.items?.length || 0}
|
|
||||||
color={wishlist.color}
|
|
||||||
>
|
|
||||||
<div class="flex gap-2 flex-wrap">
|
<div class="flex gap-2 flex-wrap">
|
||||||
<!-- For claimed wishlists, use saved favorite toggle -->
|
|
||||||
<form method="POST" action="?/toggleSavedFavorite" use:enhance={() => {
|
<form method="POST" action="?/toggleSavedFavorite" use:enhance={() => {
|
||||||
return async ({ update }) => {
|
return async ({ update }) => {
|
||||||
await update({ reset: false });
|
await update({ reset: false });
|
||||||
@@ -291,8 +131,7 @@
|
|||||||
>
|
>
|
||||||
{t.dashboard.copyLink}
|
{t.dashboard.copyLink}
|
||||||
</Button>
|
</Button>
|
||||||
{#if claimedWishlistsUnlocked}
|
{#if unlocked}
|
||||||
<!-- Add unclaim button for claimed wishlists -->
|
|
||||||
<form method="POST" action="?/unsaveWishlist" use:enhance={() => {
|
<form method="POST" action="?/unsaveWishlist" use:enhance={() => {
|
||||||
return async ({ update }) => {
|
return async ({ update }) => {
|
||||||
await update({ reset: false });
|
await update({ reset: false });
|
||||||
@@ -305,37 +144,18 @@
|
|||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</WishlistCard>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</WishlistGrid>
|
</WishlistSection>
|
||||||
{/if}
|
|
||||||
|
|
||||||
<WishlistGrid
|
<!-- Saved Wishlists Section -->
|
||||||
|
<WishlistSection
|
||||||
title={t.dashboard.savedWishlists}
|
title={t.dashboard.savedWishlists}
|
||||||
description={t.dashboard.savedWishlistsDescription}
|
description={t.dashboard.savedWishlistsDescription}
|
||||||
items={sortedSavedWishlists() || []}
|
items={savedWishlists()}
|
||||||
emptyMessage={t.dashboard.emptySavedWishlists}
|
emptyMessage={t.dashboard.emptySavedWishlists}
|
||||||
emptyDescription={t.dashboard.emptySavedWishlistsDescription}
|
emptyDescription={t.dashboard.emptySavedWishlistsDescription}
|
||||||
>
|
>
|
||||||
{#snippet headerAction()}
|
{#snippet actions(saved, unlocked)}
|
||||||
<div class="flex flex-col sm:flex-row gap-2">
|
|
||||||
<UnlockButton bind:unlocked={savedWishlistsUnlocked} />
|
|
||||||
</div>
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
{#snippet searchBar()}
|
|
||||||
{#if (data.savedWishlists || []).filter(saved => !saved.wishlist?.ownerToken).length > 0}
|
|
||||||
<SearchBar bind:value={savedWishlistsSearch} />
|
|
||||||
{/if}
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
{#snippet children(saved)}
|
|
||||||
<WishlistCard
|
|
||||||
title={saved.wishlist?.title}
|
|
||||||
description={getSavedWishlistDescription(saved)}
|
|
||||||
itemCount={saved.wishlist?.items?.length || 0}
|
|
||||||
color={saved.wishlist?.color}
|
|
||||||
>
|
|
||||||
<div class="flex gap-2 flex-wrap">
|
<div class="flex gap-2 flex-wrap">
|
||||||
<form method="POST" action="?/toggleSavedFavorite" use:enhance={() => {
|
<form method="POST" action="?/toggleSavedFavorite" use:enhance={() => {
|
||||||
return async ({ update }) => {
|
return async ({ update }) => {
|
||||||
@@ -354,7 +174,7 @@
|
|||||||
>
|
>
|
||||||
{t.dashboard.viewWishlist}
|
{t.dashboard.viewWishlist}
|
||||||
</Button>
|
</Button>
|
||||||
{#if savedWishlistsUnlocked}
|
{#if unlocked}
|
||||||
<form method="POST" action="?/unsaveWishlist" use:enhance={() => {
|
<form method="POST" action="?/unsaveWishlist" use:enhance={() => {
|
||||||
return async ({ update }) => {
|
return async ({ update }) => {
|
||||||
await update({ reset: false });
|
await update({ reset: false });
|
||||||
@@ -367,7 +187,6 @@
|
|||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</WishlistCard>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</WishlistGrid>
|
</WishlistSection>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
|
|||||||
Reference in New Issue
Block a user