metropolis/frontend/src/main.ts

143 lines
3.5 KiB
TypeScript

import './style.scss';
import { Query } from './generated/graphql';
import root from './components/root.hbs';
import loading from './components/loading.hbs';
import itemList from './components/itemList.hbs';
import itemDetails from './components/itemDetails.hbs';
async function request<T = Query>(
query: string,
variables?: { [key: string]: any },
): Promise<T> {
return fetch('/api/graphql', {
method: 'POST',
body: JSON.stringify({ query, variables }),
headers: new Headers({
'Content-Type': 'application/json',
}),
})
.then((res) => res.json())
.then((res) => res.data);
}
const itemListCursors: (string | null)[] = [null];
async function loadItemList(cursor?: string | null) {
document.querySelector('#main')!.innerHTML = loading();
const loaded = await request(
`
query ($cursor: ID) {
itemList(cursor: $cursor) {
nodes {
id
ean13
name
}
cursor
hasNextPage
}
}
`,
{
cursor,
},
);
if (
loaded.itemList.cursor &&
!itemListCursors.includes(loaded.itemList.cursor)
) {
itemListCursors.push(loaded.itemList.cursor);
}
const hasPreviousPage = itemListCursors.length > 2;
document.querySelector('#main')!.innerHTML = itemList({
...loaded.itemList,
previousPage: hasPreviousPage,
nextPage: loaded.itemList.hasNextPage,
});
const itemsNext = document.querySelector('#items-next') as HTMLAnchorElement;
if (loaded.itemList.hasNextPage) {
itemsNext.addEventListener('click', () =>
loadItemList(loaded.itemList.cursor),
);
}
const itemsPrevious = document.querySelector(
'#items-previous',
) as HTMLAnchorElement;
if (hasPreviousPage) {
itemsPrevious.addEventListener('click', () => {
itemListCursors.pop();
loadItemList(itemListCursors[itemListCursors.length - 2]);
});
}
(
Array.from(
document.querySelectorAll('.item-open-details'),
) as HTMLButtonElement[]
).forEach((butt) =>
butt.addEventListener('click', () => showItemDetails(butt.dataset.id!)),
);
}
async function showModal(state: boolean = true) {
const cl = (document.querySelector('#modal') as HTMLDivElement).classList;
if (state) {
cl.add('is-active');
} else {
cl.remove('is-active');
}
}
async function showItemDetails(id: string) {
(document.querySelector('#modal-title') as HTMLParagraphElement).innerHTML =
'Item details';
(document.querySelector('#modal-body') as HTMLDivElement).innerHTML =
loading();
showModal(true);
const loaded = await request(
`
query ($id: ID!) {
item(id: $id) {
id
ean13
name
notes
ancestors {
ean13
name
}
descendants {
ean13
name
parent {
ean13
}
}
}
}
`,
{
id,
},
);
(document.querySelector('#modal-body') as HTMLDivElement).innerHTML =
itemDetails(loaded.item!);
(
Array.from(
document.querySelectorAll('#modal .item-open-details'),
) as HTMLButtonElement[]
).forEach((butt) =>
butt.addEventListener('click', () => showItemDetails(butt.dataset.id!)),
);
}
window.addEventListener('load', () => {
document.body.innerHTML = root();
['#modal-close', '#modal-background'].forEach((el) =>
(document.querySelector(el) as HTMLButtonElement).addEventListener(
'click',
() => showModal(false),
),
);
loadItemList();
});