serier och taggar

This commit is contained in:
2025-09-11 01:26:06 +02:00
parent e23822b30c
commit f88c25f117
8 changed files with 242 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import type { Component } from "solid-js";
import Home from "./components/Home";
import BookList from "./components/BookList";
import AuthorList from "./components/AuthorList";
import SeriesList from "./components/SeriesList";
const App: Component = () => {
return (
@@ -35,6 +36,9 @@ const App: Component = () => {
<a class="nav-link" href="/authors">
Authors
</a>
<a class="nav-link" href="/series">
Series
</a>
</div>
</div>
</div>
@@ -46,6 +50,7 @@ const App: Component = () => {
<Route path="/books/author/:authorid" component={BookList} />
<Route path="/books" component={BookList} />
<Route path="/authors" component={AuthorList} />
<Route path="/series" component={SeriesList} />
<Route path="/" component={Home} />
</Router>
</main>

View File

@@ -0,0 +1,89 @@
import { createSignal, onMount, For, type Component } from "solid-js";
import AuthorCard from "./AuthorCard";
import BibblanService from "../services/bibblanservice";
import { series, listBook } from "../types/types";
const SeriesList: Component = () => {
const [series, setSeries] = createSignal<series[]>([]);
const [query, setQuery] = createSignal("");
const update = (query: string) => {
setQuery(query);
BibblanService.getSeries(query).then(setSeries);
};
onMount(() => {
update(query());
});
const distinctAuthors = (
books: listBook[]
): { id: number; name: string }[] => {
return [
...new Set(
books.map((b) => JSON.stringify({ id: b.authorId, name: b.authorName }))
),
].map((x) => JSON.parse(x)) as { id: number; name: string }[];
};
const minDate = (books: listBook[]): string => {
if (books.length === 0) return "";
const darr = books.map((b) => new Date(b.pubDate));
const d = darr.reduce((min, b) => (b < min ? b : min), darr[0]);
return d?.toISOString().substr(0, 10) ?? "";
};
const maxDate = (books: listBook[]): string => {
if (books.length === 0) return "";
const darr = books.map((b) => new Date(b.pubDate));
const d = darr.reduce((max, b) => (b > max ? b : max), darr[0]);
return d?.toISOString().substr(0, 10) ?? "";
};
return (
<div>
<h1>Series!</h1>
<input
type="text"
class="form-control mb-3"
placeholder="Search..."
onInput={(e) => update(e.currentTarget.value)}
/>
<table class="table p-3">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Author</th>
<th>Book Count</th>
<th>Published</th>
</tr>
</thead>
<tbody>
<For each={series()}>
{(item) => (
<tr>
<td>{item.id}</td>
<td>{item.name}</td>
<td>
<For each={distinctAuthors(item.books)}>
{(author) => (
<a href={`/books/author/${author.id}`}>{author.name}</a>
)}
</For>
</td>
<td>{item.books.length}</td>
<td>
{minDate(item.books) ?? "N/A"} -{" "}
{maxDate(item.books) ?? "N/A"}
</td>
</tr>
)}
</For>
</tbody>
</table>
</div>
);
};
export default SeriesList;

View File

@@ -25,6 +25,17 @@ const BibblanService = {
const response = await fetch(url);
return response.json();
},
getSeries: async (
query: string | undefined = undefined
): Promise<author[]> => {
let url = "/api/bibblan/series";
if (query != undefined && query.length > 0) {
url += `?query=${encodeURIComponent(query)}`;
}
const response = await fetch(url);
return response.json();
},
};
export default BibblanService;

View File

@@ -18,4 +18,19 @@ interface author {
bookCount: number;
}
export type { book, author };
interface listBook {
id: number;
title: string;
authorId: number;
authorName: string;
pubDate: Date;
seriesIndex: number;
}
interface series {
id: number;
name: string;
books: Array<listBook>;
}
export type { book, author, series, listBook };