import * as React from "bloatless-react"; import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { ObjectEntryView } from "./objectEntryView"; import { RenameView } from "../renameView"; interface CategoryRow { category: string; statusColumns: React.MapState; } interface StatusColumn { status: string; items: React.ListState; } interface StatusCellItem { priority: number; status: string; messageObject: MessageObjectWithIndex; } // data only interface StatusData { title: string; items: MessageObject[]; } export function StatusView( chat: Chat, messageObjects: React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { const rows = new React.MapState(); const statuses = new React.MapState(); const sortedStatuses = React.createProxyState([statuses], () => [...statuses.value.values()] .map((statusData) => statusData.title) .sort((a, b) => a.localeCompare(b)) ); const sortedCategoryNames = React.createProxyState([rows], () => [...rows.value.values()] .map((row) => row.category) .sort((a, b) => a.localeCompare(b)) ); messageObjects.subscribe(() => { rows.clear(); statuses.clear(); // add items messageObjects.value.forEach((messageObject) => { const latest = chat.getMostRecentContent(messageObject); if (!latest.categoryName || !latest.status) return; const category = latest.categoryName; const status = latest.status; if (!statuses.value.has(status)) { statuses.set(status, { title: status, items: [] }); } statuses.value.get(status)!.items.push(messageObject); if (!rows.value.has(category)) { rows.set(category, { category: category, statusColumns: new React.MapState(), }); } const row = rows.value.get(category)!; if (!row.statusColumns.value.has(status)) { row.statusColumns.set(status, { status: status, items: new React.ListState(), }); } const column = row.statusColumns.value.get(status)!; column.items.add({ priority: latest.priority ?? 0, status, messageObject, }); }); // add status placeholders statuses.value.forEach((statusItemList) => { rows.value.forEach((row) => { if (row.statusColumns.value.has(statusItemList.title)) return; row.statusColumns.set(statusItemList.title, { status: statusItemList.title, items: new React.ListState(), }); }); }); }); const statusDataToHeaderView: React.StateItemConverter = ( statusData ) => { const view = StatusHeaderView(chat, statusData); sortedStatuses.subscribe( () => (view.style.order = sortedStatuses.value.indexOf(statusData.title)) ); return view; }; const categoryRowToView: React.StateItemConverter = (row) => { const view = KanbanRowView( chat, row, sortedStatuses, selectedObject, isShowingObjectModal ); sortedCategoryNames.subscribe( () => (view.style.order = sortedCategoryNames.value.indexOf(row.category)) ); return view; }; return (
); } function StatusHeaderView(chat: Chat, status: StatusData) { const editingStatus = new React.State(status.title); function rename() { status.items.forEach((messageObject) => { const latest = chat.getMostRecentContent(messageObject); latest.status = editingStatus.value; chat.addObject(messageObject); }); } return (
{RenameView(editingStatus, status.title, rename)}
); } function KanbanRowView( chat: Chat, kanbanRow: CategoryRow, sortedStatuses: React.State, selectedObject: React.State, isShowingObjectModal: React.State ) { const editingCategory = new React.State(kanbanRow.category); function renameCategory() { kanbanRow.statusColumns.value.forEach((statusColumns) => { statusColumns.items.value.forEach((statusCellItem) => { const { messageObject } = statusCellItem; const latest = chat.getMostRecentContent(messageObject); latest.categoryName = editingCategory.value; chat.addObjectAndSend(messageObject); }); }); } const statusColumnToEntryView: React.StateItemConverter = ( statusColumn ) => { const view = StatusColumnView( chat, statusColumn.items, kanbanRow.category, statusColumn.status, selectedObject, isShowingObjectModal ); sortedStatuses.subscribe( () => (view.style.order = sortedStatuses.value.indexOf(statusColumn.status)) ); return view; }; return (
{RenameView(editingCategory, kanbanRow.category, renameCategory)}
); } function StatusColumnView( chat: Chat, items: React.ListState, category: string, status: string, selectedObject: React.State, isShowingObjectModal: React.State ) { function dragOver(event: DragEvent) { event.preventDefault(); } function drop(event: DragEvent) { event.preventDefault(); var id = event.dataTransfer?.getData("text"); if (!id) return; const messageObject = chat.objects.value.get(id); if (!messageObject) return; const newContent = chat.createObjectContent(); newContent.categoryName = category; newContent.status = status; chat.updateObjectContent(messageObject, newContent); chat.addObjectAndSend(messageObject); } const cellItemToEntryView: React.StateItemConverter = ( cellItem ) => ObjectEntryView( chat, cellItem.messageObject, selectedObject, isShowingObjectModal ); return (
); }