fbla26/src/lib/components/custom/item-listing.svelte
2026-02-07 00:45:35 -06:00

144 lines
4.3 KiB
Svelte

<script lang="ts">
import type { Item } from '$lib/types/item';
import { Badge } from '$lib/components/ui/badge';
import LocationIcon from '@lucide/svelte/icons/map-pinned';
import CheckIcon from '@lucide/svelte/icons/check';
import XIcon from '@lucide/svelte/icons/x';
import PencilIcon from '@lucide/svelte/icons/pencil';
import NotebookPenIcon from '@lucide/svelte/icons/notebook-pen';
import TrashIcon from '@lucide/svelte/icons/trash';
import StarIcon from '@lucide/svelte/icons/star';
import ArchiveRestoreIcon from '@lucide/svelte/icons/archive-restore';
import { Button } from '$lib/components/ui/button';
import * as Tooltip from '$lib/components/ui/tooltip';
import { dateFormatOptions } from '$lib/shared';
import { approveDenyItem, restoreClaimedItem } from '$lib/db/items.remote';
import { invalidateAll } from '$app/navigation';
import NoImagePlaceholder from './no-image-placeholder.svelte';
export let item: Item = <Item>{};
export let admin = false;
export let editCallback: (item: Item) => void;
export let inquireCallback: (item: Item) => void;
export let claimCallback: (item: Item) => void;
let timeSincePosted: number | string = (new Date().getTime() - item.foundDate.getTime()) / 1000 / 60 / 60 / 24; // days
if (timeSincePosted < 1) {
timeSincePosted = '<1';
} else {
timeSincePosted = Math.round(timeSincePosted);
}
</script>
<div
class="h-full bg-card text-card-foreground flex flex-col gap-2 rounded-xl border shadow-sm max-w-sm overflow-hidden min-w-2xs">
{#if item.image}
<img src="https://fbla26.marinodev.com/uploads/{item.id}.jpg" class="object-cover min-h-48 max-h-48"
alt="Lost item">
{:else}
<div class="min-h-48 w-full bg-accent flex flex-col justify-center">
<div class="justify-center flex ">
<NoImagePlaceholder className="" />
</div>
<p class="text-center mt-4">No image available</p>
</div>
{/if}
<div class="flex-col flex h-full px-2 pb-2">
<!-- <div class="font-bold inline-block">{item.title}</div>-->
<!-- <div class="inline-block">-->
<div>
{#if item.transferred}
<Badge variant="secondary" class="inline-block">In Lost & Found</Badge>
{:else}
<Badge variant="secondary" class="inline-block">With Finder</Badge>
{/if}
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger
>
<Badge variant="outline" class="inline-block">{timeSincePosted}
day{(timeSincePosted === 1 || timeSincePosted === '<1') ? '' : 's'} ago
</Badge>
</Tooltip.Trigger
>
<Tooltip.Content>
<p>{item.foundDate.toLocaleDateString('en-US', dateFormatOptions)}</p>
</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
</div>
<div class="flex-1">{item.description}</div>
{#if item.foundLocation}
<div class="mt-2">
<LocationIcon class="float-left mr-1" size={24} />
<div>{item.foundLocation}</div>
</div>
{/if}
{#if admin}
<div class="mt-2 justify-between flex">
{#if item.approvedDate === null}
<Button variant="ghost" class="text-positive"
onclick={async () => {await approveDenyItem({id: item.id, approved: true});
invalidateAll()}}>
<CheckIcon />
Approve
</Button>
<Button variant="ghost" class="text-destructive"
onclick={async () => {await approveDenyItem({id: item.id, approved: false});
invalidateAll()}}>
<XIcon />
Deny
</Button>
{/if}
{#if item.claimedDate === null}
<Button variant="ghost" class="text-action"
onclick={() => {editCallback(item)}}>
<PencilIcon />
Manage
</Button>
{:else}
<Button variant="ghost" class="text-destructive"
onclick={async () => {await approveDenyItem({id: item.id, approved: false});
invalidateAll()}}>
<TrashIcon />
Delete
</Button>
<Button variant="ghost" class="text-action"
onclick={async () => {await restoreClaimedItem(item.id);
invalidateAll()}}>
<ArchiveRestoreIcon />
Restore
</Button>
{/if}
</div>
{:else}
<div class="mt-2 justify-between flex">
<Button variant="ghost" class="text-action"
onclick={() => {inquireCallback(item)}}>
<NotebookPenIcon />
Inquire
</Button>
<Button variant="ghost" class="text-primary"
onclick={() => {claimCallback(item)}}>
<StarIcon />
Claim
</Button>
</div>
{/if}
</div>
</div>