Skip to content

Commit

Permalink
Merge pull request #29 from Gschaftlhaberer/feat/create-and-delete-sh…
Browse files Browse the repository at this point in the history
…opping-lists

Feat/create and delete shopping lists
  • Loading branch information
pdamianik committed Apr 12, 2024
2 parents 2aeba26 + 1ac56ae commit 98d1f60
Show file tree
Hide file tree
Showing 22 changed files with 511 additions and 146 deletions.
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ vite.config.js.timestamp-*
vite.config.ts.timestamp-*
couchdb
shopping
test-results
6 changes: 5 additions & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,9 @@
"vitest": "^1.2.0",
"yaml": "^2.4.1"
},
"type": "module"
"type": "module",
"dependencies": {
"@types/speakingurl": "^13.0.6",
"speakingurl": "^14.0.1"
}
}
3 changes: 2 additions & 1 deletion app/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'pnpm run build && pnpm run preview',
port: 4173
port: 4173,
reuseExistingServer: true
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
Expand Down
17 changes: 17 additions & 0 deletions app/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 0 additions & 49 deletions app/src/lib/components/ListeErstellenForm.svelte

This file was deleted.

15 changes: 0 additions & 15 deletions app/src/lib/components/ListenItem.svelte

This file was deleted.

18 changes: 0 additions & 18 deletions app/src/lib/components/ListenÜbersicht.svelte

This file was deleted.

39 changes: 39 additions & 0 deletions app/src/lib/components/Product.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script lang="ts">
import type { ExistingDocument, Product } from '$lib/db';
import { db as DB } from '$lib/db';
import { get } from 'svelte/store';
import { Card, Heading, Button } from 'flowbite-svelte';
export let product: ExistingDocument<Product>;
async function deleteProduct() {
const db = get(DB);
await db.remove(product);
}
</script>

<Card {...$$restProps} class="flex flex-row items-center justify-between">
<div class="flex-grow">
<Heading class="inline-block flex-shrink" tag="h4">{product.name}</Heading>
</div>
<div class="flex flex-col items-center text-neutral-500 dark:text-neutral-300">
<span class="text-xl">{product.count}</span>
<span class="text-sm">Stück</span>
</div>
<Button on:click={deleteProduct} class="ml-4">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
class="h-6 w-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
></path>
</svg>
</Button>
</Card>
42 changes: 40 additions & 2 deletions app/src/lib/components/ProductList.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,48 @@
<script lang="ts">
import type { ExistingDocument, ProductList } from '$lib/db';
import { Card, Heading } from 'flowbite-svelte';
import { Button, Card, Heading, Modal } from 'flowbite-svelte';
import TrashBinSolid from '~icons/flowbite/trash-bin-solid';
import ExclamationCircleSolid from '~icons/flowbite/exclamation-circle-solid';
export let productlist: ExistingDocument<ProductList>;
import { db as DB } from '$lib/db';
import { get } from 'svelte/store';
async function deleteList() {
const db = get(DB);
const list = await db.get(deleteModalId);
await db.remove(list);
}
let deleteModal = false;
let deleteModalId = '';
</script>

<Card href={`/items/${productlist._id}`} {...$$restProps}>
<Heading tag="h4">{productlist.name}</Heading>
<div class="flex items-center justify-between">
<Heading tag="h4">{productlist.name}</Heading>
<Button
color="red"
on:click={(e) => {
e.preventDefault();
deleteModal = true;
deleteModalId = productlist._id;
}}
aria-label="Löschen"
>
<TrashBinSolid />
</Button>
</div>
</Card>

<Modal bind:open={deleteModal} size="xs" autoclose outsideclose>
<div class="text-center">
<ExclamationCircleSolid class="mx-auto mb-4 h-12 w-12 text-gray-400 dark:text-gray-200" />
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">
Sicher, dass sie dieses Produkt löschen möchten?
</h3>
<Button color="red" class="me-2" on:click={deleteList}>Ja, ich bin sicher</Button>
<Button color="alternative">Nein, abbrechen</Button>
</div>
</Modal>
9 changes: 8 additions & 1 deletion app/src/lib/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,11 @@ export interface ProductList {
name: string;
}

export const db = writable(new PouchDB<ProductList>('shopping'));
export interface Product {
type: 'product';
list: string;
name: string;
count: number;
}

export const db = writable(new PouchDB<ProductList | Product>('shopping'));
1 change: 1 addition & 0 deletions app/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
// place files you want to import through the `$lib` alias in this folder.
export { default as getSlug } from 'speakingurl';
67 changes: 62 additions & 5 deletions app/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
<script lang="ts">
import { Heading, ListPlaceholder, Alert, P } from 'flowbite-svelte';
import { Heading, ListPlaceholder, Alert, P, Modal, Button, Label, Input } from 'flowbite-svelte';
import type { PageData } from './$types';
import { db, type ExistingDocument, type ProductList as PL } from '$lib/db';
import ProductList from '$lib/components/ProductList.svelte';
import { browser } from '$app/environment';
import { onMount } from 'svelte';
import { get } from 'svelte/store';
import PlusOutline from '~icons/flowbite/plus-outline';
import { getSlug } from '$lib';
export let data: PageData;
export let lists: ExistingDocument<PL>[] = [];
let cancel_changes: (() => void)[] = [];
onMount(() => {
return () => {
cancel_changes.forEach((cancel) => {
if (cancel) {
cancel();
}
});
};
});
data.lists.then((result) => {
lists = result.docs;
lists = result.docs as never[] | ExistingDocument<PL>[];
if (browser) {
$db
.changes({
since: 'now',
live: true,
include_docs: true,
filter: (doc) => {
console.log(doc);
return doc.type === 'list' || doc._deleted;
}
})
.on('change', (change) => {
console.log('change', change);
if (change.deleted) {
lists = lists.filter((list) => list._id !== change.id);
} else {
const index = lists.findIndex((list) => list._id === change.id);
if (change.doc) {
if (change.doc && change.doc.type === 'list') {
if (index === -1) {
lists = [...lists, change.doc];
} else {
Expand All @@ -42,6 +55,22 @@
}
return result;
});
let name = '';
let createModal = false;
async function addList() {
if (name.trim() !== '') {
await get(db).put({
_id: getSlug(name),
type: 'list',
name: name,
version: ''
});
name = '';
createModal = false;
}
}
</script>

<svelte:head>
Expand All @@ -62,4 +91,32 @@
{:catch error}
<Alert color="red">Ein Fehler ist aufgetreten: {error.message}</Alert>
{/await}

<!-- Button zum Erstellen einer neuen Liste -->
<Button
size="xl"
on:click={() => (createModal = true)}
class="mt-5 flex flex-row items-center justify-center gap-2"
>
<PlusOutline />
<span>Neue Liste erstellen</span>
</Button>
</div>

<Modal bind:open={createModal} outsideclose>
<form class="flex flex-col space-y-6" on:submit|preventDefault={addList}>
<Heading tag="h4">Neue Einkaufsliste erstellen</Heading>
<Label for="list-name" class="space-y-2"
><span>Name der Einkaufsliste</span>
<Input
id="list-name"
bind:value={name}
placeholder="List name"
required
class="w-full"
/></Label
>

<Button type="submit" variant="primary" class="w-full">Liste hinzufügen</Button>
</form>
</Modal>
Loading

0 comments on commit 98d1f60

Please sign in to comment.