add: multiple ownership of wishlists
This commit is contained in:
@@ -13,8 +13,23 @@
|
||||
|
||||
const t = $derived(languageStore.t);
|
||||
|
||||
// Combine owned and claimed wishlists for "My Wishlists"
|
||||
const allMyWishlists = $derived(() => {
|
||||
const owned = data.wishlists || [];
|
||||
// Only include claimed wishlists (those with ownerToken, meaning they were claimed via edit link)
|
||||
const claimed = (data.savedWishlists || [])
|
||||
.filter(saved => saved.wishlist?.ownerToken) // Has edit access
|
||||
.map(saved => ({
|
||||
...saved.wishlist,
|
||||
isFavorite: saved.isFavorite,
|
||||
isClaimed: true,
|
||||
savedId: saved.id
|
||||
}));
|
||||
return [...owned, ...claimed];
|
||||
});
|
||||
|
||||
const sortedWishlists = $derived(
|
||||
[...data.wishlists].sort((a, b) => {
|
||||
[...allMyWishlists()].sort((a, b) => {
|
||||
if (a.isFavorite && !b.isFavorite) return -1;
|
||||
if (!a.isFavorite && b.isFavorite) return 1;
|
||||
|
||||
@@ -32,8 +47,11 @@
|
||||
})
|
||||
);
|
||||
|
||||
// Saved wishlists are those WITHOUT ownerToken (saved from public view only)
|
||||
const sortedSavedWishlists = $derived(
|
||||
[...data.savedWishlists].sort((a, b) => {
|
||||
[...(data.savedWishlists || [])]
|
||||
.filter(saved => !saved.wishlist?.ownerToken) // No edit access
|
||||
.sort((a, b) => {
|
||||
if (a.isFavorite && !b.isFavorite) return -1;
|
||||
if (!a.isFavorite && b.isFavorite) return 1;
|
||||
|
||||
@@ -107,6 +125,21 @@
|
||||
color={wishlist.color}
|
||||
>
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
{#if wishlist.isClaimed}
|
||||
<!-- For claimed wishlists, use saved favorite toggle -->
|
||||
<form method="POST" action="?/toggleSavedFavorite" use:enhance={() => {
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
};
|
||||
}}>
|
||||
<input type="hidden" name="savedWishlistId" value={wishlist.savedId} />
|
||||
<input type="hidden" name="isFavorite" value={wishlist.isFavorite} />
|
||||
<Button type="submit" size="sm" variant="outline">
|
||||
<Star class={wishlist.isFavorite ? "fill-yellow-500 text-yellow-500" : ""} />
|
||||
</Button>
|
||||
</form>
|
||||
{:else}
|
||||
<!-- For owned wishlists, use regular favorite toggle -->
|
||||
<form method="POST" action="?/toggleFavorite" use:enhance={() => {
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
@@ -118,6 +151,7 @@
|
||||
<Star class={wishlist.isFavorite ? "fill-yellow-500 text-yellow-500" : ""} />
|
||||
</Button>
|
||||
</form>
|
||||
{/if}
|
||||
<Button
|
||||
size="sm"
|
||||
onclick={() => (window.location.href = `/wishlist/${wishlist.ownerToken}/edit`)}
|
||||
@@ -135,6 +169,19 @@
|
||||
>
|
||||
{t.dashboard.copyLink}
|
||||
</Button>
|
||||
{#if wishlist.isClaimed}
|
||||
<!-- Add unclaim button for claimed wishlists -->
|
||||
<form method="POST" action="?/unsaveWishlist" use:enhance={() => {
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
};
|
||||
}}>
|
||||
<input type="hidden" name="savedWishlistId" value={wishlist.savedId} />
|
||||
<Button type="submit" size="sm" variant="destructive">
|
||||
{t.dashboard.unsave}
|
||||
</Button>
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
</WishlistCard>
|
||||
{/snippet}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { PageServerLoad, Actions } from './$types';
|
||||
import { db } from '$lib/server/db';
|
||||
import { wishlists, items } from '$lib/server/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { wishlists, items, savedWishlists } from '$lib/server/schema';
|
||||
import { eq, and } from 'drizzle-orm';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, locals }) => {
|
||||
const wishlist = await db.query.wishlists.findFirst({
|
||||
@@ -19,11 +19,29 @@ export const load: PageServerLoad = async ({ params, locals }) => {
|
||||
}
|
||||
|
||||
const session = await locals.auth();
|
||||
let hasClaimed = false;
|
||||
let isOwner = false;
|
||||
|
||||
if (session?.user?.id) {
|
||||
// Check if user is the owner
|
||||
isOwner = wishlist.userId === session.user.id;
|
||||
|
||||
// Check if user has claimed this wishlist
|
||||
const savedWishlist = await db.query.savedWishlists.findFirst({
|
||||
where: and(
|
||||
eq(savedWishlists.userId, session.user.id),
|
||||
eq(savedWishlists.wishlistId, wishlist.id)
|
||||
)
|
||||
});
|
||||
hasClaimed = !!savedWishlist;
|
||||
}
|
||||
|
||||
return {
|
||||
wishlist,
|
||||
publicUrl: `/wishlist/${wishlist.publicToken}`,
|
||||
isAuthenticated: !!session?.user
|
||||
isAuthenticated: !!session?.user,
|
||||
hasClaimed,
|
||||
isOwner
|
||||
};
|
||||
};
|
||||
|
||||
@@ -224,5 +242,66 @@ export const actions: Actions = {
|
||||
.where(eq(wishlists.id, wishlist.id));
|
||||
|
||||
return { success: true };
|
||||
},
|
||||
|
||||
claimWishlist: async ({ params, locals }) => {
|
||||
const session = await locals.auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
throw error(401, 'You must be signed in to claim a wishlist');
|
||||
}
|
||||
|
||||
const wishlist = await db.query.wishlists.findFirst({
|
||||
where: eq(wishlists.ownerToken, params.token)
|
||||
});
|
||||
|
||||
if (!wishlist) {
|
||||
throw error(404, 'Wishlist not found');
|
||||
}
|
||||
|
||||
// Check if already claimed
|
||||
const existing = await db.query.savedWishlists.findFirst({
|
||||
where: and(
|
||||
eq(savedWishlists.userId, session.user.id),
|
||||
eq(savedWishlists.wishlistId, wishlist.id)
|
||||
)
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
return { success: true, message: 'Already claimed' };
|
||||
}
|
||||
|
||||
await db.insert(savedWishlists).values({
|
||||
userId: session.user.id,
|
||||
wishlistId: wishlist.id,
|
||||
isFavorite: false
|
||||
});
|
||||
|
||||
return { success: true, message: 'Wishlist claimed successfully' };
|
||||
},
|
||||
|
||||
unclaimWishlist: async ({ params, locals }) => {
|
||||
const session = await locals.auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
throw error(401, 'You must be signed in');
|
||||
}
|
||||
|
||||
const wishlist = await db.query.wishlists.findFirst({
|
||||
where: eq(wishlists.ownerToken, params.token)
|
||||
});
|
||||
|
||||
if (!wishlist) {
|
||||
throw error(404, 'Wishlist not found');
|
||||
}
|
||||
|
||||
await db.delete(savedWishlists).where(
|
||||
and(
|
||||
eq(savedWishlists.userId, session.user.id),
|
||||
eq(savedWishlists.wishlistId, wishlist.id)
|
||||
)
|
||||
);
|
||||
|
||||
return { success: true, message: 'Wishlist unclaimed' };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -206,6 +206,44 @@
|
||||
ownerUrl="/wishlist/{data.wishlist.ownerToken}/edit"
|
||||
/>
|
||||
|
||||
{#if data.isAuthenticated}
|
||||
<div class="mb-6">
|
||||
{#if data.isOwner}
|
||||
<Button
|
||||
disabled
|
||||
variant="outline"
|
||||
class="w-full md:w-auto opacity-60 cursor-not-allowed"
|
||||
>
|
||||
You Own This Wishlist
|
||||
</Button>
|
||||
<p class="text-sm text-muted-foreground mt-2">
|
||||
This wishlist is already in your dashboard as the owner.
|
||||
</p>
|
||||
{:else}
|
||||
<form
|
||||
method="POST"
|
||||
action={data.hasClaimed ? "?/unclaimWishlist" : "?/claimWishlist"}
|
||||
use:enhance
|
||||
>
|
||||
<Button
|
||||
type="submit"
|
||||
variant={data.hasClaimed ? "outline" : "default"}
|
||||
class="w-full md:w-auto"
|
||||
>
|
||||
{data.hasClaimed ? "Unclaim Wishlist" : "Claim Wishlist"}
|
||||
</Button>
|
||||
</form>
|
||||
<p class="text-sm text-muted-foreground mt-2">
|
||||
{#if data.hasClaimed}
|
||||
You have claimed this wishlist. It will appear in your dashboard.
|
||||
{:else}
|
||||
Claim this wishlist to add it to your dashboard for easy access.
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<WishlistActionButtons
|
||||
bind:rearranging={rearranging}
|
||||
onToggleAddForm={handleToggleAddForm}
|
||||
|
||||
Reference in New Issue
Block a user