143 lines
3.5 KiB
TypeScript
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();
|
|
});
|