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 STATUS_OPTIONS = ["New", "Data Entered", "Reviewed", "Consolidated"] as const;
const TYPE_OPTIONS = ["Purchase", "Gas"] as const;
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." });
const form = await request.formData();
const Status = (form.get("Status") as string)?.trim() || "New";
const Type = (form.get("Type") as string)?.trim() || "Purchase";
const imageFile = form.get("Image") as File | null;
const hasImage = imageFile && imageFile.size > 0;
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",
User: user.id,
};
@@ -48,7 +46,7 @@ export const actions = {
err && typeof err === "object" && "message" in err
? String((err as { message: string }).message)
: "Failed to create receipt.";
return fail(500, { error: message, Status, Type });
return fail(500, { error: message, Type });
}
return { success: true };
+7 -7
View File
@@ -1,7 +1,6 @@
import {
Icon_default
} from "./chunk-MR7TRD3U.js";
import "./chunk-2LGM3QYM.js";
} from "./chunk-SK3R2OSP.js";
import {
check_target,
hmr,
@@ -10,11 +9,11 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
append,
comment
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
FILENAME,
HMR,
@@ -23,12 +22,13 @@ import {
noop,
pop,
push
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// 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 {
Icon_default
} from "./chunk-MR7TRD3U.js";
import "./chunk-2LGM3QYM.js";
} from "./chunk-SK3R2OSP.js";
import {
check_target,
hmr,
@@ -10,11 +9,11 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
append,
comment
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
FILENAME,
HMR,
@@ -23,12 +22,13 @@ import {
noop,
pop,
push
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// 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 {
Icon_default
} from "./chunk-MR7TRD3U.js";
import "./chunk-2LGM3QYM.js";
} from "./chunk-SK3R2OSP.js";
import {
check_target,
hmr,
@@ -10,11 +9,11 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
append,
comment
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
FILENAME,
HMR,
@@ -23,12 +22,13 @@ import {
noop,
pop,
push
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// 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 {
Icon_default
} from "./chunk-MR7TRD3U.js";
import "./chunk-2LGM3QYM.js";
} from "./chunk-SK3R2OSP.js";
import {
check_target,
hmr,
@@ -10,11 +9,11 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
append,
comment
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
FILENAME,
HMR,
@@ -23,12 +22,13 @@ import {
noop,
pop,
push
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// 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 {
Icon_default
} from "./chunk-MR7TRD3U.js";
import "./chunk-2LGM3QYM.js";
} from "./chunk-SK3R2OSP.js";
import {
check_target,
hmr,
@@ -10,11 +9,11 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
append,
comment
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
FILENAME,
HMR,
@@ -23,12 +22,13 @@ import {
noop,
pop,
push
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// 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",
"configHash": "441370a6",
"lockfileHash": "9401e68b",
"browserHash": "04aeb2a4",
"browserHash": "c578848f",
"optimized": {
"svelte": {
"src": "../../svelte/src/index-client.js",
"file": "svelte.js",
"fileHash": "1ddbf175",
"fileHash": "836a0569",
"needsInterop": false
},
"svelte/animate": {
"src": "../../svelte/src/animate/index.js",
"file": "svelte_animate.js",
"fileHash": "d9d56906",
"fileHash": "a84129da",
"needsInterop": false
},
"svelte/attachments": {
"src": "../../svelte/src/attachments/index.js",
"file": "svelte_attachments.js",
"fileHash": "c15aecdf",
"fileHash": "2242f01b",
"needsInterop": false
},
"svelte/easing": {
"src": "../../svelte/src/easing/index.js",
"file": "svelte_easing.js",
"fileHash": "e5864893",
"fileHash": "0123c7d6",
"needsInterop": false
},
"svelte/internal": {
@@ -37,184 +37,184 @@
"svelte/internal/client": {
"src": "../../svelte/src/internal/client/index.js",
"file": "svelte_internal_client.js",
"fileHash": "a252d832",
"fileHash": "bf7d241e",
"needsInterop": false
},
"svelte/internal/disclose-version": {
"src": "../../svelte/src/internal/disclose-version.js",
"file": "svelte_internal_disclose-version.js",
"fileHash": "4acec545",
"fileHash": "5ac70717",
"needsInterop": false
},
"svelte/internal/flags/async": {
"src": "../../svelte/src/internal/flags/async.js",
"file": "svelte_internal_flags_async.js",
"fileHash": "cb994494",
"fileHash": "1b74e6fc",
"needsInterop": false
},
"svelte/internal/flags/legacy": {
"src": "../../svelte/src/internal/flags/legacy.js",
"file": "svelte_internal_flags_legacy.js",
"fileHash": "76de734a",
"fileHash": "1c59baa5",
"needsInterop": false
},
"svelte/internal/flags/tracing": {
"src": "../../svelte/src/internal/flags/tracing.js",
"file": "svelte_internal_flags_tracing.js",
"fileHash": "945a287e",
"fileHash": "6a43fbc1",
"needsInterop": false
},
"svelte/legacy": {
"src": "../../svelte/src/legacy/legacy-client.js",
"file": "svelte_legacy.js",
"fileHash": "d42e96f3",
"fileHash": "f44ad964",
"needsInterop": false
},
"svelte/motion": {
"src": "../../svelte/src/motion/index.js",
"file": "svelte_motion.js",
"fileHash": "d899f28f",
"fileHash": "eed1a42f",
"needsInterop": false
},
"svelte/reactivity": {
"src": "../../svelte/src/reactivity/index-client.js",
"file": "svelte_reactivity.js",
"fileHash": "78a01aef",
"fileHash": "8addd267",
"needsInterop": false
},
"svelte/reactivity/window": {
"src": "../../svelte/src/reactivity/window/index.js",
"file": "svelte_reactivity_window.js",
"fileHash": "8e4d19b4",
"fileHash": "cb259eae",
"needsInterop": false
},
"svelte/store": {
"src": "../../svelte/src/store/index-client.js",
"file": "svelte_store.js",
"fileHash": "daa71f26",
"fileHash": "8719f5c5",
"needsInterop": false
},
"svelte/transition": {
"src": "../../svelte/src/transition/index.js",
"file": "svelte_transition.js",
"fileHash": "2ba3c5f3",
"fileHash": "6d4c0f07",
"needsInterop": false
},
"svelte/events": {
"src": "../../svelte/src/events/index.js",
"file": "svelte_events.js",
"fileHash": "4f1aa8f8",
"fileHash": "ec738ae4",
"needsInterop": false
},
"svelte > clsx": {
"src": "../../clsx/dist/clsx.mjs",
"file": "svelte___clsx.js",
"fileHash": "dd6a46d5",
"fileHash": "a84375a2",
"needsInterop": false
},
"@lucide/svelte/icons/check": {
"src": "../../@lucide/svelte/dist/icons/check.js",
"file": "@lucide_svelte_icons_check.js",
"fileHash": "aed21143",
"fileHash": "cc59c42d",
"needsInterop": false
},
"@lucide/svelte/icons/chevron-right": {
"src": "../../@lucide/svelte/dist/icons/chevron-right.js",
"file": "@lucide_svelte_icons_chevron-right.js",
"fileHash": "fad53529",
"fileHash": "4ebfe37c",
"needsInterop": false
},
"@lucide/svelte/icons/circle": {
"src": "../../@lucide/svelte/dist/icons/circle.js",
"file": "@lucide_svelte_icons_circle.js",
"fileHash": "bf331329",
"fileHash": "c9116309",
"needsInterop": false
},
"@lucide/svelte/icons/minus": {
"src": "../../@lucide/svelte/dist/icons/minus.js",
"file": "@lucide_svelte_icons_minus.js",
"fileHash": "c3ee1ff6",
"fileHash": "e38affc6",
"needsInterop": false
},
"@lucide/svelte/icons/x": {
"src": "../../@lucide/svelte/dist/icons/x.js",
"file": "@lucide_svelte_icons_x.js",
"fileHash": "e411e45f",
"fileHash": "dd4ef7b8",
"needsInterop": false
},
"barcode-detector-api-polyfill": {
"src": "../../barcode-detector-api-polyfill/esm/index.js",
"file": "barcode-detector-api-polyfill.js",
"fileHash": "6c03744a",
"fileHash": "e171d6a3",
"needsInterop": false
},
"bits-ui": {
"src": "../../bits-ui/dist/index.js",
"file": "bits-ui.js",
"fileHash": "4faefbe8",
"fileHash": "79f12900",
"needsInterop": false
},
"clsx": {
"src": "../../clsx/dist/clsx.mjs",
"file": "clsx.js",
"fileHash": "41f586d2",
"fileHash": "2d2f5d80",
"needsInterop": false
},
"devalue": {
"src": "../../devalue/index.js",
"file": "devalue.js",
"fileHash": "3717d88b",
"fileHash": "d36225a1",
"needsInterop": false
},
"esm-env": {
"src": "../../esm-env/index.js",
"file": "esm-env.js",
"fileHash": "d7bf04c9",
"fileHash": "b2a3e5c0",
"needsInterop": false
},
"pocketbase": {
"src": "../../pocketbase/dist/pocketbase.es.mjs",
"file": "pocketbase.js",
"fileHash": "8025416e",
"fileHash": "d86e8c93",
"needsInterop": false
},
"tailwind-merge": {
"src": "../../tailwind-merge/dist/bundle-mjs.mjs",
"file": "tailwind-merge.js",
"fileHash": "f66be4a7",
"fileHash": "5a4842de",
"needsInterop": false
},
"tailwind-variants": {
"src": "../../tailwind-variants/dist/index.js",
"file": "tailwind-variants.js",
"fileHash": "b33ed3b9",
"fileHash": "af3e226f",
"needsInterop": false
},
"@lucide/svelte/icons/chevron-down": {
"src": "../../@lucide/svelte/dist/icons/chevron-down.js",
"file": "@lucide_svelte_icons_chevron-down.js",
"fileHash": "dfeee67b",
"fileHash": "c086c4f6",
"needsInterop": false
},
"@lucide/svelte/icons/chevron-up": {
"src": "../../@lucide/svelte/dist/icons/chevron-up.js",
"file": "@lucide_svelte_icons_chevron-up.js",
"fileHash": "dda66014",
"fileHash": "8f687e14",
"needsInterop": false
},
"heic2any": {
"src": "../../heic2any/dist/heic2any.js",
"file": "heic2any.js",
"fileHash": "fb3f1ac6",
"needsInterop": true
}
},
"chunks": {
"chunk-HRPYXN4O": {
"file": "chunk-HRPYXN4O.js"
"chunk-2KB4Y67V": {
"file": "chunk-2KB4Y67V.js"
},
"chunk-YERFD2CZ": {
"file": "chunk-YERFD2CZ.js"
},
"chunk-GBET5VCG": {
"file": "chunk-GBET5VCG.js"
},
"chunk-YSF5ZXQP": {
"file": "chunk-YSF5ZXQP.js"
"chunk-UKQGYTAZ": {
"file": "chunk-UKQGYTAZ.js"
},
"chunk-7RQDXF5S": {
"file": "chunk-7RQDXF5S.js"
@@ -222,35 +222,41 @@
"chunk-MZVN5SDE": {
"file": "chunk-MZVN5SDE.js"
},
"chunk-MR7TRD3U": {
"file": "chunk-MR7TRD3U.js"
"chunk-SK3R2OSP": {
"file": "chunk-SK3R2OSP.js"
},
"chunk-2LGM3QYM": {
"file": "chunk-2LGM3QYM.js"
"chunk-HRPYXN4O": {
"file": "chunk-HRPYXN4O.js"
},
"chunk-LDPLLRRU": {
"file": "chunk-LDPLLRRU.js"
"chunk-XGKSMLPM": {
"file": "chunk-XGKSMLPM.js"
},
"chunk-UKTTYZCO": {
"file": "chunk-UKTTYZCO.js"
"chunk-7XW5QO7S": {
"file": "chunk-7XW5QO7S.js"
},
"chunk-UWLXLUJC": {
"file": "chunk-UWLXLUJC.js"
"chunk-SWXNV5Y3": {
"file": "chunk-SWXNV5Y3.js"
},
"chunk-XWATFG4W": {
"file": "chunk-XWATFG4W.js"
},
"chunk-U7P2NEEE": {
"file": "chunk-U7P2NEEE.js"
},
"chunk-HNWPC2PS": {
"file": "chunk-HNWPC2PS.js"
},
"chunk-OHYQYV5R": {
"file": "chunk-OHYQYV5R.js"
},
"chunk-U7P2NEEE": {
"file": "chunk-U7P2NEEE.js"
"chunk-2LGM3QYM": {
"file": "chunk-2LGM3QYM.js"
},
"chunk-X4VJQ2O3": {
"file": "chunk-X4VJQ2O3.js"
"chunk-YERFD2CZ": {
"file": "chunk-YERFD2CZ.js"
},
"chunk-LYA4E26T": {
"file": "chunk-LYA4E26T.js"
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
import {
__publicField
} from "./chunk-X4VJQ2O3.js";
} from "./chunk-LYA4E26T.js";
// node_modules/ts-custom-error/dist/custom-error.mjs
function fixProto(target, prototype) {
+10 -10
View File
@@ -1,10 +1,9 @@
import {
SvelteMap
} from "./chunk-GBET5VCG.js";
import "./chunk-YSF5ZXQP.js";
} from "./chunk-2KB4Y67V.js";
import "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js";
import "./chunk-MZVN5SDE.js";
import "./chunk-2LGM3QYM.js";
import {
add_locations,
append_styles,
@@ -39,7 +38,7 @@ import {
validate_snippet_args,
validate_void_dynamic_element,
wrap_snippet
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
append,
comment,
@@ -50,7 +49,7 @@ import {
set_text,
text,
unmount
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
FILENAME,
HMR,
@@ -86,15 +85,16 @@ import {
user_derived,
user_effect,
user_pre_effect
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import {
clsx
} from "./chunk-U7P2NEEE.js";
import {
true_default
} from "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import {
clsx
} from "./chunk-U7P2NEEE.js";
import "./chunk-2LGM3QYM.js";
import {
__export,
__privateAdd,
@@ -103,7 +103,7 @@ import {
__privateSet,
__privateWrapper,
__publicField
} from "./chunk-X4VJQ2O3.js";
} from "./chunk-LYA4E26T.js";
// node_modules/bits-ui/dist/bits/accordion/exports.js
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_default
} from "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
clsx,
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
var escaped = {
+1 -1
View File
@@ -2,7 +2,7 @@ import {
false_default,
true_default
} from "./chunk-HNWPC2PS.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
true_default as BROWSER,
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
var ClientResponseError = class _ClientResponseError extends Error {
+5 -5
View File
@@ -7,12 +7,12 @@ import {
hydratable,
onDestroy,
onMount
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
hydrate,
mount,
unmount
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
createContext,
flushSync,
@@ -24,12 +24,12 @@ import {
settled,
tick,
untrack
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
afterUpdate,
beforeUpdate,
+1 -1
View File
@@ -2,7 +2,7 @@ import {
clsx,
clsx_default
} from "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
clsx,
clsx_default as default
+1 -1
View File
@@ -1,7 +1,7 @@
import {
cubicOut
} from "./chunk-YERFD2CZ.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/animate/index.js
function flip(node, { from, to }, params = {}) {
+5 -5
View File
@@ -1,14 +1,14 @@
import {
createAttachmentKey,
fromAction
} from "./chunk-LDPLLRRU.js";
import "./chunk-UKTTYZCO.js";
import "./chunk-UWLXLUJC.js";
} from "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
createAttachmentKey,
fromAction
+1 -1
View File
@@ -31,7 +31,7 @@ import {
sineInOut,
sineOut
} from "./chunk-YERFD2CZ.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
backIn,
backInOut,
+2 -2
View File
@@ -1,11 +1,11 @@
import "./chunk-7RQDXF5S.js";
import {
on
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
on
};
+5 -5
View File
@@ -107,7 +107,7 @@ import {
validate_store,
validate_void_dynamic_element,
wrap_snippet
} from "./chunk-LDPLLRRU.js";
} from "./chunk-XGKSMLPM.js";
import {
append,
comment,
@@ -125,7 +125,7 @@ import {
text,
trusted,
with_script
} from "./chunk-UKTTYZCO.js";
} from "./chunk-7XW5QO7S.js";
import {
$document,
$window,
@@ -199,12 +199,12 @@ import {
user_effect,
user_pre_effect,
wait
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
CLASS,
FILENAME,
+1 -1
View File
@@ -1,2 +1,2 @@
import "./chunk-2LGM3QYM.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
+1 -1
View File
@@ -1,7 +1,7 @@
import {
enable_async_mode_flag
} from "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/internal/flags/async.js
enable_async_mode_flag();
+1 -1
View File
@@ -1,3 +1,3 @@
import "./chunk-MZVN5SDE.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
+1 -1
View File
@@ -1,7 +1,7 @@
import {
enable_tracing_mode_flag
} from "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/internal/flags/tracing.js
enable_tracing_mode_flag();
+3 -3
View File
@@ -12,12 +12,12 @@ import {
stopImmediatePropagation,
stopPropagation,
trusted
} from "./chunk-UKTTYZCO.js";
import "./chunk-UWLXLUJC.js";
} from "./chunk-7XW5QO7S.js";
import "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
asClassComponent,
createBubbler,
+10 -10
View File
@@ -1,17 +1,14 @@
import {
linear
} from "./chunk-YERFD2CZ.js";
import {
MediaQuery
} from "./chunk-GBET5VCG.js";
import "./chunk-YSF5ZXQP.js";
} from "./chunk-2KB4Y67V.js";
import "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js";
import {
loop,
raf,
writable
} from "./chunk-LDPLLRRU.js";
import "./chunk-UKTTYZCO.js";
} from "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import {
deferred,
get,
@@ -20,19 +17,22 @@ import {
set,
state,
tag
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import {
true_default
} from "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import {
linear
} from "./chunk-YERFD2CZ.js";
import {
__privateAdd,
__privateGet,
__privateMethod,
__privateSet
} from "./chunk-X4VJQ2O3.js";
} from "./chunk-LYA4E26T.js";
// node_modules/svelte/src/motion/utils.js
function is_date(obj) {
+7 -7
View File
@@ -5,19 +5,19 @@ import {
SvelteSet,
SvelteURL,
SvelteURLSearchParams
} from "./chunk-GBET5VCG.js";
import "./chunk-YSF5ZXQP.js";
} from "./chunk-2KB4Y67V.js";
import "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js";
import "./chunk-LDPLLRRU.js";
import "./chunk-UKTTYZCO.js";
import "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import {
createSubscriber
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
MediaQuery,
SvelteDate,
+6 -6
View File
@@ -1,27 +1,27 @@
import {
ReactiveValue
} from "./chunk-YSF5ZXQP.js";
} from "./chunk-UKQGYTAZ.js";
import "./chunk-7RQDXF5S.js";
import "./chunk-LDPLLRRU.js";
import "./chunk-UKTTYZCO.js";
import "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import {
get,
on,
set,
source,
tag
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import {
true_default
} from "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import {
__privateAdd,
__privateGet,
__privateMethod
} from "./chunk-X4VJQ2O3.js";
} from "./chunk-LYA4E26T.js";
// node_modules/svelte/src/reactivity/window/index.js
var scrollX = new ReactiveValue(
+5 -5
View File
@@ -4,8 +4,8 @@ import {
readable,
readonly,
writable
} from "./chunk-LDPLLRRU.js";
import "./chunk-UKTTYZCO.js";
} from "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import {
active_effect,
active_reaction,
@@ -15,12 +15,12 @@ import {
render_effect,
set_active_effect,
set_active_reaction
} from "./chunk-UWLXLUJC.js";
} from "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/store/index-client.js
function toStore(get2, set) {
+1 -1
View File
@@ -4,7 +4,7 @@ import {
import {
true_default
} from "./chunk-HNWPC2PS.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
// node_modules/svelte/src/transition/index.js
var linear = (x) => x;
+1 -1
View File
@@ -8,7 +8,7 @@ import {
twMerge,
validators
} from "./chunk-HRPYXN4O.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
export {
createTailwindMerge,
extendTailwindMerge,
+1 -1
View File
@@ -2,7 +2,7 @@ import {
extendTailwindMerge,
twMerge
} from "./chunk-HRPYXN4O.js";
import "./chunk-X4VJQ2O3.js";
import "./chunk-LYA4E26T.js";
// node_modules/tailwind-variants/dist/chunk-LQJYWU4O.js
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 STATUS_OPTIONS = ["New", "Data Entered", "Reviewed", "Consolidated"] as const;
const TYPE_OPTIONS = ["Purchase", "Gas"] as const;
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." });
const form = await request.formData();
const Status = (form.get("Status") as string)?.trim() || "New";
const Type = (form.get("Type") as string)?.trim() || "Purchase";
const imageFile = form.get("Image") as File | null;
const hasImage = imageFile && imageFile.size > 0;
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",
User: user.id,
};
@@ -47,7 +45,7 @@ export const actions: Actions = {
err && typeof err === "object" && "message" in err
? String((err as { message: string }).message)
: "Failed to create receipt.";
return fail(500, { error: message, Status, Type });
return fail(500, { error: message, Type });
}
return { success: true };
-1
View File
@@ -127,7 +127,6 @@
action="/receipts?/create"
submitLabel="Create"
error={form?.error}
defaultStatus={form?.Status ?? "New"}
defaultType={form?.Type ?? "Purchase"}
onSuccess={onReceiptCreateSuccess}
/>
+25 -21
View File
@@ -1,10 +1,9 @@
<script lang="ts">
import { Button } from "$lib/components/ui/button";
import { Input } from "$lib/components/ui/input";
import { Label } from "$lib/components/ui/label";
import { convertImageToWebP } from "$lib/convert-image-to-webp";
import { enhance } from "$app/forms";
const STATUS_OPTIONS = ["New", "Data Entered", "Reviewed", "Consolidated"] as const;
const TYPE_OPTIONS = ["Purchase", "Gas"] as const;
let {
@@ -12,28 +11,44 @@
submitLabel,
error,
onSuccess,
defaultStatus = "New",
defaultType = "Purchase",
}: {
action: string;
submitLabel: string;
error?: string | null;
onSuccess?: () => void;
defaultStatus?: string;
defaultType?: string;
} = $props();
let imageInputEl = $state<HTMLInputElement | null>(null);
let imageFileName = $state<string | null>(null);
let imageConverting = $state(false);
function openScanReceipt() {
imageInputEl?.click();
}
function onImageChange(e: Event) {
async function onImageChange(e: Event) {
const input = e.currentTarget as HTMLInputElement;
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>
@@ -49,19 +64,6 @@
}}
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">
<Label for="Type">Type</Label>
<select
@@ -96,10 +98,12 @@
onchange={onImageChange}
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>
{: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}
</div>
</div>
+16 -3
View File
@@ -4,6 +4,7 @@
import * as Collapsible from "$lib/components/ui/collapsible";
import { Input } from "$lib/components/ui/input";
import { Label } from "$lib/components/ui/label";
import { convertImageToWebP } from "$lib/convert-image-to-webp";
import { POCKETBASE_BASE_URL } from "$lib/pocketbase";
import { enhance } from "$app/forms";
import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
@@ -135,11 +136,23 @@
function openReplaceImage() {
imageInputEl?.click();
}
function onImageChange() {
async function onImageChange() {
const input = imageInputEl;
const file = input?.files?.[0] ?? null;
selectedImageFile = file;
imageFileName = file ? file.name : null;
if (!file || !file.type.startsWith("image/")) {
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() {
imageError = true;