diff --git a/package.json b/package.json index d883a98..0188e7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "paper-cost", - "version": "1.4.0", + "version": "1.7.0", "private": true, "scripts": { "dev": "vite dev", @@ -12,24 +12,22 @@ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "test:ui": "playwright test", "test:unit": "vitest", - "lint": "prettier --plugin-search-dir . --check .", - "format": "prettier --plugin-search-dir . --write ." + "lint": "prettier --check .", + "format": "prettier --write ." }, "devDependencies": { "@iconify/svelte": "^4.0.2", "@playwright/test": "^1.46.1", - "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-vercel": "^5.4.1", - "@sveltejs/kit": "^2.0.0", - "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@sveltejs/kit": "^2.7.2", + "@sveltejs/vite-plugin-svelte": "^4.0.0", "@types/mixpanel-browser": "^2.49.0", "@types/node": "^22.5.0", "autoprefixer": "^10.4.14", "dotenv": "^16.4.5", "postcss": "^8.4.27", - "prettier": "^2.8.0", - "prettier-plugin-svelte": "^2.10.1", - "svelte": "^4.0.5", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.7", "svelte-check": "^3.4.3", "tailwindcss": "^3.3.3", "tslib": "^2.4.1", @@ -44,8 +42,8 @@ "@supabase/supabase-js": "^2.44.3", "dayjs": "^1.11.11", "mixpanel-browser": "^2.55.1", + "svelte": "^5.1.0", "svelte-persisted-store": "^0.11.0", - "svelte-sonner": "^0.3.27", - "tippy.js": "^6.3.7" + "svelte-sonner": "^0.3.27" } } diff --git a/src/lib/elements/About.svelte b/src/lib/elements/About.svelte index ff6b073..c56dbba 100644 --- a/src/lib/elements/About.svelte +++ b/src/lib/elements/About.svelte @@ -1,7 +1,8 @@
diff --git a/src/lib/elements/Button.svelte b/src/lib/elements/Button.svelte index d8f9d56..cc6eb8e 100644 --- a/src/lib/elements/Button.svelte +++ b/src/lib/elements/Button.svelte @@ -1,14 +1,16 @@ diff --git a/src/lib/elements/Footer.svelte b/src/lib/elements/Footer.svelte index c4c47fa..01d3dbb 100644 --- a/src/lib/elements/Footer.svelte +++ b/src/lib/elements/Footer.svelte @@ -5,9 +5,13 @@ import { enhance } from '$app/forms' import mixpanel from '$lib/utils/mixpanel' - export let showSettings = false - export let showAbout = false - export let loading = false + type FooterProp = { showSettings: boolean; showAbout: boolean; loading: boolean } + + let { + showSettings = $bindable(), + showAbout = $bindable(), + loading = $bindable() + }: FooterProp = $props() const navItems = [ { href: '/', label: 'Home', icon: 'clarity:home-line' }, @@ -34,7 +38,7 @@ {label} {/each} - @@ -45,7 +49,7 @@ class="absolute w-20 right-3 bottom-11 flex flex-col items-start divide-y divide-orange-400 gap-1 bg-slate-50 p-2 rounded" > void + onrestore?: (id: string) => void + } = $props() - const dispatch = createEventDispatcher() - - let deleteConfirm = '' + let deleteConfirm = $state('')
@@ -29,18 +35,27 @@

- + {#if onrestore} + + {/if} diff --git a/src/lib/elements/Input.svelte b/src/lib/elements/Input.svelte index 2bcf8ea..07a232e 100644 --- a/src/lib/elements/Input.svelte +++ b/src/lib/elements/Input.svelte @@ -1,18 +1,33 @@ @@ -14,10 +19,14 @@ > - + {@render children?.()}
diff --git a/src/lib/elements/PaperItem.svelte b/src/lib/elements/PaperItem.svelte index 4e5dc3d..207305c 100644 --- a/src/lib/elements/PaperItem.svelte +++ b/src/lib/elements/PaperItem.svelte @@ -3,40 +3,61 @@ import Input from './Input.svelte' import { receive, send } from '$lib/utils/tools' import { fields, placeholders } from '$lib/utils/constants' - import { createEventDispatcher } from 'svelte' import type { Paper } from '$lib/utils/services' - export let paper: Paper - export let index: number - export let totalPaper: number - export let perPaperResult: Map + let { + paper = $bindable(), + index, + totalPaper, + perPaperResult, + onkeydown, + onremove + }: { + paper: Paper + index: number + totalPaper: number + perPaperResult: Map + onkeydown: (event: KeyboardEvent) => void + onremove: () => void + } = $props() - const dispatch = createEventDispatcher() + $effect(() => { + console.log(paper) + })
- {#each fields as field} - - {/each} + {#if paper} + {#each fields as field} + + {/each} + {/if}

- = {perPaperResult.get(paper.id)?.toFixed(2) || 'total'} + = {perPaperResult.get(paper?.id)?.toFixed(2) || 'total'}

diff --git a/src/lib/elements/Result.svelte b/src/lib/elements/Result.svelte index 40d03e7..ef34046 100644 --- a/src/lib/elements/Result.svelte +++ b/src/lib/elements/Result.svelte @@ -1,9 +1,9 @@
diff --git a/src/lib/elements/SingleLine.svelte b/src/lib/elements/SingleLine.svelte new file mode 100644 index 0000000..8452c92 --- /dev/null +++ b/src/lib/elements/SingleLine.svelte @@ -0,0 +1 @@ +
diff --git a/src/lib/index.ts b/src/lib/index.ts deleted file mode 100644 index 856f2b6..0000000 --- a/src/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -// place files you want to import through the `$lib` alias in this folder. diff --git a/src/lib/utils/services.ts b/src/lib/utils/services.ts index 0504b0d..4917d1a 100644 --- a/src/lib/utils/services.ts +++ b/src/lib/utils/services.ts @@ -11,7 +11,7 @@ export type Paper = { } export type CostHistoryType = { - id?: string + id: string name: string papers: Paper[] final_price: number diff --git a/src/lib/utils/tooltip.ts b/src/lib/utils/tooltip.ts deleted file mode 100644 index 348dc33..0000000 --- a/src/lib/utils/tooltip.ts +++ /dev/null @@ -1,12 +0,0 @@ -import tippy from 'tippy.js' -import 'tippy.js/dist/tippy.css' -import 'tippy.js/animations/scale.css' - -tippy('[data-tippy]', { - content: (reference) => reference.getAttribute('data-tippy') || '', - allowHTML: true, - placement: 'auto', - arrow: true, - delay: 100, - animation: 'scale' -}) diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 92bc789..5f08438 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -2,7 +2,6 @@ import '$lib/app.css' import '@fontsource/jost' import { navigating } from '$app/stores' - import Loader from '$lib/elements/Loader.svelte' import mixpanel from '$lib/utils/mixpanel' import { Toaster } from 'svelte-sonner' import Modal from '$lib/elements/Modal.svelte' @@ -10,14 +9,13 @@ import About from '$lib/elements/About.svelte' import FullPageLoader from '$lib/elements/FullPageLoader.svelte' import Footer from '$lib/elements/Footer.svelte' - import { onMount } from 'svelte' - export let data - let showSettings = false - let showAbout = false - let loading = false + let { data, children } = $props() + let showSettings = $state(false) + let showAbout = $state(false) + let loading = $state(false) - onMount(() => { + $effect(() => { mixpanel.identify(data.user?.id) mixpanel.people.set({ email: data.user?.email @@ -39,9 +37,9 @@
-
+
- + {@render children()}
= new Map() - let finalPrice: number = 0 - let inputs: NodeListOf | null + let paperCount: Paper[] = $state([{ ...paperFields, id: makeid(5) }]) + let perPaperResult: SvelteMap = new SvelteMap() + let finalPrice: number = $state(0) + let inputs: NodeListOf | [] = $state([]) let inputGroupRef: HTMLDivElement - let focusedIndex = 0 - let product_name = '' - let isSavingHistory = false + let focusedIndex = $state(0) + let product_name = $state('') + let inputsArray: HTMLInputElement[] = $state([]) + let isSavingHistory = $state(false) const addPaper = async () => { paperCount.push({ ...paperFields, id: makeid(5) }) - paperCount = paperCount getAllInputs() } const removePaper = async (idx: string) => { paperCount = paperCount.filter((field) => field.id != idx) if (perPaperResult.has(idx)) perPaperResult.delete(idx) - perPaperResult = perPaperResult setTimeout(() => { getAllInputs() }, 300) @@ -68,6 +69,7 @@ if ($totalHistoryStore < MAX_HISTORY) { isSavingHistory = true const response = await addHistory({ + id: '', name: product_name, final_price: finalPrice, papers: paperCount, @@ -98,29 +100,34 @@ const getAllInputs = async () => { await tick() inputs = inputGroupRef.querySelectorAll('input') + inputsArray = Array.from(inputs) } const setFocus = (element?: HTMLInputElement) => { - if (inputs) { + if (inputs.length) { $focusedInputStore = element || inputs[0] - $focusedInputStore.focus() + $focusedInputStore?.focus() } } - $: hasNullValue = + const hasNullValue = $derived( paperCount && - paperCount.find((paper) => { - return !paper.length || !paper.width || !paper.thickness || !paper.rate - }) - $: showSaveHistory = perPaperResult.size == paperCount.length + paperCount.find((paper) => { + return !paper.length || !paper.width || !paper.thickness || !paper.rate + }) + ) + + const showSaveHistory = $derived(perPaperResult.size == paperCount.length) + // Handling and maintaining focused input index - $: inputsArray = inputs && Array.from(inputs) - $: focusedInputID = $focusedInputStore && $focusedInputStore.getAttribute('id') - $: if (focusedInputID && inputsArray && inputsArray.length) { - focusedIndex = inputsArray - .map((input) => input.getAttribute('id')) - .findIndex((id) => focusedInputID == id) - } + const focusedInputID = $derived($focusedInputStore && $focusedInputStore.getAttribute('id')) + $effect(() => { + if (focusedInputID && inputsArray && inputsArray.length) { + focusedIndex = inputsArray + .map((input) => input.getAttribute('id')) + .findIndex((id) => focusedInputID == id) + } + }) const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Enter' && inputs) { @@ -139,10 +146,10 @@ } } - onMount(async () => { - await getAllInputs() + onMount(() => { + getAllInputs() setFocus() - $totalHistoryStore = await getTotalHistory() + getTotalHistory().then((totalHistory) => ($totalHistoryStore = totalHistory)) }) @@ -152,7 +159,8 @@

Paper Cost

-
+ +
{#if $totalHistoryStore >= MAX_HISTORY}

@@ -170,7 +178,7 @@ {#if showSaveHistory}

@@ -198,20 +206,20 @@
{/if} {#if paperCount.length} -
diff --git a/src/routes/(app)/history/+page.svelte b/src/routes/(app)/history/+page.svelte index 77a2e03..25176ca 100644 --- a/src/routes/(app)/history/+page.svelte +++ b/src/routes/(app)/history/+page.svelte @@ -7,9 +7,11 @@ import Icon from '@iconify/svelte' import mixpanel from '$lib/utils/mixpanel' import { toast } from 'svelte-sonner' + import SingleLine from '$lib/elements/SingleLine.svelte' - export let data - let isLoading = false + let { data } = $props() + + let isLoading = $state(false) mixpanel.track_pageview({ url: '/history' @@ -35,14 +37,14 @@ {data.histories.length}

-
+
{#if !isLoading} {#if data.histories.length}
{#each sortedByCreatedAt(data.histories) as cost} - handleDelete(e.detail)} /> + handleDelete(id)} /> {/each}
{:else} diff --git a/src/routes/(app)/history/[id]/+page.svelte b/src/routes/(app)/history/[id]/+page.svelte index b2fe73c..f27b29b 100644 --- a/src/routes/(app)/history/[id]/+page.svelte +++ b/src/routes/(app)/history/[id]/+page.svelte @@ -3,11 +3,11 @@ import Result from '$lib/elements/Result.svelte' import dayjs from 'dayjs' import { calculateCost, type CostHistoryType } from '$lib/utils/services' - import Icon from '@iconify/svelte' + import SingleLine from '$lib/elements/SingleLine.svelte' - export let data + const { data } = $props() - let history: CostHistoryType | null = data.history + let history: CostHistoryType | null = $state(data.history) @@ -16,7 +16,8 @@

Cost Details

-
+ + {#if history}
@@ -33,15 +34,15 @@
{#if history.papers.length} - {#each history.papers as { length, width, thickness, rate, id }} + {#each history.papers as { length, width, thickness, rate, id }, i}
- - - - + + + +

= {calculateCost({ length, width, thickness, rate, id }).toFixed(2)} diff --git a/src/routes/(app)/history/trash/+page.svelte b/src/routes/(app)/history/trash/+page.svelte index 98de136..269ad9f 100644 --- a/src/routes/(app)/history/trash/+page.svelte +++ b/src/routes/(app)/history/trash/+page.svelte @@ -7,9 +7,11 @@ import Icon from '@iconify/svelte' import mixpanel from '$lib/utils/mixpanel' import { toast } from 'svelte-sonner' + import SingleLine from '$lib/elements/SingleLine.svelte' - export let data - let isLoading = false + let { data } = $props() + + let isLoading = $state(false) mixpanel.track_pageview({ url: '/history/trash' @@ -51,7 +53,8 @@ {data.histories.length}

-
+ +
handleRestore(e.detail)} - on:delete={(e) => handleDelete(e.detail)} + onrestore={(id) => handleRestore(id)} + ondelete={(id) => handleDelete(id)} /> {/each}
@@ -74,7 +77,7 @@