aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src
diff options
context:
space:
mode:
authorMaksymilian Jopek <maks@jopek.eu>2022-03-10 15:39:25 +0100
committerMaksymilian Jopek <maks@jopek.eu>2022-03-10 15:39:25 +0100
commit58e1ffa9effc92f5ddebee4068d5931be12201b0 (patch)
tree45b3fb1e652c7ec72e486fb9c21b1fda0deb7db9 /frontend/src
downloadбібліотека-58e1ffa9effc92f5ddebee4068d5931be12201b0.tar.gz
бібліотека-58e1ffa9effc92f5ddebee4068d5931be12201b0.tar.zst
бібліотека-58e1ffa9effc92f5ddebee4068d5931be12201b0.zip
Initial commit w/ v1.0.0
Diffstat (limited to 'frontend/src')
-rw-r--r--frontend/src/AddBook.svelte103
-rw-r--r--frontend/src/App.svelte32
-rw-r--r--frontend/src/Books.svelte165
-rw-r--r--frontend/src/DBInput.svelte60
-rw-r--r--frontend/src/Login.svelte74
-rw-r--r--frontend/src/Search.svelte92
-rw-r--r--frontend/src/assets/svelte.pngbin0 -> 5185 bytes
-rw-r--r--frontend/src/main.ts7
-rw-r--r--frontend/src/utils.ts22
-rw-r--r--frontend/src/vite-env.d.ts2
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
new file mode 100644
index 0000000..e673c91
--- /dev/null
+++ b/frontend/src/assets/svelte.png
Binary files differ
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" />