Refactor environment variable declarations, enhance image handling in item forms, and update asset references in SvelteKit project for improved functionality and performance.
This commit is contained in:
@@ -12,6 +12,7 @@ export interface StackqItem {
|
||||
Has_Parent: boolean;
|
||||
Parent: string; // relation id
|
||||
Stock: boolean;
|
||||
Image?: string; // file filename
|
||||
created: string;
|
||||
updated: string;
|
||||
expand?: {
|
||||
|
||||
@@ -45,11 +45,13 @@ export const actions: Actions = {
|
||||
const Has_Parent = parseBool(form.get("Has_Parent"));
|
||||
const Parent = (form.get("Parent") as string)?.trim() ?? "";
|
||||
const Stock = parseBool(form.get("Stock"));
|
||||
const imageFileCreate = form.get("Image") as File | null;
|
||||
const hasImage = imageFileCreate && imageFileCreate.size > 0;
|
||||
|
||||
if (!Item) return fail(400, { error: "Item name is required", form: "create" });
|
||||
|
||||
try {
|
||||
await locals.pb.collection(COLLECTION).create({
|
||||
const body: Record<string, unknown> = {
|
||||
Item,
|
||||
SKU,
|
||||
Description,
|
||||
@@ -61,7 +63,9 @@ export const actions: Actions = {
|
||||
Has_Parent: !!Has_Parent,
|
||||
Parent: Parent || null,
|
||||
Stock: !!Stock,
|
||||
});
|
||||
};
|
||||
if (hasImage) body.Image = imageFileCreate;
|
||||
await locals.pb.collection(COLLECTION).create(body);
|
||||
} catch (e: unknown) {
|
||||
const message = e && typeof e === "object" && "message" in e ? String((e as { message: string }).message) : "Create failed";
|
||||
return fail(500, { error: message, form: "create" });
|
||||
@@ -85,11 +89,13 @@ export const actions: Actions = {
|
||||
const Has_Parent = parseBool(form.get("Has_Parent"));
|
||||
const Parent = (form.get("Parent") as string)?.trim() ?? "";
|
||||
const Stock = parseBool(form.get("Stock"));
|
||||
const Image = form.get("Image") as File | null;
|
||||
const imageFile = Image && Image.size > 0 ? Image : undefined;
|
||||
|
||||
if (!Item) return fail(400, { error: "Item name is required", form: "update" });
|
||||
|
||||
try {
|
||||
await locals.pb.collection(COLLECTION).update(id, {
|
||||
const body: Record<string, unknown> = {
|
||||
Item,
|
||||
SKU,
|
||||
Description,
|
||||
@@ -101,7 +107,9 @@ export const actions: Actions = {
|
||||
Has_Parent: !!Has_Parent,
|
||||
Parent: Parent || null,
|
||||
Stock: !!Stock,
|
||||
});
|
||||
};
|
||||
if (imageFile) body.Image = imageFile;
|
||||
await locals.pb.collection(COLLECTION).update(id, body);
|
||||
} catch (e: unknown) {
|
||||
const message = e && typeof e === "object" && "message" in e ? String((e as { message: string }).message) : "Update failed";
|
||||
return fail(500, { error: message, form: "update" });
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
}
|
||||
|
||||
const items = $derived(data?.items ?? []);
|
||||
const PB_BASE = "https://pocketbase.ccllc.pro";
|
||||
const COLLECTION = "Stackq_Items";
|
||||
function imageUrl(item: StackqItem): string | null {
|
||||
if (!item.Image) return null;
|
||||
return `${PB_BASE}/api/files/${COLLECTION}/${item.id}/${item.Image}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -50,6 +56,7 @@
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head>Image</Table.Head>
|
||||
<Table.Head>Item</Table.Head>
|
||||
<Table.Head>SKU</Table.Head>
|
||||
<Table.Head class="max-w-[200px]">Description</Table.Head>
|
||||
@@ -68,13 +75,25 @@
|
||||
<Table.Body>
|
||||
{#if items.length === 0}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan="13" class="h-24 text-center text-muted-foreground">
|
||||
<Table.Cell colspan="14" class="h-24 text-center text-muted-foreground">
|
||||
No items.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{:else}
|
||||
{#each items as item (item.id)}
|
||||
<Table.Row>
|
||||
<Table.Cell class="w-16">
|
||||
{#if imageUrl(item)}
|
||||
<img
|
||||
src={imageUrl(item)!}
|
||||
alt=""
|
||||
class="size-14 rounded border object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
{:else}
|
||||
<span class="text-muted-foreground text-xs">—</span>
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
<Table.Cell class="font-medium">{item.Item ?? "—"}</Table.Cell>
|
||||
<Table.Cell class="font-mono text-xs">{item.SKU ?? "—"}</Table.Cell>
|
||||
<Table.Cell class="max-w-[200px] truncate" title={item.Description ?? ""}>
|
||||
|
||||
@@ -4,9 +4,15 @@
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { enhance } from "$app/forms";
|
||||
import { Camera, X } from "@lucide/svelte";
|
||||
import { pb } from "$lib/pocketbase";
|
||||
import { UOM_OPTIONS, CATAGORY_OPTIONS, SUB_CATAGORY_OPTIONS } from "$lib/constants/items";
|
||||
import type { StackqItem } from "$lib/types/items";
|
||||
|
||||
const COLLECTION = "Stackq_Items";
|
||||
function itemImageUrl(recordId: string, filename: string): string {
|
||||
return `${pb.baseUrl}/api/files/${COLLECTION}/${recordId}/${filename}`;
|
||||
}
|
||||
|
||||
let {
|
||||
item = null,
|
||||
itemsForParent = [],
|
||||
@@ -141,6 +147,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action={action}
|
||||
enctype="multipart/form-data"
|
||||
use:enhance={() => async ({ update, result }) => {
|
||||
await update();
|
||||
if (result.type === "success" && result.data?.success) {
|
||||
@@ -201,6 +208,21 @@
|
||||
<Input id="Description" name="Description" value={defaultDesc} />
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="Image">Image</Label>
|
||||
{#if isEdit && item?.Image}
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<img
|
||||
src={itemImageUrl(item!.id, item!.Image)}
|
||||
alt=""
|
||||
class="size-20 rounded border object-cover"
|
||||
/>
|
||||
<span class="text-muted-foreground text-sm">Replace:</span>
|
||||
</div>
|
||||
{/if}
|
||||
<Input id="Image" name="Image" type="file" accept="image/*" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="UOM">UOM</Label>
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
const items = $derived(data?.items ?? []);
|
||||
const itemsForParent = $derived(data?.itemsForParent ?? []);
|
||||
|
||||
const PB_BASE = "https://pocketbase.ccllc.pro";
|
||||
const COLLECTION = "Stackq_Items";
|
||||
function imageUrl(item: StackqItem): string | null {
|
||||
if (!item.Image) return null;
|
||||
return `${PB_BASE}/api/files/${COLLECTION}/${item.id}/${item.Image}`;
|
||||
}
|
||||
|
||||
function asList(val: string | string[] | undefined): string[] {
|
||||
if (val == null) return [];
|
||||
return Array.isArray(val) ? val : [val];
|
||||
@@ -92,6 +99,7 @@
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head>Image</Table.Head>
|
||||
<Table.Head>Item</Table.Head>
|
||||
<Table.Head>SKU</Table.Head>
|
||||
<Table.Head class="max-w-[200px]">Description</Table.Head>
|
||||
@@ -111,13 +119,32 @@
|
||||
<Table.Body>
|
||||
{#if items.length === 0}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan="14" class="h-24 text-center text-muted-foreground">
|
||||
<Table.Cell colspan="15" class="h-24 text-center text-muted-foreground">
|
||||
No items. Create one or check PocketBase collection name and auth.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{:else}
|
||||
{#each items as item (item.id)}
|
||||
<Table.Row>
|
||||
<Table.Cell class="w-16">
|
||||
{#if imageUrl(item)}
|
||||
<a
|
||||
href={imageUrl(item)!}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="block overflow-hidden rounded border"
|
||||
>
|
||||
<img
|
||||
src={imageUrl(item)!}
|
||||
alt=""
|
||||
class="size-14 object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
</a>
|
||||
{:else}
|
||||
<span class="text-muted-foreground text-xs">—</span>
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
<Table.Cell class="font-medium">{item.Item ?? "—"}</Table.Cell>
|
||||
<Table.Cell class="font-mono text-xs">{item.SKU ?? "—"}</Table.Cell>
|
||||
<Table.Cell class="max-w-[200px] truncate" title={item.Description ?? ""}>
|
||||
|
||||
Reference in New Issue
Block a user