diff --git a/src/components/Message.svelte b/src/components/Message.svelte index edb5d63c99e6bad5b6aaa36a46290f278e4c132e..6f82a7cee200ae2f643340999c000fd61523b62b 100644 --- a/src/components/Message.svelte +++ b/src/components/Message.svelte @@ -1,7 +1,8 @@ -<script> +<script lang="ts"> import { scale } from "svelte/transition"; - import { removeMessage } from "$lib/messages"; - export let message; + import { removeMessage } from "$lib/messages.js"; + import type { Message } from "$lib/messages.js"; + export let message: Message; </script> <style> diff --git a/src/components/MessageComponent.svelte b/src/components/MessageComponent.svelte index 20351c0718d7ef6436d4c11eeb5595dd2213f5e0..d8c88c4fb3b379c9ce22c8c125828c4c277e4c29 100644 --- a/src/components/MessageComponent.svelte +++ b/src/components/MessageComponent.svelte @@ -1,8 +1,6 @@ <script> import { messageStore } from "$lib/messages"; import Message from "./Message.svelte"; - let messages; - messageStore.subscribe(val=>messages=val); </script> <style> @@ -16,7 +14,7 @@ </style> <div class="messages"> - {#each messages as message (message.id)} + {#each $messageStore as message (message.id)} <Message {message} /> {/each} </div> diff --git a/src/lib/customcodes.js b/src/lib/customcodes.ts similarity index 100% rename from src/lib/customcodes.js rename to src/lib/customcodes.ts diff --git a/src/lib/flags.js b/src/lib/flags.ts similarity index 100% rename from src/lib/flags.js rename to src/lib/flags.ts diff --git a/src/lib/inputhandler.js b/src/lib/inputhandler.ts similarity index 67% rename from src/lib/inputhandler.js rename to src/lib/inputhandler.ts index 2795a164dc947a41dc241e41f303d3a0c5fc6271..187c013f576add62ffaa2d0c92efc7f93270046a 100644 --- a/src/lib/inputhandler.js +++ b/src/lib/inputhandler.ts @@ -1,11 +1,13 @@ import { browser } from "$app/environment"; -const functions = new Map(); +type InputHandler = (input: string) => any; -export function addInputHandler(handler, splitOnNewline = true) { +const functions: Map<InputHandler, {keydown: (e: KeyboardEvent)=>void, paste: (e: ClipboardEvent)=>void}> = new Map(); + +export function addInputHandler(handler: InputHandler, splitOnNewline: boolean = true): ()=>void { if(!browser) return; let input = ""; - const keydown = (e) => { + const keydown = (e: KeyboardEvent) => { if(e.key === "Enter"){ handler(input); input = ""; @@ -19,7 +21,7 @@ export function addInputHandler(handler, splitOnNewline = true) { input += e.key; } }; - const paste = (e) => { + const paste = (e: ClipboardEvent) => { const text = e.clipboardData.getData("text"); const lines = splitOnNewline ? text.split("\n") : [text]; for(const line of lines) @@ -29,9 +31,10 @@ export function addInputHandler(handler, splitOnNewline = true) { window.addEventListener("keydown", keydown); window.addEventListener("paste", paste); functions.set(handler, {keydown, paste}); + return () => removeInputHandler(handler); } -export function removeInputHandler(handler) { +export function removeInputHandler(handler: InputHandler) { if(!browser) return; const funcs = functions.get(handler); if(funcs) { diff --git a/src/lib/messages.js b/src/lib/messages.js deleted file mode 100644 index 14f85c831c62c78359d73f46c085c6884dc21a95..0000000000000000000000000000000000000000 --- a/src/lib/messages.js +++ /dev/null @@ -1,38 +0,0 @@ -import { writable } from "svelte/store"; -import { browser } from "$app/environment"; - -let currMsgId; -let messages; -function loadMessageStore(){ - if(browser){ - const data = localStorage.getItem("messages") || "[]"; - messages = JSON.parse(data); - currMsgId = messages.map(msg=>msg.id).reduce((max, id)=>Math.max(max, id), 0); - const store = new writable(messages); - store.subscribe(msgs=>{ - messages = msgs; - localStorage.setItem("messages", JSON.stringify(msgs)); - }); - return store; - } - return new writable([]); -} -export const messageStore = loadMessageStore(); -export function addMessage(type, message){ - if(browser) messageStore.update(messages => [...messages, {type, message, id: ++currMsgId}]); -} -export function removeMessage(message){ - if(browser) messageStore.update(messages => messages.filter(m => m.id !== message.id)); -} -export function getCurrentMessages(){ - return messages; -} - -export const MessageType = { - INFO: "info", - WARN: "warning", - WARNING: "warning", - ERROR: "error", - SUCCESS: "success", - DEFAULT: "default" -}; diff --git a/src/lib/messages.ts b/src/lib/messages.ts new file mode 100644 index 0000000000000000000000000000000000000000..1e8b9e1765d206af8816e39eba90c94048291379 --- /dev/null +++ b/src/lib/messages.ts @@ -0,0 +1,50 @@ +import { writable, type Writable } from "svelte/store"; +import { browser } from "$app/environment"; + +type MessageType = "info" | "warning" | "error" | "success" | "default"; +export type Message = { + type: MessageType, + message: string, + id: number, + duration?: number +}; + +let currMsgId: number; +let messages: Message[]; +function loadMessageStore(): Writable<Message[]>{ + if(browser){ + const data = localStorage.getItem("messages") || "[]"; + messages = JSON.parse(data); + currMsgId = messages.map(msg=>msg.id).reduce((max, id)=>Math.max(max, id), 0); + const store = writable(messages); + store.subscribe(msgs=>{ + messages = msgs; + localStorage.setItem("messages", JSON.stringify(msgs)); + }); + return store; + } + return writable([]); +} +export const messageStore = loadMessageStore(); +export function addMessage(type: MessageType, message: string, duration?: number){ + if(browser){ + const msg = {type, message, id: ++currMsgId, duration}; + messageStore.update(messages => [...messages, msg]); + return msg; + } +} +export function removeMessage(message: Message){ + if(browser) messageStore.update(messages => messages.filter(m => m.id !== message.id)); +} +export function getCurrentMessages(){ + return messages; +} + +export const MessageType = { + INFO: "info" as MessageType, + WARN: "warning" as MessageType, + WARNING: "warning" as MessageType, + ERROR: "error" as MessageType, + SUCCESS: "success" as MessageType, + DEFAULT: "default" as MessageType +}; diff --git a/src/lib/server/authentication.js b/src/lib/server/authentication.ts similarity index 50% rename from src/lib/server/authentication.js rename to src/lib/server/authentication.ts index 79b3ecbee659f30b0495930e397e464eb1c480ab..85f01c1f67f5bc40b42ca88479cbd8d5faf77122 100644 --- a/src/lib/server/authentication.js +++ b/src/lib/server/authentication.ts @@ -1,31 +1,31 @@ import { nanoid } from "nanoid"; -const sessions = new Map(); +const sessions: Map<string, string> = new Map(); -function generate() { - let token; +function generate(): string { + let token: string; do { token = nanoid(32); } while (sessions.has(token)); return token; } -function getTokenForCard(card) { +function getTokenForCard(card: string): string|undefined { for (const [token, c] of sessions) { if (c === card) return token; } } -export function generateSessionToken(card) { +export function generateSessionToken(card: string): string { const token = getTokenForCard(card) ?? generate(); sessions.set(token, card); return token; } -export function getCardFromSessionToken(sessionToken) { +export function getCardFromSessionToken(sessionToken: string): string { return sessions.get(sessionToken); } -export function invalidateSessionToken(sessionToken) { +export function invalidateSessionToken(sessionToken: string) { sessions.delete(sessionToken); } diff --git a/src/lib/server/database.js b/src/lib/server/database.ts similarity index 91% rename from src/lib/server/database.js rename to src/lib/server/database.ts index 0c13304bcb0f61857b6efb6d26b5fd4ecc9a9da4..8b1ec5386918a7f86d194a222de3e4bc1a2388ef 100644 --- a/src/lib/server/database.js +++ b/src/lib/server/database.ts @@ -1,4 +1,4 @@ -import prisma from "@prisma/client"; +import prisma, { PrismaClient } from "@prisma/client"; import { Codes } from "$lib/customcodes"; import { building } from "$app/environment"; @@ -11,7 +11,7 @@ function getDatabase(){ return db; } -async function initDatabase(db){ +async function initDatabase(db: PrismaClient){ // While building the database is not needed and probably not even available if(building) return; diff --git a/src/routes/admin/api/articles.js b/src/routes/admin/api/articles.ts similarity index 65% rename from src/routes/admin/api/articles.js rename to src/routes/admin/api/articles.ts index 10b35fbe0bb9236e2247013fcfd4556592792eb7..a18d6b566bbd17daee61ce65dc8fff7367903ac4 100644 --- a/src/routes/admin/api/articles.js +++ b/src/routes/admin/api/articles.ts @@ -1,11 +1,11 @@ import { db } from "$lib/server/database"; -export function getPriceModifier(userBalance, noPremium=false){ +export function getPriceModifier(userBalance: number, noPremium: boolean = false){ if(noPremium===true) return ()=>0; if (userBalance < 0) { const debt = -userBalance; const premium = 200 / (1 + Math.pow(Math.E, ((-debt + 2900) / 1000))); - return originalPrice=>{ + return (originalPrice: number)=>{ if(originalPrice < 0) { // just in case that some article should have a negative price (e.g. for refunds) return 0; @@ -18,7 +18,7 @@ export function getPriceModifier(userBalance, noPremium=false){ } }; }else{ - return originalPrice=>{ + return (originalPrice: number)=>{ if (userBalance < originalPrice) { // 10%, aber maximal 0,10€ Aufschlag return Math.min(10, Math.ceil(0.1 * originalPrice)); @@ -29,7 +29,7 @@ export function getPriceModifier(userBalance, noPremium=false){ } } -export function restockArticle(code, amount, cost){ +export function restockArticle(code: string, amount: number, cost: number){ return db.item.update({ where: {code}, data: { @@ -43,27 +43,27 @@ export function restockArticle(code, amount, cost){ }); } -export async function restockArticles(restocks){ +export async function restockArticles(restocks: {code: string, amount: number, cost: number}[]){ return db.$transaction(restocks.map(({code, amount, cost})=>restockArticle(code, amount, cost))); } -export async function createArticle(code, name, price, categoryId, image, available=true, show=true){ +export async function createArticle(code: string, name: string, price: number, categoryId: number, image: string, available=true, show=true){ return db.item.create({data: {code, name, price, categoryId, image, available, show}}); } -export async function updateArticle(code, name, price, categoryId, image, available, show){ +export async function updateArticle(code: string, name: string, price: number, categoryId: number, image: string, available: boolean, show: boolean){ return db.item.update({where: {code}, data: {name, price, categoryId, image, available, show}}); } -export async function createCategory(name, position){ +export async function createCategory(name: string, position: number){ return db.itemCategory.create({data: {name, position}}); } -export async function updateCategory(id, name, position){ +export async function updateCategory(id: number, name: string, position: number){ return db.itemCategory.update({where: {id}, data: {name, position}}); } -export async function deleteCategory(id){ +export async function deleteCategory(id: number){ return db.itemCategory.delete({where: {id}}); } diff --git a/src/routes/admin/api/notificationChannels.js b/src/routes/admin/api/notificationChannels.ts similarity index 100% rename from src/routes/admin/api/notificationChannels.js rename to src/routes/admin/api/notificationChannels.ts diff --git a/src/routes/admin/api/transactions.js b/src/routes/admin/api/transactions.ts similarity index 100% rename from src/routes/admin/api/transactions.js rename to src/routes/admin/api/transactions.ts diff --git a/src/routes/admin/api/users.js b/src/routes/admin/api/users.ts similarity index 100% rename from src/routes/admin/api/users.js rename to src/routes/admin/api/users.ts diff --git a/src/routes/api/transactions.ts b/src/routes/api/transactions.ts index 3e62f3116bdce33fc07c45e5efd2f96454c1851c..12f769f8ef48fc8b72b02c4934d1f1cd6ac902b9 100644 --- a/src/routes/api/transactions.ts +++ b/src/routes/api/transactions.ts @@ -154,7 +154,42 @@ export async function fetchTransactions(userId: number, balanceAfterwards: numbe /* [limit]+1 items are fetched because then we can check if there are more items to fetch. */ - const moneyTransactions = (await getMoneyTransactions(userId, before.moneyTransactions, limit+1)).map(transaction => ({ + type MoneyTransaction = { + type: "transaction", + name: "Aufladen" | "Auszahlung", + difference: number, + createdAt: Date, + verified: boolean, + id: number, + balance?: number + }; + type ItemTransaction = { + type: "item", + name: string, + difference: number, + premium: number, + createdAt: Date, + image: string, + id: number, + balance?: number + }; + type MoneyTransfer = { + type: "transfer", + name: string, + difference: number, + createdAt: Date, + id: number, + balance?: number + }; + type VoucherUse = { + type: "voucher", + name: string, + difference: number, + createdAt: Date, + id: number, + balance?: number + }; + const moneyTransactions: MoneyTransaction[] = (await getMoneyTransactions(userId, before.moneyTransactions, limit+1)).map(transaction => ({ type: "transaction", name: transaction.amount > 0 ? "Aufladen" : "Auszahlung", difference: transaction.amount, @@ -162,7 +197,7 @@ export async function fetchTransactions(userId: number, balanceAfterwards: numbe verified: !!transaction.verifiedById, id: transaction.id })); - const itemTransactions = (await getItemTransactions(userId, before.itemTransactions, limit+1)).map(transaction => ({ + const itemTransactions: ItemTransaction[] = (await getItemTransactions(userId, before.itemTransactions, limit+1)).map(transaction => ({ type: "item", name: transaction.item.name, difference: -(transaction.price + transaction.premium), @@ -171,14 +206,14 @@ export async function fetchTransactions(userId: number, balanceAfterwards: numbe image: transaction.item.image, id: transaction.id })); - const moneyTransfers = (await getMoneyTransfers(userId, before.moneyTransactions, limit+1)).map(transfer => ({ + const moneyTransfers: MoneyTransfer[] = (await getMoneyTransfers(userId, before.moneyTransactions, limit+1)).map(transfer => ({ type: "transfer", name: transfer.fromId === userId ? `Gesendet an ${transfer.to.name}` : `Empfangen von ${transfer.from.name}`, difference: transfer.fromId === userId ? -transfer.amount : transfer.amount, createdAt: transfer.createdAt, id: transfer.id })); - const voucherUses = (await getUsedVouchers(userId, before.voucherUses, limit+1)).map(voucher => ({ + const voucherUses: VoucherUse[] = (await getUsedVouchers(userId, before.voucherUses, limit+1)).map(voucher => ({ type: "voucher", name: `Gutschein ${voucher.code} eingelöst`, difference: voucher.amount, @@ -186,7 +221,7 @@ export async function fetchTransactions(userId: number, balanceAfterwards: numbe id: voucher.id })); let transactions = [...moneyTransactions, ...itemTransactions, ...moneyTransfers, ...voucherUses] - .sort((a, b) => b.createdAt - a.createdAt); + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); const hasMore = transactions.length > limit; if(transactions.length > limit) transactions = transactions.filter((_,i)=>i<limit); if (transactions.length > 0) {