Refactor receipt handling by removing status options from the server-side logic and simplifying the default status to "New". Update the receipt form to eliminate the status selection, enhancing user experience by focusing on essential fields. Improve image upload handling with WebP conversion support in both receipt creation and editing components.
CI / build (push) Has been skipped
CI / deploy (push) Successful in 1m25s

This commit is contained in:
eewing
2026-02-19 11:19:35 -06:00
parent f51f9c9f81
commit 6e6ad0de05
39 changed files with 259 additions and 242 deletions
@@ -5,7 +5,6 @@ import type { StackqReceipt } from "$lib/types/receipts";
const COLLECTION = "Stackq_Receipts"; const COLLECTION = "Stackq_Receipts";
const STATUS_OPTIONS = ["New", "Data Entered", "Reviewed", "Consolidated"] as const;
const TYPE_OPTIONS = ["Purchase", "Gas"] as const; const TYPE_OPTIONS = ["Purchase", "Gas"] as const;
export const load = async ({ locals }: Parameters<PageServerLoad>[0]) => { export const load = async ({ locals }: Parameters<PageServerLoad>[0]) => {
@@ -29,13 +28,12 @@ export const actions = {
if (!user?.id) return fail(401, { error: "You must be logged in to create a receipt." }); if (!user?.id) return fail(401, { error: "You must be logged in to create a receipt." });
const form = await request.formData(); const form = await request.formData();
const Status = (form.get("Status") as string)?.trim() || "New";
const Type = (form.get("Type") as string)?.trim() || "Purchase"; const Type = (form.get("Type") as string)?.trim() || "Purchase";
const imageFile = form.get("Image") as File | null; const imageFile = form.get("Image") as File | null;
const hasImage = imageFile && imageFile.size > 0; const hasImage = imageFile && imageFile.size > 0;
const body: Record<string, unknown> = { const body: Record<string, unknown> = {
Status: STATUS_OPTIONS.includes(Status as (typeof STATUS_OPTIONS)[number]) ? Status : "New", Status: "New",
Type: TYPE_OPTIONS.includes(Type as (typeof TYPE_OPTIONS)[number]) ? Type : "Purchase", Type: TYPE_OPTIONS.includes(Type as (typeof TYPE_OPTIONS)[number]) ? Type : "Purchase",
User: user.id, User: user.id,
}; };
@@ -48,7 +46,7 @@ export const actions = {
err && typeof err === "object" && "message" in err err && typeof err === "object" && "message" in err
? String((err as { message: string }).message) ? String((err as { message: string }).message)
: "Failed to create receipt."; : "Failed to create receipt.";
return fail(500, { error: message, Status, Type }); return fail(500, { error: message, Type });
} }
return { success: true }; return { success: true };
+7 -7
View File
@@ -1,7 +1,6 @@
import { import {
Icon_default Icon_default
} from "./chunk-MR7TRD3U.js"; } from "./chunk-SK3R2OSP.js";
import "./chunk-2LGM3QYM.js";
import { import {
check_target, check_target,
hmr, hmr,
@@ -10,11 +9,11 @@ import {
snippet, snippet,
spread_props, spread_props,
wrap_snippet wrap_snippet
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
append, append,
comment comment
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
FILENAME, FILENAME,
HMR, HMR,
@@ -23,12 +22,13 @@ import {
noop, noop,
pop, pop,
push push
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-2LGM3QYM.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/check.svelte // node_modules/@lucide/svelte/dist/icons/check.svelte
Check[FILENAME] = "node_modules/@lucide/svelte/dist/icons/check.svelte"; Check[FILENAME] = "node_modules/@lucide/svelte/dist/icons/check.svelte";
+7 -7
View File
@@ -1,7 +1,6 @@
import { import {
Icon_default Icon_default
} from "./chunk-MR7TRD3U.js"; } from "./chunk-SK3R2OSP.js";
import "./chunk-2LGM3QYM.js";
import { import {
check_target, check_target,
hmr, hmr,
@@ -10,11 +9,11 @@ import {
snippet, snippet,
spread_props, spread_props,
wrap_snippet wrap_snippet
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
append, append,
comment comment
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
FILENAME, FILENAME,
HMR, HMR,
@@ -23,12 +22,13 @@ import {
noop, noop,
pop, pop,
push push
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-2LGM3QYM.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/chevron-right.svelte // node_modules/@lucide/svelte/dist/icons/chevron-right.svelte
Chevron_right[FILENAME] = "node_modules/@lucide/svelte/dist/icons/chevron-right.svelte"; Chevron_right[FILENAME] = "node_modules/@lucide/svelte/dist/icons/chevron-right.svelte";
+7 -7
View File
@@ -1,7 +1,6 @@
import { import {
Icon_default Icon_default
} from "./chunk-MR7TRD3U.js"; } from "./chunk-SK3R2OSP.js";
import "./chunk-2LGM3QYM.js";
import { import {
check_target, check_target,
hmr, hmr,
@@ -10,11 +9,11 @@ import {
snippet, snippet,
spread_props, spread_props,
wrap_snippet wrap_snippet
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
append, append,
comment comment
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
FILENAME, FILENAME,
HMR, HMR,
@@ -23,12 +22,13 @@ import {
noop, noop,
pop, pop,
push push
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-2LGM3QYM.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/circle.svelte // node_modules/@lucide/svelte/dist/icons/circle.svelte
Circle[FILENAME] = "node_modules/@lucide/svelte/dist/icons/circle.svelte"; Circle[FILENAME] = "node_modules/@lucide/svelte/dist/icons/circle.svelte";
+7 -7
View File
@@ -1,7 +1,6 @@
import { import {
Icon_default Icon_default
} from "./chunk-MR7TRD3U.js"; } from "./chunk-SK3R2OSP.js";
import "./chunk-2LGM3QYM.js";
import { import {
check_target, check_target,
hmr, hmr,
@@ -10,11 +9,11 @@ import {
snippet, snippet,
spread_props, spread_props,
wrap_snippet wrap_snippet
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
append, append,
comment comment
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
FILENAME, FILENAME,
HMR, HMR,
@@ -23,12 +22,13 @@ import {
noop, noop,
pop, pop,
push push
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-2LGM3QYM.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/minus.svelte // node_modules/@lucide/svelte/dist/icons/minus.svelte
Minus[FILENAME] = "node_modules/@lucide/svelte/dist/icons/minus.svelte"; Minus[FILENAME] = "node_modules/@lucide/svelte/dist/icons/minus.svelte";
+7 -7
View File
@@ -1,7 +1,6 @@
import { import {
Icon_default Icon_default
} from "./chunk-MR7TRD3U.js"; } from "./chunk-SK3R2OSP.js";
import "./chunk-2LGM3QYM.js";
import { import {
check_target, check_target,
hmr, hmr,
@@ -10,11 +9,11 @@ import {
snippet, snippet,
spread_props, spread_props,
wrap_snippet wrap_snippet
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
append, append,
comment comment
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
FILENAME, FILENAME,
HMR, HMR,
@@ -23,12 +22,13 @@ import {
noop, noop,
pop, pop,
push push
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-2LGM3QYM.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/x.svelte // node_modules/@lucide/svelte/dist/icons/x.svelte
X[FILENAME] = "node_modules/@lucide/svelte/dist/icons/x.svelte"; X[FILENAME] = "node_modules/@lucide/svelte/dist/icons/x.svelte";
+63 -57
View File
@@ -2,30 +2,30 @@
"hash": "e1b6cade", "hash": "e1b6cade",
"configHash": "441370a6", "configHash": "441370a6",
"lockfileHash": "9401e68b", "lockfileHash": "9401e68b",
"browserHash": "04aeb2a4", "browserHash": "c578848f",
"optimized": { "optimized": {
"svelte": { "svelte": {
"src": "../../svelte/src/index-client.js", "src": "../../svelte/src/index-client.js",
"file": "svelte.js", "file": "svelte.js",
"fileHash": "1ddbf175", "fileHash": "836a0569",
"needsInterop": false "needsInterop": false
}, },
"svelte/animate": { "svelte/animate": {
"src": "../../svelte/src/animate/index.js", "src": "../../svelte/src/animate/index.js",
"file": "svelte_animate.js", "file": "svelte_animate.js",
"fileHash": "d9d56906", "fileHash": "a84129da",
"needsInterop": false "needsInterop": false
}, },
"svelte/attachments": { "svelte/attachments": {
"src": "../../svelte/src/attachments/index.js", "src": "../../svelte/src/attachments/index.js",
"file": "svelte_attachments.js", "file": "svelte_attachments.js",
"fileHash": "c15aecdf", "fileHash": "2242f01b",
"needsInterop": false "needsInterop": false
}, },
"svelte/easing": { "svelte/easing": {
"src": "../../svelte/src/easing/index.js", "src": "../../svelte/src/easing/index.js",
"file": "svelte_easing.js", "file": "svelte_easing.js",
"fileHash": "e5864893", "fileHash": "0123c7d6",
"needsInterop": false "needsInterop": false
}, },
"svelte/internal": { "svelte/internal": {
@@ -37,184 +37,184 @@
"svelte/internal/client": { "svelte/internal/client": {
"src": "../../svelte/src/internal/client/index.js", "src": "../../svelte/src/internal/client/index.js",
"file": "svelte_internal_client.js", "file": "svelte_internal_client.js",
"fileHash": "a252d832", "fileHash": "bf7d241e",
"needsInterop": false "needsInterop": false
}, },
"svelte/internal/disclose-version": { "svelte/internal/disclose-version": {
"src": "../../svelte/src/internal/disclose-version.js", "src": "../../svelte/src/internal/disclose-version.js",
"file": "svelte_internal_disclose-version.js", "file": "svelte_internal_disclose-version.js",
"fileHash": "4acec545", "fileHash": "5ac70717",
"needsInterop": false "needsInterop": false
}, },
"svelte/internal/flags/async": { "svelte/internal/flags/async": {
"src": "../../svelte/src/internal/flags/async.js", "src": "../../svelte/src/internal/flags/async.js",
"file": "svelte_internal_flags_async.js", "file": "svelte_internal_flags_async.js",
"fileHash": "cb994494", "fileHash": "1b74e6fc",
"needsInterop": false "needsInterop": false
}, },
"svelte/internal/flags/legacy": { "svelte/internal/flags/legacy": {
"src": "../../svelte/src/internal/flags/legacy.js", "src": "../../svelte/src/internal/flags/legacy.js",
"file": "svelte_internal_flags_legacy.js", "file": "svelte_internal_flags_legacy.js",
"fileHash": "76de734a", "fileHash": "1c59baa5",
"needsInterop": false "needsInterop": false
}, },
"svelte/internal/flags/tracing": { "svelte/internal/flags/tracing": {
"src": "../../svelte/src/internal/flags/tracing.js", "src": "../../svelte/src/internal/flags/tracing.js",
"file": "svelte_internal_flags_tracing.js", "file": "svelte_internal_flags_tracing.js",
"fileHash": "945a287e", "fileHash": "6a43fbc1",
"needsInterop": false "needsInterop": false
}, },
"svelte/legacy": { "svelte/legacy": {
"src": "../../svelte/src/legacy/legacy-client.js", "src": "../../svelte/src/legacy/legacy-client.js",
"file": "svelte_legacy.js", "file": "svelte_legacy.js",
"fileHash": "d42e96f3", "fileHash": "f44ad964",
"needsInterop": false "needsInterop": false
}, },
"svelte/motion": { "svelte/motion": {
"src": "../../svelte/src/motion/index.js", "src": "../../svelte/src/motion/index.js",
"file": "svelte_motion.js", "file": "svelte_motion.js",
"fileHash": "d899f28f", "fileHash": "eed1a42f",
"needsInterop": false "needsInterop": false
}, },
"svelte/reactivity": { "svelte/reactivity": {
"src": "../../svelte/src/reactivity/index-client.js", "src": "../../svelte/src/reactivity/index-client.js",
"file": "svelte_reactivity.js", "file": "svelte_reactivity.js",
"fileHash": "78a01aef", "fileHash": "8addd267",
"needsInterop": false "needsInterop": false
}, },
"svelte/reactivity/window": { "svelte/reactivity/window": {
"src": "../../svelte/src/reactivity/window/index.js", "src": "../../svelte/src/reactivity/window/index.js",
"file": "svelte_reactivity_window.js", "file": "svelte_reactivity_window.js",
"fileHash": "8e4d19b4", "fileHash": "cb259eae",
"needsInterop": false "needsInterop": false
}, },
"svelte/store": { "svelte/store": {
"src": "../../svelte/src/store/index-client.js", "src": "../../svelte/src/store/index-client.js",
"file": "svelte_store.js", "file": "svelte_store.js",
"fileHash": "daa71f26", "fileHash": "8719f5c5",
"needsInterop": false "needsInterop": false
}, },
"svelte/transition": { "svelte/transition": {
"src": "../../svelte/src/transition/index.js", "src": "../../svelte/src/transition/index.js",
"file": "svelte_transition.js", "file": "svelte_transition.js",
"fileHash": "2ba3c5f3", "fileHash": "6d4c0f07",
"needsInterop": false "needsInterop": false
}, },
"svelte/events": { "svelte/events": {
"src": "../../svelte/src/events/index.js", "src": "../../svelte/src/events/index.js",
"file": "svelte_events.js", "file": "svelte_events.js",
"fileHash": "4f1aa8f8", "fileHash": "ec738ae4",
"needsInterop": false "needsInterop": false
}, },
"svelte > clsx": { "svelte > clsx": {
"src": "../../clsx/dist/clsx.mjs", "src": "../../clsx/dist/clsx.mjs",
"file": "svelte___clsx.js", "file": "svelte___clsx.js",
"fileHash": "dd6a46d5", "fileHash": "a84375a2",
"needsInterop": false "needsInterop": false
}, },
"@lucide/svelte/icons/check": { "@lucide/svelte/icons/check": {
"src": "../../@lucide/svelte/dist/icons/check.js", "src": "../../@lucide/svelte/dist/icons/check.js",
"file": "@lucide_svelte_icons_check.js", "file": "@lucide_svelte_icons_check.js",
"fileHash": "aed21143", "fileHash": "cc59c42d",
"needsInterop": false "needsInterop": false
}, },
"@lucide/svelte/icons/chevron-right": { "@lucide/svelte/icons/chevron-right": {
"src": "../../@lucide/svelte/dist/icons/chevron-right.js", "src": "../../@lucide/svelte/dist/icons/chevron-right.js",
"file": "@lucide_svelte_icons_chevron-right.js", "file": "@lucide_svelte_icons_chevron-right.js",
"fileHash": "fad53529", "fileHash": "4ebfe37c",
"needsInterop": false "needsInterop": false
}, },
"@lucide/svelte/icons/circle": { "@lucide/svelte/icons/circle": {
"src": "../../@lucide/svelte/dist/icons/circle.js", "src": "../../@lucide/svelte/dist/icons/circle.js",
"file": "@lucide_svelte_icons_circle.js", "file": "@lucide_svelte_icons_circle.js",
"fileHash": "bf331329", "fileHash": "c9116309",
"needsInterop": false "needsInterop": false
}, },
"@lucide/svelte/icons/minus": { "@lucide/svelte/icons/minus": {
"src": "../../@lucide/svelte/dist/icons/minus.js", "src": "../../@lucide/svelte/dist/icons/minus.js",
"file": "@lucide_svelte_icons_minus.js", "file": "@lucide_svelte_icons_minus.js",
"fileHash": "c3ee1ff6", "fileHash": "e38affc6",
"needsInterop": false "needsInterop": false
}, },
"@lucide/svelte/icons/x": { "@lucide/svelte/icons/x": {
"src": "../../@lucide/svelte/dist/icons/x.js", "src": "../../@lucide/svelte/dist/icons/x.js",
"file": "@lucide_svelte_icons_x.js", "file": "@lucide_svelte_icons_x.js",
"fileHash": "e411e45f", "fileHash": "dd4ef7b8",
"needsInterop": false "needsInterop": false
}, },
"barcode-detector-api-polyfill": { "barcode-detector-api-polyfill": {
"src": "../../barcode-detector-api-polyfill/esm/index.js", "src": "../../barcode-detector-api-polyfill/esm/index.js",
"file": "barcode-detector-api-polyfill.js", "file": "barcode-detector-api-polyfill.js",
"fileHash": "6c03744a", "fileHash": "e171d6a3",
"needsInterop": false "needsInterop": false
}, },
"bits-ui": { "bits-ui": {
"src": "../../bits-ui/dist/index.js", "src": "../../bits-ui/dist/index.js",
"file": "bits-ui.js", "file": "bits-ui.js",
"fileHash": "4faefbe8", "fileHash": "79f12900",
"needsInterop": false "needsInterop": false
}, },
"clsx": { "clsx": {
"src": "../../clsx/dist/clsx.mjs", "src": "../../clsx/dist/clsx.mjs",
"file": "clsx.js", "file": "clsx.js",
"fileHash": "41f586d2", "fileHash": "2d2f5d80",
"needsInterop": false "needsInterop": false
}, },
"devalue": { "devalue": {
"src": "../../devalue/index.js", "src": "../../devalue/index.js",
"file": "devalue.js", "file": "devalue.js",
"fileHash": "3717d88b", "fileHash": "d36225a1",
"needsInterop": false "needsInterop": false
}, },
"esm-env": { "esm-env": {
"src": "../../esm-env/index.js", "src": "../../esm-env/index.js",
"file": "esm-env.js", "file": "esm-env.js",
"fileHash": "d7bf04c9", "fileHash": "b2a3e5c0",
"needsInterop": false "needsInterop": false
}, },
"pocketbase": { "pocketbase": {
"src": "../../pocketbase/dist/pocketbase.es.mjs", "src": "../../pocketbase/dist/pocketbase.es.mjs",
"file": "pocketbase.js", "file": "pocketbase.js",
"fileHash": "8025416e", "fileHash": "d86e8c93",
"needsInterop": false "needsInterop": false
}, },
"tailwind-merge": { "tailwind-merge": {
"src": "../../tailwind-merge/dist/bundle-mjs.mjs", "src": "../../tailwind-merge/dist/bundle-mjs.mjs",
"file": "tailwind-merge.js", "file": "tailwind-merge.js",
"fileHash": "f66be4a7", "fileHash": "5a4842de",
"needsInterop": false "needsInterop": false
}, },
"tailwind-variants": { "tailwind-variants": {
"src": "../../tailwind-variants/dist/index.js", "src": "../../tailwind-variants/dist/index.js",
"file": "tailwind-variants.js", "file": "tailwind-variants.js",
"fileHash": "b33ed3b9", "fileHash": "af3e226f",
"needsInterop": false "needsInterop": false
}, },
"@lucide/svelte/icons/chevron-down": { "@lucide/svelte/icons/chevron-down": {
"src": "../../@lucide/svelte/dist/icons/chevron-down.js", "src": "../../@lucide/svelte/dist/icons/chevron-down.js",
"file": "@lucide_svelte_icons_chevron-down.js", "file": "@lucide_svelte_icons_chevron-down.js",
"fileHash": "dfeee67b", "fileHash": "c086c4f6",
"needsInterop": false "needsInterop": false
}, },
"@lucide/svelte/icons/chevron-up": { "@lucide/svelte/icons/chevron-up": {
"src": "../../@lucide/svelte/dist/icons/chevron-up.js", "src": "../../@lucide/svelte/dist/icons/chevron-up.js",
"file": "@lucide_svelte_icons_chevron-up.js", "file": "@lucide_svelte_icons_chevron-up.js",
"fileHash": "dda66014", "fileHash": "8f687e14",
"needsInterop": false "needsInterop": false
},
"heic2any": {
"src": "../../heic2any/dist/heic2any.js",
"file": "heic2any.js",
"fileHash": "fb3f1ac6",
"needsInterop": true
} }
}, },
"chunks": { "chunks": {
"chunk-HRPYXN4O": { "chunk-2KB4Y67V": {
"file": "chunk-HRPYXN4O.js" "file": "chunk-2KB4Y67V.js"
}, },
"chunk-YERFD2CZ": { "chunk-UKQGYTAZ": {
"file": "chunk-YERFD2CZ.js" "file": "chunk-UKQGYTAZ.js"
},
"chunk-GBET5VCG": {
"file": "chunk-GBET5VCG.js"
},
"chunk-YSF5ZXQP": {
"file": "chunk-YSF5ZXQP.js"
}, },
"chunk-7RQDXF5S": { "chunk-7RQDXF5S": {
"file": "chunk-7RQDXF5S.js" "file": "chunk-7RQDXF5S.js"
@@ -222,35 +222,41 @@
"chunk-MZVN5SDE": { "chunk-MZVN5SDE": {
"file": "chunk-MZVN5SDE.js" "file": "chunk-MZVN5SDE.js"
}, },
"chunk-MR7TRD3U": { "chunk-SK3R2OSP": {
"file": "chunk-MR7TRD3U.js" "file": "chunk-SK3R2OSP.js"
}, },
"chunk-2LGM3QYM": { "chunk-HRPYXN4O": {
"file": "chunk-2LGM3QYM.js" "file": "chunk-HRPYXN4O.js"
}, },
"chunk-LDPLLRRU": { "chunk-XGKSMLPM": {
"file": "chunk-LDPLLRRU.js" "file": "chunk-XGKSMLPM.js"
}, },
"chunk-UKTTYZCO": { "chunk-7XW5QO7S": {
"file": "chunk-UKTTYZCO.js" "file": "chunk-7XW5QO7S.js"
}, },
"chunk-UWLXLUJC": { "chunk-SWXNV5Y3": {
"file": "chunk-UWLXLUJC.js" "file": "chunk-SWXNV5Y3.js"
}, },
"chunk-XWATFG4W": { "chunk-XWATFG4W": {
"file": "chunk-XWATFG4W.js" "file": "chunk-XWATFG4W.js"
}, },
"chunk-U7P2NEEE": {
"file": "chunk-U7P2NEEE.js"
},
"chunk-HNWPC2PS": { "chunk-HNWPC2PS": {
"file": "chunk-HNWPC2PS.js" "file": "chunk-HNWPC2PS.js"
}, },
"chunk-OHYQYV5R": { "chunk-OHYQYV5R": {
"file": "chunk-OHYQYV5R.js" "file": "chunk-OHYQYV5R.js"
}, },
"chunk-U7P2NEEE": { "chunk-2LGM3QYM": {
"file": "chunk-U7P2NEEE.js" "file": "chunk-2LGM3QYM.js"
}, },
"chunk-X4VJQ2O3": { "chunk-YERFD2CZ": {
"file": "chunk-X4VJQ2O3.js" "file": "chunk-YERFD2CZ.js"
},
"chunk-LYA4E26T": {
"file": "chunk-LYA4E26T.js"
} }
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
import { import {
__publicField __publicField
} from "./chunk-X4VJQ2O3.js"; } from "./chunk-LYA4E26T.js";
// node_modules/ts-custom-error/dist/custom-error.mjs // node_modules/ts-custom-error/dist/custom-error.mjs
function fixProto(target, prototype) { function fixProto(target, prototype) {
+10 -10
View File
@@ -1,10 +1,9 @@
import { import {
SvelteMap SvelteMap
} from "./chunk-GBET5VCG.js"; } from "./chunk-2KB4Y67V.js";
import "./chunk-YSF5ZXQP.js"; import "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js"; import "./chunk-7RQDXF5S.js";
import "./chunk-MZVN5SDE.js"; import "./chunk-MZVN5SDE.js";
import "./chunk-2LGM3QYM.js";
import { import {
add_locations, add_locations,
append_styles, append_styles,
@@ -39,7 +38,7 @@ import {
validate_snippet_args, validate_snippet_args,
validate_void_dynamic_element, validate_void_dynamic_element,
wrap_snippet wrap_snippet
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
append, append,
comment, comment,
@@ -50,7 +49,7 @@ import {
set_text, set_text,
text, text,
unmount unmount
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
FILENAME, FILENAME,
HMR, HMR,
@@ -86,15 +85,16 @@ import {
user_derived, user_derived,
user_effect, user_effect,
user_pre_effect user_pre_effect
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import {
clsx
} from "./chunk-U7P2NEEE.js";
import { import {
true_default true_default
} from "./chunk-HNWPC2PS.js"; } from "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import { import "./chunk-2LGM3QYM.js";
clsx
} from "./chunk-U7P2NEEE.js";
import { import {
__export, __export,
__privateAdd, __privateAdd,
@@ -103,7 +103,7 @@ import {
__privateSet, __privateSet,
__privateWrapper, __privateWrapper,
__publicField __publicField
} from "./chunk-X4VJQ2O3.js"; } from "./chunk-LYA4E26T.js";
// node_modules/bits-ui/dist/bits/accordion/exports.js // node_modules/bits-ui/dist/bits/accordion/exports.js
var exports_exports = {}; var exports_exports = {};
-37
View File
@@ -1,37 +0,0 @@
var __defProp = Object.defineProperty;
var __getProtoOf = Object.getPrototypeOf;
var __reflectGet = Reflect.get;
var __typeError = (msg) => {
throw TypeError(msg);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
var __privateWrapper = (obj, member, setter, getter) => ({
set _(value) {
__privateSet(obj, member, value, setter);
},
get _() {
return __privateGet(obj, member, getter);
}
});
var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
export {
__export,
__publicField,
__privateGet,
__privateAdd,
__privateSet,
__privateMethod,
__privateWrapper,
__superGet
};
-7
View File
@@ -1,7 +0,0 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+1 -1
View File
@@ -2,7 +2,7 @@ import {
clsx, clsx,
clsx_default clsx_default
} from "./chunk-U7P2NEEE.js"; } from "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
export { export {
clsx, clsx,
clsx_default as default clsx_default as default
+1 -1
View File
@@ -1,4 +1,4 @@
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/devalue/src/utils.js // node_modules/devalue/src/utils.js
var escaped = { var escaped = {
+1 -1
View File
@@ -2,7 +2,7 @@ import {
false_default, false_default,
true_default true_default
} from "./chunk-HNWPC2PS.js"; } from "./chunk-HNWPC2PS.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
export { export {
true_default as BROWSER, true_default as BROWSER,
true_default as DEV, true_default as DEV,
+1 -1
View File
@@ -1,4 +1,4 @@
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/pocketbase/dist/pocketbase.es.mjs // node_modules/pocketbase/dist/pocketbase.es.mjs
var ClientResponseError = class _ClientResponseError extends Error { var ClientResponseError = class _ClientResponseError extends Error {
+5 -5
View File
@@ -7,12 +7,12 @@ import {
hydratable, hydratable,
onDestroy, onDestroy,
onMount onMount
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
hydrate, hydrate,
mount, mount,
unmount unmount
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
createContext, createContext,
flushSync, flushSync,
@@ -24,12 +24,12 @@ import {
settled, settled,
tick, tick,
untrack untrack
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-LYA4E26T.js";
import "./chunk-X4VJQ2O3.js";
export { export {
afterUpdate, afterUpdate,
beforeUpdate, beforeUpdate,
+1 -1
View File
@@ -2,7 +2,7 @@ import {
clsx, clsx,
clsx_default clsx_default
} from "./chunk-U7P2NEEE.js"; } from "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
export { export {
clsx, clsx,
clsx_default as default clsx_default as default
+1 -1
View File
@@ -1,7 +1,7 @@
import { import {
cubicOut cubicOut
} from "./chunk-YERFD2CZ.js"; } from "./chunk-YERFD2CZ.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/animate/index.js // node_modules/svelte/src/animate/index.js
function flip(node, { from, to }, params = {}) { function flip(node, { from, to }, params = {}) {
+5 -5
View File
@@ -1,14 +1,14 @@
import { import {
createAttachmentKey, createAttachmentKey,
fromAction fromAction
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import "./chunk-UKTTYZCO.js"; import "./chunk-7XW5QO7S.js";
import "./chunk-UWLXLUJC.js"; import "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-LYA4E26T.js";
import "./chunk-X4VJQ2O3.js";
export { export {
createAttachmentKey, createAttachmentKey,
fromAction fromAction
+1 -1
View File
@@ -31,7 +31,7 @@ import {
sineInOut, sineInOut,
sineOut sineOut
} from "./chunk-YERFD2CZ.js"; } from "./chunk-YERFD2CZ.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
export { export {
backIn, backIn,
backInOut, backInOut,
+2 -2
View File
@@ -1,11 +1,11 @@
import "./chunk-7RQDXF5S.js"; import "./chunk-7RQDXF5S.js";
import { import {
on on
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
export { export {
on on
}; };
+5 -5
View File
@@ -107,7 +107,7 @@ import {
validate_store, validate_store,
validate_void_dynamic_element, validate_void_dynamic_element,
wrap_snippet wrap_snippet
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import { import {
append, append,
comment, comment,
@@ -125,7 +125,7 @@ import {
text, text,
trusted, trusted,
with_script with_script
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import { import {
$document, $document,
$window, $window,
@@ -199,12 +199,12 @@ import {
user_effect, user_effect,
user_pre_effect, user_pre_effect,
wait wait
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-LYA4E26T.js";
import "./chunk-X4VJQ2O3.js";
export { export {
CLASS, CLASS,
FILENAME, FILENAME,
+1 -1
View File
@@ -1,2 +1,2 @@
import "./chunk-2LGM3QYM.js"; import "./chunk-2LGM3QYM.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
+1 -1
View File
@@ -1,7 +1,7 @@
import { import {
enable_async_mode_flag enable_async_mode_flag
} from "./chunk-OHYQYV5R.js"; } from "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/internal/flags/async.js // node_modules/svelte/src/internal/flags/async.js
enable_async_mode_flag(); enable_async_mode_flag();
+1 -1
View File
@@ -1,3 +1,3 @@
import "./chunk-MZVN5SDE.js"; import "./chunk-MZVN5SDE.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
+1 -1
View File
@@ -1,7 +1,7 @@
import { import {
enable_tracing_mode_flag enable_tracing_mode_flag
} from "./chunk-OHYQYV5R.js"; } from "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/internal/flags/tracing.js // node_modules/svelte/src/internal/flags/tracing.js
enable_tracing_mode_flag(); enable_tracing_mode_flag();
+3 -3
View File
@@ -12,12 +12,12 @@ import {
stopImmediatePropagation, stopImmediatePropagation,
stopPropagation, stopPropagation,
trusted trusted
} from "./chunk-UKTTYZCO.js"; } from "./chunk-7XW5QO7S.js";
import "./chunk-UWLXLUJC.js"; import "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
export { export {
asClassComponent, asClassComponent,
createBubbler, createBubbler,
+10 -10
View File
@@ -1,17 +1,14 @@
import {
linear
} from "./chunk-YERFD2CZ.js";
import { import {
MediaQuery MediaQuery
} from "./chunk-GBET5VCG.js"; } from "./chunk-2KB4Y67V.js";
import "./chunk-YSF5ZXQP.js"; import "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js"; import "./chunk-7RQDXF5S.js";
import { import {
loop, loop,
raf, raf,
writable writable
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import "./chunk-UKTTYZCO.js"; import "./chunk-7XW5QO7S.js";
import { import {
deferred, deferred,
get, get,
@@ -20,19 +17,22 @@ import {
set, set,
state, state,
tag tag
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import { import {
true_default true_default
} from "./chunk-HNWPC2PS.js"; } from "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import {
linear
} from "./chunk-YERFD2CZ.js";
import { import {
__privateAdd, __privateAdd,
__privateGet, __privateGet,
__privateMethod, __privateMethod,
__privateSet __privateSet
} from "./chunk-X4VJQ2O3.js"; } from "./chunk-LYA4E26T.js";
// node_modules/svelte/src/motion/utils.js // node_modules/svelte/src/motion/utils.js
function is_date(obj) { function is_date(obj) {
+7 -7
View File
@@ -5,19 +5,19 @@ import {
SvelteSet, SvelteSet,
SvelteURL, SvelteURL,
SvelteURLSearchParams SvelteURLSearchParams
} from "./chunk-GBET5VCG.js"; } from "./chunk-2KB4Y67V.js";
import "./chunk-YSF5ZXQP.js"; import "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js"; import "./chunk-7RQDXF5S.js";
import "./chunk-LDPLLRRU.js"; import "./chunk-XGKSMLPM.js";
import "./chunk-UKTTYZCO.js"; import "./chunk-7XW5QO7S.js";
import { import {
createSubscriber createSubscriber
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-LYA4E26T.js";
import "./chunk-X4VJQ2O3.js";
export { export {
MediaQuery, MediaQuery,
SvelteDate, SvelteDate,
+6 -6
View File
@@ -1,27 +1,27 @@
import { import {
ReactiveValue ReactiveValue
} from "./chunk-YSF5ZXQP.js"; } from "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js"; import "./chunk-7RQDXF5S.js";
import "./chunk-LDPLLRRU.js"; import "./chunk-XGKSMLPM.js";
import "./chunk-UKTTYZCO.js"; import "./chunk-7XW5QO7S.js";
import { import {
get, get,
on, on,
set, set,
source, source,
tag tag
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import { import {
true_default true_default
} from "./chunk-HNWPC2PS.js"; } from "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import { import {
__privateAdd, __privateAdd,
__privateGet, __privateGet,
__privateMethod __privateMethod
} from "./chunk-X4VJQ2O3.js"; } from "./chunk-LYA4E26T.js";
// node_modules/svelte/src/reactivity/window/index.js // node_modules/svelte/src/reactivity/window/index.js
var scrollX = new ReactiveValue( var scrollX = new ReactiveValue(
+5 -5
View File
@@ -4,8 +4,8 @@ import {
readable, readable,
readonly, readonly,
writable writable
} from "./chunk-LDPLLRRU.js"; } from "./chunk-XGKSMLPM.js";
import "./chunk-UKTTYZCO.js"; import "./chunk-7XW5QO7S.js";
import { import {
active_effect, active_effect,
active_reaction, active_reaction,
@@ -15,12 +15,12 @@ import {
render_effect, render_effect,
set_active_effect, set_active_effect,
set_active_reaction set_active_reaction
} from "./chunk-UWLXLUJC.js"; } from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js"; import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js"; import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js"; import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js"; import "./chunk-LYA4E26T.js";
import "./chunk-X4VJQ2O3.js";
// node_modules/svelte/src/store/index-client.js // node_modules/svelte/src/store/index-client.js
function toStore(get2, set) { function toStore(get2, set) {
+1 -1
View File
@@ -4,7 +4,7 @@ import {
import { import {
true_default true_default
} from "./chunk-HNWPC2PS.js"; } from "./chunk-HNWPC2PS.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/transition/index.js // node_modules/svelte/src/transition/index.js
var linear = (x) => x; var linear = (x) => x;
+1 -1
View File
@@ -8,7 +8,7 @@ import {
twMerge, twMerge,
validators validators
} from "./chunk-HRPYXN4O.js"; } from "./chunk-HRPYXN4O.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
export { export {
createTailwindMerge, createTailwindMerge,
extendTailwindMerge, extendTailwindMerge,
+1 -1
View File
@@ -2,7 +2,7 @@ import {
extendTailwindMerge, extendTailwindMerge,
twMerge twMerge
} from "./chunk-HRPYXN4O.js"; } from "./chunk-HRPYXN4O.js";
import "./chunk-X4VJQ2O3.js"; import "./chunk-LYA4E26T.js";
// node_modules/tailwind-variants/dist/chunk-LQJYWU4O.js // node_modules/tailwind-variants/dist/chunk-LQJYWU4O.js
var SPACE_REGEX = /\s+/g; var SPACE_REGEX = /\s+/g;
+43
View File
@@ -0,0 +1,43 @@
/**
* Converts an image File to WebP and returns a new File.
* Used so receipt uploads are stored only as WebP.
*/
export function convertImageToWebP(file: File, quality = 0.85): Promise<File> {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
URL.revokeObjectURL(url);
const canvas = document.createElement("canvas");
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
const ctx = canvas.getContext("2d");
if (!ctx) {
reject(new Error("Could not get canvas context"));
return;
}
ctx.drawImage(img, 0, 0);
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error("Failed to encode WebP"));
return;
}
const baseName = file.name.replace(/\.[^.]+$/i, "") || "image";
const webpFile = new File([blob], `${baseName}.webp`, {
type: "image/webp",
lastModified: Date.now(),
});
resolve(webpFile);
},
"image/webp",
quality
);
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(new Error("Failed to load image"));
};
img.src = url;
});
}
+2 -4
View File
@@ -4,7 +4,6 @@ import type { StackqReceipt } from "$lib/types/receipts";
const COLLECTION = "Stackq_Receipts"; const COLLECTION = "Stackq_Receipts";
const STATUS_OPTIONS = ["New", "Data Entered", "Reviewed", "Consolidated"] as const;
const TYPE_OPTIONS = ["Purchase", "Gas"] as const; const TYPE_OPTIONS = ["Purchase", "Gas"] as const;
export const load: PageServerLoad = async ({ locals }) => { export const load: PageServerLoad = async ({ locals }) => {
@@ -28,13 +27,12 @@ export const actions: Actions = {
if (!user?.id) return fail(401, { error: "You must be logged in to create a receipt." }); if (!user?.id) return fail(401, { error: "You must be logged in to create a receipt." });
const form = await request.formData(); const form = await request.formData();
const Status = (form.get("Status") as string)?.trim() || "New";
const Type = (form.get("Type") as string)?.trim() || "Purchase"; const Type = (form.get("Type") as string)?.trim() || "Purchase";
const imageFile = form.get("Image") as File | null; const imageFile = form.get("Image") as File | null;
const hasImage = imageFile && imageFile.size > 0; const hasImage = imageFile && imageFile.size > 0;
const body: Record<string, unknown> = { const body: Record<string, unknown> = {
Status: STATUS_OPTIONS.includes(Status as (typeof STATUS_OPTIONS)[number]) ? Status : "New", Status: "New",
Type: TYPE_OPTIONS.includes(Type as (typeof TYPE_OPTIONS)[number]) ? Type : "Purchase", Type: TYPE_OPTIONS.includes(Type as (typeof TYPE_OPTIONS)[number]) ? Type : "Purchase",
User: user.id, User: user.id,
}; };
@@ -47,7 +45,7 @@ export const actions: Actions = {
err && typeof err === "object" && "message" in err err && typeof err === "object" && "message" in err
? String((err as { message: string }).message) ? String((err as { message: string }).message)
: "Failed to create receipt."; : "Failed to create receipt.";
return fail(500, { error: message, Status, Type }); return fail(500, { error: message, Type });
} }
return { success: true }; return { success: true };
-1
View File
@@ -127,7 +127,6 @@
action="/receipts?/create" action="/receipts?/create"
submitLabel="Create" submitLabel="Create"
error={form?.error} error={form?.error}
defaultStatus={form?.Status ?? "New"}
defaultType={form?.Type ?? "Purchase"} defaultType={form?.Type ?? "Purchase"}
onSuccess={onReceiptCreateSuccess} onSuccess={onReceiptCreateSuccess}
/> />
+25 -21
View File
@@ -1,10 +1,9 @@
<script lang="ts"> <script lang="ts">
import { Button } from "$lib/components/ui/button"; import { Button } from "$lib/components/ui/button";
import { Input } from "$lib/components/ui/input";
import { Label } from "$lib/components/ui/label"; import { Label } from "$lib/components/ui/label";
import { convertImageToWebP } from "$lib/convert-image-to-webp";
import { enhance } from "$app/forms"; import { enhance } from "$app/forms";
const STATUS_OPTIONS = ["New", "Data Entered", "Reviewed", "Consolidated"] as const;
const TYPE_OPTIONS = ["Purchase", "Gas"] as const; const TYPE_OPTIONS = ["Purchase", "Gas"] as const;
let { let {
@@ -12,28 +11,44 @@
submitLabel, submitLabel,
error, error,
onSuccess, onSuccess,
defaultStatus = "New",
defaultType = "Purchase", defaultType = "Purchase",
}: { }: {
action: string; action: string;
submitLabel: string; submitLabel: string;
error?: string | null; error?: string | null;
onSuccess?: () => void; onSuccess?: () => void;
defaultStatus?: string;
defaultType?: string; defaultType?: string;
} = $props(); } = $props();
let imageInputEl = $state<HTMLInputElement | null>(null); let imageInputEl = $state<HTMLInputElement | null>(null);
let imageFileName = $state<string | null>(null); let imageFileName = $state<string | null>(null);
let imageConverting = $state(false);
function openScanReceipt() { function openScanReceipt() {
imageInputEl?.click(); imageInputEl?.click();
} }
function onImageChange(e: Event) { async function onImageChange(e: Event) {
const input = e.currentTarget as HTMLInputElement; const input = e.currentTarget as HTMLInputElement;
const file = input.files?.[0]; const file = input.files?.[0];
imageFileName = file ? file.name : null; if (!file || !file.type.startsWith("image/")) {
imageFileName = null;
return;
}
imageConverting = true;
imageFileName = null;
try {
const webpFile = await convertImageToWebP(file);
const dt = new DataTransfer();
dt.items.add(webpFile);
input.files = dt.files;
imageFileName = webpFile.name;
} catch {
imageFileName = file.name + " (conversion failed)";
input.value = "";
} finally {
imageConverting = false;
}
} }
</script> </script>
@@ -49,19 +64,6 @@
}} }}
class="flex flex-col gap-4" class="flex flex-col gap-4"
> >
<div class="space-y-2">
<Label for="Status">Status</Label>
<select
id="Status"
name="Status"
class="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-xs"
>
{#each STATUS_OPTIONS as o}
<option value={o} selected={defaultStatus === o}>{o}</option>
{/each}
</select>
</div>
<div class="space-y-2"> <div class="space-y-2">
<Label for="Type">Type</Label> <Label for="Type">Type</Label>
<select <select
@@ -96,10 +98,12 @@
onchange={onImageChange} onchange={onImageChange}
class="hidden" class="hidden"
/> />
{#if imageFileName} {#if imageConverting}
<p class="text-muted-foreground text-xs">Converting to WebP…</p>
{:else if imageFileName}
<p class="text-muted-foreground text-xs">Selected: {imageFileName}</p> <p class="text-muted-foreground text-xs">Selected: {imageFileName}</p>
{:else} {:else}
<p class="text-muted-foreground text-xs">Optional. Use “Scan receipt” to take a photo or pick an image.</p> <p class="text-muted-foreground text-xs">Optional. Images are converted to WebP before upload.</p>
{/if} {/if}
</div> </div>
</div> </div>
+16 -3
View File
@@ -4,6 +4,7 @@
import * as Collapsible from "$lib/components/ui/collapsible"; import * as Collapsible from "$lib/components/ui/collapsible";
import { Input } from "$lib/components/ui/input"; import { Input } from "$lib/components/ui/input";
import { Label } from "$lib/components/ui/label"; import { Label } from "$lib/components/ui/label";
import { convertImageToWebP } from "$lib/convert-image-to-webp";
import { POCKETBASE_BASE_URL } from "$lib/pocketbase"; import { POCKETBASE_BASE_URL } from "$lib/pocketbase";
import { enhance } from "$app/forms"; import { enhance } from "$app/forms";
import ChevronDownIcon from "@lucide/svelte/icons/chevron-down"; import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
@@ -135,11 +136,23 @@
function openReplaceImage() { function openReplaceImage() {
imageInputEl?.click(); imageInputEl?.click();
} }
function onImageChange() { async function onImageChange() {
const input = imageInputEl; const input = imageInputEl;
const file = input?.files?.[0] ?? null; const file = input?.files?.[0] ?? null;
selectedImageFile = file; if (!file || !file.type.startsWith("image/")) {
imageFileName = file ? file.name : null; selectedImageFile = null;
imageFileName = null;
return;
}
try {
const webpFile = await convertImageToWebP(file);
selectedImageFile = webpFile;
imageFileName = webpFile.name;
} catch {
selectedImageFile = null;
imageFileName = null;
if (input) input.value = "";
}
} }
function imageLoadError() { function imageLoadError() {
imageError = true; imageError = true;