diff options
Diffstat (limited to 'frontend/src')
| -rw-r--r-- | frontend/src/AddBook.svelte | 103 | ||||
| -rw-r--r-- | frontend/src/App.svelte | 32 | ||||
| -rw-r--r-- | frontend/src/Books.svelte | 165 | ||||
| -rw-r--r-- | frontend/src/DBInput.svelte | 60 | ||||
| -rw-r--r-- | frontend/src/Login.svelte | 74 | ||||
| -rw-r--r-- | frontend/src/Search.svelte | 92 | ||||
| -rw-r--r-- | frontend/src/assets/svelte.png | bin | 0 -> 5185 bytes | |||
| -rw-r--r-- | frontend/src/main.ts | 7 | ||||
| -rw-r--r-- | frontend/src/utils.ts | 22 | ||||
| -rw-r--r-- | frontend/src/vite-env.d.ts | 2 |
10 files changed, 557 insertions, 0 deletions
diff --git a/frontend/src/AddBook.svelte b/frontend/src/AddBook.svelte new file mode 100644 index 0000000..9352808 --- /dev/null +++ b/frontend/src/AddBook.svelte @@ -0,0 +1,103 @@ +<script lang="ts"> + import { postToServer } from "./utils"; + + export let whereami: string; + export let mode: string; + export let ebook: any; + + let author: string = ebook ? ebook.author : "", + title: string = ebook ? ebook.title : "", + isbn: string = ebook ? ebook.isbn : "", + format: string = ebook ? ebook.format : "", + pages: string = ebook ? ebook.pages : "", + description: string = ebook ? ebook.description : "", + year: number = ebook ? ebook.year : null, + id: number = ebook ? ebook.id : null, + publisher: string = ebook ? ebook.publisher : ""; + + async function add() { + await postToServer( + "/book", + { + author, + title, + year, + publisher, + id, + isbn, + format, + pages, + description, + }, + true + ); + author = ""; + title = ""; + year = null; + publisher = ""; + id = null; + isbn = ""; + format = ""; + pages = ""; + description = ""; + if (mode === "edit") whereami = "books"; + } +</script> + +<main> + <button type="button" on:click={add}> + {mode[0].toUpperCase() + mode.substring(1)} + </button><br /> + <label for="author">Author:</label> + <input bind:value={author} id="author" maxlength="100" /><br /> + <label for="title">Title:</label> + <input bind:value={title} id="title" maxlength="100" /><br /> + <label for="year">Year:</label> + <input + bind:value={year} + id="year" + type="number" + min="0000" + step="1" + max="2000000" + /><br /> + <label for="publisher">Publisher:</label> + <input bind:value={publisher} id="publisher" maxlength="100" /><br /> + <label for="isbn">Isbn:</label> + <input bind:value={isbn} id="isbn" maxlength="13" /><br /> + <label for="format">Format:</label> + <input bind:value={format} id="format" maxlength="3" /><br /> + <label for="pages">Pages:</label> + <input + bind:value={pages} + id="pages" + type="number" + min="0" + step="1" + max="2000000" + /><br /> + <label for="description">Description:</label> + <input bind:value={description} id="description" maxlength="255" /><br /> + <button type="button" on:click={() => (whereami = "books")}>Go back</button> +</main> + +<style> + :root { + font-family: "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell; + } + + main { + text-align: center; + font-size: 1.9em; + } + button { + margin-top: 30px; + margin-bottom: 30px; + margin-left: 15px; + text-decoration: underline; + font-size: 1em; + } + input { + font-size: 1em; + } +</style> diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte new file mode 100644 index 0000000..ee4d894 --- /dev/null +++ b/frontend/src/App.svelte @@ -0,0 +1,32 @@ +<script lang="ts"> + import DbInput from "./DBInput.svelte"; + import Login from "./Login.svelte"; + import Books from "./Books.svelte"; + import AddBook from "./AddBook.svelte"; + let whereami = "check-db"; + // whereami = "books"; + let ebook = {}; + // whereami = "books"; + + $: { + console.log(whereami); + } +</script> + +{#if whereami === "check-db"} + <DbInput bind:whereami /> +{:else if whereami === "login"} + <Login bind:whereami /> +{:else if whereami === "books"} + <Books bind:whereami bind:ebook /> +{:else if whereami === "add-book"} + <AddBook bind:whereami mode="add" ebook={null} /> +{:else if whereami === "edit-book"} + <AddBook bind:whereami mode="edit" bind:ebook /> +{/if} + +<style> + :root { + font-family: "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell; + } +</style> diff --git a/frontend/src/Books.svelte b/frontend/src/Books.svelte new file mode 100644 index 0000000..db1c10b --- /dev/null +++ b/frontend/src/Books.svelte @@ -0,0 +1,165 @@ +<script lang="ts"> + import { fetchFromServer, deleteOnServer } from "./utils"; + import Search from "./Search.svelte"; + + export let whereami: string; + export let ebook: object; + + // let thead: HTMLTableSectionElement, tbody: HTMLTableSectionElement; + let searchCom: Search; + let filters: any = { key: 2 }; + let books: Array<any> = []; + let _books: Array<any> = []; + async function loadData() { + _books = await fetchFromServer("/books"); + books = _books; + } + loadData(); + + let showSearch = false; + + $: { + async function getBooks() { + if (Object.keys(filters).length === 1) { + books = _books; + } else { + books = _books.filter((b: any) => { + for (const fk in filters) { + const fv = filters[fk]; + if (!fv || fk === "key") continue; + if ( + b[fk] + .toString() + .toLowerCase() + .includes(fv.toString().toLowerCase()) + ) + return true; + } + return false; + }); + } + } + getBooks(); + } + + function add() { + whereami = "add-book"; + } + function search() { + showSearch = !showSearch; + } + function edit(book: object) { + whereami = "edit-book"; + ebook = book; + } + async function remove(id: number) { + await deleteOnServer("/book?bid=" + id, true); + _books = _books.filter((b) => b.id !== id); + } + function clearFilters() { + searchCom.clear(); + filters = { key: Math.random() }; + } +</script> + +<main> + <button type="button" class="main-btn" on:click={add}>Add</button> + <button type="button" class="main-btn" on:click={search}> + {showSearch ? "Hide" : "Show"} search dialog + </button> + <button type="button" class="main-btn" on:click={clearFilters}> + Clear filters + </button> + <button type="button" class="main-btn" on:click={loadData}> + Reload data + </button> + {#if showSearch} + <Search bind:filters bind:this={searchCom} /> + {/if} + <table> + <thead> + <tr> + <th>Id</th> + <th>Author</th> + <th>Title</th> + <th>Year of<br />publication</th> + <th>Publisher</th> + <th>Isbn</th> + <th>Format</th> + <th>Pages</th> + <th>Description</th> + <th /> + <th /> + </tr> + </thead> + <tbody> + {#each books as book} + <tr> + <td>{book.id}</td> + <td>{book.author}</td> + <td>{book.title}</td> + <td>{book.year}</td> + <td>{book.publisher}</td> + <td>{book.isbn}</td> + <td>{book.format}</td> + <td>{book.pages}</td> + <td>{book.description}</td> + <td> + <button + type="button" + class="action-btn" + on:click={() => edit(book)} + > + Edit + </button> + </td> + <td> + <button + type="button" + class="action-btn" + on:click={() => remove(book.id)} + > + Remove + </button> + </td> + </tr> + {/each} + </tbody> + </table> +</main> + +<style> + :root { + font-family: "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell; + } + + main { + text-align: center; + } + table { + margin: 0 auto; + border-collapse: collapse; + width: 90%; + font-size: 1.5em; + } + thead { + font-weight: bold; + } + td, + th { + border: 1px solid black; + } + .main-btn { + margin-top: 30px; + margin-bottom: 30px; + margin-left: 15px; + font-size: 1.9em; + text-decoration: underline; + } + .action-btn { + margin-top: 10px; + margin-bottom: 10px; + font-size: 1.2em; + text-decoration: underline; + } +</style> diff --git a/frontend/src/DBInput.svelte b/frontend/src/DBInput.svelte new file mode 100644 index 0000000..f520014 --- /dev/null +++ b/frontend/src/DBInput.svelte @@ -0,0 +1,60 @@ +<script lang="ts"> + import { postToServer } from "./utils"; + + export let whereami: string; + + let pt: string; + + async function sendData() { + const ids = ["server", "port", "database", "user", "password"]; + const body: any = {}; + for (const id of ids) { + body[id] = (document.getElementById(id) as HTMLInputElement).value; + } + body["port"] = parseInt(body["port"]); + + const res = await postToServer("/check-db", body, true); + if (res === "ok") { + whereami = "login"; + } else { + pt = "Error, your database credentials are wrong"; + } + } +</script> + +<main> + <label for="server">Server:</label> + <input type="text" id="server" value="127.0.0.1" /><br /><br /> + <label for="port">Port:</label> + <input type="number" min="1" max="65535" id="port" value="3306" /><br /><br /> + <label for="database">Database:</label> + <input type="text" id="database" value="aitp" /><br /><br /> + <label for="user">User:</label> + <input type="text" id="user" value="admin" /><br /><br /> + <label for="password">Password:</label> + <input type="password" id="password" value="qwerty" /><br /><br /> + <button type="button" on:click={sendData}>Connect</button> + <p contenteditable="true" bind:innerHTML={pt} /> +</main> + +<style> + :root { + font-family: "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell; + } + + main { + text-align: center; + padding: 1em; + margin: 0 auto; + font-size: 2em; + } + input, + button { + font-size: 1em; + margin-left: 10px; + } + + p { + color: red; + } +</style> diff --git a/frontend/src/Login.svelte b/frontend/src/Login.svelte new file mode 100644 index 0000000..674ca47 --- /dev/null +++ b/frontend/src/Login.svelte @@ -0,0 +1,74 @@ +<script lang="ts"> + export let whereami: string; + import { postToServer } from "./utils"; + + let pt = ""; + let mode = "login", + // email = "maks@maks.pl", + email = "asd@asd", + login = "maks", + password = "qwerty"; + + async function register() { + const res = await postToServer( + "/login", + { email, login, password, mode }, + true + ); + console.log(res); + if (res === "ok") { + whereami = "books"; + } else { + pt = "Wrong login or password"; + } + } +</script> + +<main> + {#if mode === "register"} + <label for="email">Email:</label> + <input bind:value={email} type="email" id="email" maxlength="254" /><br + /><br /> + {/if} + <label for="login">Login:</label> + <input bind:value={login} type="text" id="login" maxlength="256" /><br /><br + /> + <label for="password">Password:</label> + <input bind:value={password} type="password" id="password" /><br /><br /> + <button type="button" on:click={register}> + {mode === "login" ? "Login" : "Register"} + </button><br /><br /> + <label for="mode">Register:</label> + <input + type="checkbox" + id="mode" + on:click={() => (mode = mode === "login" ? "register" : "login")} + /> + <p>{pt}</p> +</main> + +<style> + :root { + font-family: "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell; + } + + main { + text-align: center; + padding: 1em; + margin: 0 auto; + font-size: 2em; + } + input, + button { + font-size: 1em; + margin-left: 10px; + } + input[type="checkbox"] { + width: 25px; + height: 25px; + } + + p { + color: red; + } +</style> diff --git a/frontend/src/Search.svelte b/frontend/src/Search.svelte new file mode 100644 index 0000000..2f192eb --- /dev/null +++ b/frontend/src/Search.svelte @@ -0,0 +1,92 @@ +<script lang="ts"> + export let filters: any; + let id: number, + author: string, + title: string, + year: number, + isbn: string, + format: string, + pages: string, + description: string, + publisher: string; + export function clear() { + id = null; + author = null; + title = null; + year = null; + isbn = null; + format = null; + pages = null; + description = null; + publisher = null; + } + $: { + if (id) filters["id"] = id; + else delete filters["id"]; + if (author) filters["author"] = author; + else delete filters["author"]; + if (title) filters["title"] = title; + else delete filters["title"]; + if (year) filters["year"] = year; + else delete filters["year"]; + if (publisher) filters["publisher"] = publisher; + else delete filters["publisher"]; + if (isbn) filters["isbn"] = isbn; + else delete filters["isbn"]; + if (format) filters["format"] = format; + else delete filters["format"]; + if (pages) filters["pages"] = pages; + else delete filters["pages"]; + if (description) filters["description"] = description; + else delete filters["description"]; + filters["key"] = Math.random(); + } +</script> + +<main> + <label for="id">Id:</label> + <input type="number" id="id" bind:value={id} /><br /> + <label for="author">Author:</label> + <input type="text" id="author" bind:value={author} /><br /> + <label for="title">Title:</label> + <input type="text" id="title" bind:value={title} /><br /> + <label for="year">Year:</label> + <input type="number" id="year" bind:value={year} /><br /> + <label for="publisher">Publisher:</label> + <input type="number" id="publisher" bind:value={publisher} /><br /> + <label for="isbn">Isbn:</label> + <!-- @tsignore --> + <input bind:value={isbn} id="isbn" /><br /> + <label for="format">Format:</label> + <input bind:value={format} id="format" /><br /> + <label for="pages">Pages:</label> + <input bind:value={pages} id="pages" /><br /> + <label for="description">Description:</label> + <input + bind:value={description} + id="description" + style="margin-bottom: 0;" + /><br /> + <!-- <button on:click={search}>Filter</button> --> +</main> + +<style> + main { + position: fixed; + left: 0; + right: 0; + margin: auto; + height: fit-content; + width: fit-content; + /* border: 1px solid black; */ + font-size: 1.9em; + margin-bottom: 30px; + color: white; + background-color: rgba(0, 0, 0, 0.75); + padding: 50px; + } + input { + font-size: 1em; + margin-bottom: 30px; + } +</style> diff --git a/frontend/src/assets/svelte.png b/frontend/src/assets/svelte.png Binary files differnew file mode 100644 index 0000000..e673c91 --- /dev/null +++ b/frontend/src/assets/svelte.png diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..d8200ac --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,7 @@ +import App from './App.svelte' + +const app = new App({ + target: document.getElementById('app') +}) + +export default app diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts new file mode 100644 index 0000000..0bf115a --- /dev/null +++ b/frontend/src/utils.ts @@ -0,0 +1,22 @@ +export const url = "http://localhost:8000"; +export async function postToServer(path: string, body: object, asText = false) { + const res = await fetch(url + path, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + if (asText) return await res.text() + return res.json(); +} +export async function fetchFromServer(path: string, asText = false) { + const res = await fetch(url + path); + if (asText) return await res.text() + return res.json(); +} +export async function deleteOnServer(path: string, asText = false) { + const res = await fetch(url + path, { method: "DELETE" }); + if (asText) return await res.text() + return res.json(); +} diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..4078e74 --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// <reference types="svelte" /> +/// <reference types="vite/client" /> |
