From 801b674e17e6913c3faf125f81d1c81933f89ec8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aaron=20D=C3=B6tsch?= <aaron@fsmpi.rwth-aachen.de>
Date: Thu, 2 Mar 2023 18:00:35 +0100
Subject: [PATCH] Implement sorting of categories and products

Categories now have an int property and they get sorted based on that, smallest first.
Products now get sorted by the amount how often they got bought.
---
 prisma/migrations/20230302134013_/migration.sql |  5 +++++
 prisma/schema.prisma                            |  4 +++-
 src/routes/admin/api/articles.js                |  8 ++++----
 src/routes/admin/product/+page.server.js        | 10 ++++++----
 src/routes/admin/product/CategoryItem.svelte    |  6 ++++--
 src/routes/admin/product/CategoryList.svelte    |  3 ++-
 src/routes/api/articles.js                      |  4 ++--
 src/routes/api/transactions.js                  |  1 +
 8 files changed, 27 insertions(+), 14 deletions(-)
 create mode 100644 prisma/migrations/20230302134013_/migration.sql

diff --git a/prisma/migrations/20230302134013_/migration.sql b/prisma/migrations/20230302134013_/migration.sql
new file mode 100644
index 0000000..ea4b5f2
--- /dev/null
+++ b/prisma/migrations/20230302134013_/migration.sql
@@ -0,0 +1,5 @@
+-- AlterTable
+ALTER TABLE "Item" ADD COLUMN     "bought" INTEGER NOT NULL DEFAULT 0;
+
+-- AlterTable
+ALTER TABLE "ItemCategory" ADD COLUMN     "position" INTEGER NOT NULL DEFAULT 0;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 3005a45..a5c4c33 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -12,7 +12,7 @@ datasource db {
 
 model User {
   id        Int      @id @default(autoincrement())
-  email     String   @unique
+  email     String
   name      String
   balance   Int      @default(0)
   createdAt DateTime @default(now())
@@ -43,6 +43,7 @@ model Transaction {
 model ItemCategory {
   id        Int      @id @default(autoincrement())
   name      String
+  position  Int      @default(0)
   createdAt DateTime @default(now())
   items     Item[]
 }
@@ -56,6 +57,7 @@ model Item {
   createdAt DateTime @default(now())
   image     String?
   stock     Int      @default(0)
+  bought    Int      @default(0)
   available Boolean  @default(true)
   restocks  Restock[]
   transactions ItemTransaction[]
diff --git a/src/routes/admin/api/articles.js b/src/routes/admin/api/articles.js
index f794b28..825b737 100644
--- a/src/routes/admin/api/articles.js
+++ b/src/routes/admin/api/articles.js
@@ -52,12 +52,12 @@ export async function updateArticle(code, name, price, categoryId, image, availa
 	return db.item.update({where: {code}, data: {name, price, categoryId, image, available}});
 }
 
-export async function createCategory(name){
-	return db.itemCategory.create({data: {name}});
+export async function createCategory(name, position){
+	return db.itemCategory.create({data: {name, position}});
 }
 
-export async function updateCategory(id, name){
-	return db.itemCategory.update({where: {id}, data: {name}});
+export async function updateCategory(id, name, position){
+	return db.itemCategory.update({where: {id}, data: {name, position}});
 }
 
 export async function deleteCategory(id){
diff --git a/src/routes/admin/product/+page.server.js b/src/routes/admin/product/+page.server.js
index 285bb0a..96378e6 100644
--- a/src/routes/admin/product/+page.server.js
+++ b/src/routes/admin/product/+page.server.js
@@ -64,16 +64,18 @@ export const actions = {
 		const data = await event.request.formData();
 		const id = parseInt(data.get('id'));
 		const name = data.get('name');
-		if(!id || !name) return { error: "Invalid form data" };
-		const category = await updateCategory(id, name);
+		const position = parseInt(data.get('position'));
+		if(!id || !name || !Number.isInteger(position)) return { error: "Invalid form data" };
+		const category = await updateCategory(id, name, position);
 		delete category.createdAt;
 		return {success: true, category};
 	},
 	createCategory: async event => {
 		const data = await event.request.formData();
 		const name = data.get('name');
-		if(!name) return { error: "Invalid form data" };
-		const category = await createCategory(name);
+		const position = parseInt(data.get('position'));
+		if(!name || !Number.isInteger(position)) return { error: "Invalid form data" };
+		const category = await createCategory(name, position);
 		delete category.createdAt;
 		return {success: true, category};
 	}
diff --git a/src/routes/admin/product/CategoryItem.svelte b/src/routes/admin/product/CategoryItem.svelte
index a2a0a83..0264335 100644
--- a/src/routes/admin/product/CategoryItem.svelte
+++ b/src/routes/admin/product/CategoryItem.svelte
@@ -2,7 +2,7 @@
 	import { enhance } from "$app/forms";
 	import { addMessage, MessageType } from "$lib/messages";
 	
-	export let name, id, canDelete;
+	export let name, position, id, canDelete;
 	let edit = false;
 	function deleteCategory(){
 		fetch("/admin/category", {
@@ -25,6 +25,7 @@
 		return async ({result})=>{
 			if(result.type === "success"){
 				name = result.data.category.name;
+				position = result.data.category.position;
 				form.reset();
 				edit = false;
 				addMessage(MessageType.SUCCESS, "Kategorie wurde bearbeitet");
@@ -35,12 +36,13 @@
 		};
 	}}>
 		<input type="text" name="name" value={name} />
+		<input type="number" name="position" step="1" value={position} />
 		<input type="hidden" name="id" value={id} />
 		<button type="submit">Speichern</button>
 		<button type="button" on:click={()=>edit=false}>Abbrechen</button>
 	</form>
 {:else}
-	{name}
+	{name} ({position})
 	<button type="button" on:click={()=>edit=true}>Bearbeiten</button>
 	<button type="button" on:click={deleteCategory} disabled={!canDelete}>Löschen</button>
 {/if}
diff --git a/src/routes/admin/product/CategoryList.svelte b/src/routes/admin/product/CategoryList.svelte
index 4a50d87..45a0f7d 100644
--- a/src/routes/admin/product/CategoryList.svelte
+++ b/src/routes/admin/product/CategoryList.svelte
@@ -8,7 +8,7 @@
 
 <ul>
 	{#each categories as category}
-		<li><CategoryItem bind:name={category.name} id={category.id} canDelete={products.filter(p=>p.categoryId==category.id)==0} /></li>
+		<li><CategoryItem bind:name={category.name} bind:position={category.position} id={category.id} canDelete={products.filter(p=>p.categoryId==category.id)==0} /></li>
 	{/each}
 	<li>
 		<form action="?/createCategory" method="post" use:enhance={({form, data, cancel})=>{
@@ -24,6 +24,7 @@
 			};
 		}}>
 			<input type="text" name="name" />
+			<input type="number" name="position" step="1" />
 			<button type="submit">Erstellen</button>
 		</form>
 	</li>
diff --git a/src/routes/api/articles.js b/src/routes/api/articles.js
index c0ae4d3..01e5042 100644
--- a/src/routes/api/articles.js
+++ b/src/routes/api/articles.js
@@ -2,7 +2,7 @@ import { db } from "$lib/server/database";
 
 export async function getArticles(includeNotAvailable = false) {
 	if (includeNotAvailable) return db.item.findMany();
-	else return db.item.findMany({ where: { available: true } });
+	else return db.item.findMany({ where: { available: true }, orderBy: { bought: "desc" } });
 }
 
 export async function getArticle(code) {
@@ -10,7 +10,7 @@ export async function getArticle(code) {
 }
 
 export async function getCategories() {
-	return db.itemCategory.findMany();
+	return db.itemCategory.findMany({ orderBy: { position: "asc" } });
 }
 
 export async function getCategory(id) {
diff --git a/src/routes/api/transactions.js b/src/routes/api/transactions.js
index 3e9a543..442cf42 100644
--- a/src/routes/api/transactions.js
+++ b/src/routes/api/transactions.js
@@ -14,6 +14,7 @@ export async function buyArticles(userId, card, items, noBalance=false) {
 			where: { code: item.code },
 			data: {
 				stock: { decrement: 1 },
+				bought: { increment: 1 },
 				transactions: {
 					create: {
 						price: item.price,
-- 
GitLab