import { idb, model, Field } from "async-idb-orm" import { List, ListItem, Board, Tag, ItemTag } from "./types" export { // boards loadBoards, updateBoard, addBoard, deleteBoard, archiveBoard, // lists loadLists, updateList, addList, deleteList, archiveList, // items loadItems, updateItem, addItem, deleteItem, archiveItem, // tags loadTags, updateTag, addTag, deleteTag, addItemTag, deleteItemTag, // import/export JsonUtils, } const boards = model({ id: Field.number({ primaryKey: true }), uuid: Field.string({ default: () => crypto.randomUUID() }), title: Field.string({ default: () => "" }), created: Field.date({ default: () => new Date() }), archived: Field.boolean({ default: () => false }), order: Field.number({ default: () => 0 }), }) const lists = model({ id: Field.number({ primaryKey: true }), boardId: Field.number(), title: Field.string({ default: () => "" }), created: Field.date({ default: () => new Date() }), archived: Field.boolean({ default: () => false }), order: Field.number({ default: () => 0 }), }) const items = model({ id: Field.number({ primaryKey: true }), listId: Field.number(), title: Field.string({ default: () => "" }), content: Field.string({ default: () => "" }), created: Field.date({ default: () => new Date() }), archived: Field.boolean({ default: () => false }), refereceItems: Field.array(Field.number()), order: Field.number({ default: () => 0 }), banner: Field.string({ default: undefined }), }) const tags = model({ id: Field.number({ primaryKey: true }), boardId: Field.number(), title: Field.string({ default: () => "" }), color: Field.string({ default: () => "#402579" }), }) const itemTags = model({ id: Field.number({ primaryKey: true }), itemId: Field.number(), tagId: Field.number(), boardId: Field.number(), }) const db = idb("kanban", { boards, lists, items, tags, itemTags }, 3) const JsonUtils = { export: async () => { const [boards, lists, items, tags, itemTags] = await Promise.all([ db.boards.all(), db.lists.all(), db.items.all(), db.tags.all(), db.itemTags.all(), ]) return JSON.stringify({ boards, lists, items, tags, itemTags, }) }, import: async (data: string) => { try { const parsed = JSON.parse(data) ;["boards", "lists", "items", "tags", "itemTags"].forEach((store) => { if (!(store in parsed)) throw new Error(`store '${store}' not found in import data`) }) await Promise.all([ db.boards.clear(), db.lists.clear(), db.items.clear(), db.tags.clear(), db.itemTags.clear(), ]) const { boards, lists, items, tags, itemTags } = parsed as { boards: Board[] lists: List[] items: ListItem[] tags: Tag[] itemTags: ItemTag[] } await Promise.all([ ...boards.map((b) => db.boards.create(b)), ...lists.map((l) => db.lists.create(l)), ...items.map((i) => db.items.create(i)), ...tags.map((t) => db.tags.create(t)), ...itemTags.map((it) => db.itemTags.create(it)), ]) } catch (error) { alert("an error occured while importing your data: " + error) } }, } // Boards const loadBoards = async (): Promise => await db.boards.all() const updateBoard = (board: Board) => db.boards.update(board) as Promise const addBoard = async (): Promise => { const board = await db.boards.create({}) if (!board) throw new Error("failed to create board") await addList(board.id) return board as Board } const deleteBoard = (board: Board) => db.boards.delete(board.id) as Promise const archiveBoard = (board: Board) => db.boards.update({ ...board, archived: true }) as Promise // Lists const loadLists = (boardId: number, archived = false) => db.lists.findMany((l) => { return l.boardId === boardId && l.archived === archived }) as Promise const updateList = (list: List) => db.lists.update(list) as Promise const addList = (boardId: number, order = 0) => db.lists.create({ boardId, order }) as Promise const deleteList = (list: List) => db.lists.delete(list.id) as Promise const archiveList = (list: List) => db.lists.update({ ...list, archived: true }) as Promise // Items const loadItems = (listId: number, archived = false) => db.items.findMany((i) => { return i.listId === listId && i.archived === archived }) as Promise const updateItem = (item: ListItem) => db.items.update(item) as Promise const addItem = (listId: number, order = 0) => db.items.create({ listId, refereceItems: [], order }) as Promise const deleteItem = (item: ListItem) => db.items.delete(item.id) as Promise const archiveItem = (item: ListItem) => db.items.update({ ...item, archived: true }) as Promise // Tags const loadTags = async ( boardId: number ): Promise<{ tags: Tag[]; itemTags: ItemTag[] }> => { const [tags, itemTags] = await Promise.all([ db.tags.findMany((t) => t.boardId === boardId), db.itemTags.findMany((t) => t.boardId === boardId), ]) return { tags, itemTags, } } const updateTag = (tag: Tag) => db.tags.update(tag) as Promise const addTag = (boardId: number) => db.tags.create({ boardId }) as Promise const deleteTag = async (tag: Tag) => db.tags.delete(tag.id) const addItemTag = (boardId: number, itemId: number, tagId: number) => db.itemTags.create({ boardId, itemId, tagId, }) as Promise const deleteItemTag = (itemTag: ItemTag) => db.itemTags.delete(itemTag.id)