Newer
Older
smart-home-server / webclient / src / js / components / screens / areas / areas-tree-screen.js
import { sidebarTemplate } from "./areas-funcs.js";
import { areaDevicesModal } from "./areas-devices-modal.js";
import { areaActionsModal } from "./areas-actions-modal.js";
import { createNewAreaModal } from "./areas-create-new-modal.js";
import { areaDetailsModal } from "./areas-details-modal.js";

function makeTree(data) {
	const items = data.areas;

	const map = {};
  const roots = [];

  for (const item of items) {
    map[item.id] = { ...item, children: [] };
  }

  for (const item of items) {
    const node = map[item.id];

    if (item.parent_id && map[item.parent_id]) {
      map[item.parent_id].children.push(node);
    } else {
      roots.push(node);
    }
  }

  return roots;
}

function prepareData(data) {
	const tree = makeTree(data);
	return tree;
}

function renderingBranch(branch, lvl) {
	lvl = lvl ?? 0;

	const isSingle = branch.children?.length ? "" : "is-single";
	let html = `
		<div class="branch lvl-${lvl} ${isSingle}" data-lvl="${lvl}">
			<button class="btn-icon without-hover show-childs">
				<i class="ph ph-caret-right"></i>
			</button>
			<div class="branch-container">
				<div class="branch-info">
					<span class="title"><i class="ph ph-map-trifold normalize"></i> ${branch.display_name}</span>
					[
					<span class="text-muted area-type">${branch.type}</span>
					<span><i class="ph ph-link-simple-break normalize"></i> ${branch.alias}</span>
					]
				</div>

				<div class="row g-4">
					<button 
						class="btn btn-accent btn-small with-icon actions"
						data-area-id="${branch.id}"
						data-area-name="${branch.display_name}"
					><i class="ph ph-brackets-curly"></i> Actions</button>
					<button 
						class="btn btn-accent btn-small with-icon devices" 
						data-area-id="${branch.id}"
						data-area-name="${branch.display_name}"
					><i class="ph ph-cpu"></i> Devices</button>
					<button 
						class="btn btn-small btn-primary details"
						data-area-id="${branch.id}"
						data-area-name="${branch.display_name}"
						data-parent-id="${branch.parent_id}"
					>Details</button>
				</div>
			</div>
		</div>
	`;

	if(branch.children?.length) {
		for(let childBranch of branch.children) {
			html += renderingBranch(childBranch, lvl + 1);
		}
	}

	return html;
}

function renderingAreasTree(scr, tree) {
	console.log("TREE", tree);
	let html = `<div class="tree">`;
	for(let branch of tree) {
		html += renderingBranch(branch);
	}
	html += "</div>";

	scr.currentScreen.DOMObject.querySelector(".main-container .tree-container").innerHTML = html;
}

function initAreasTree(scr, sh_api) {
	scr.currentScreen.DOMObject.querySelectorAll(".btn.devices").forEach(btn => {
		btn.addEventListener("click", e => {
			areaDevicesModal({ 
				id: e.currentTarget.dataset.areaId, 
				display_name: e.currentTarget.dataset.areaName 
			}, sh_api).show();
		});
	});

	scr.currentScreen.DOMObject.querySelectorAll(".btn.actions").forEach(btn => {
		btn.addEventListener("click", e => {
			areaActionsModal({ 
				id: e.currentTarget.dataset.areaId, 
				display_name: e.currentTarget.dataset.areaName 
			}, sh_api).show();
		});
	});

	scr.currentScreen.DOMObject.querySelectorAll(".btn.details").forEach(btn => {
		btn.addEventListener("click", e => {
			areaDetailsModal({
				id: e.currentTarget.dataset.areaId,
				display_name: e.currentTarget.dataset.areaName,
				parent_id: e.currentTarget.dataset.parentId
			}, sh_api).show();
		});
	});

	scr.currentScreen.DOMObject.querySelectorAll("button.show-childs").forEach(btn => {
		btn.addEventListener("click", e => {
			const btn = e.currentTarget;
			const branch = btn.parentNode;
			const branchLvl = parseInt(branch.dataset.lvl);

			if(!btn.classList.contains("opened")) {
				btn.classList.add("opened");
				let next = branch.nextElementSibling;
				while(next) {
					const nextBranchLvl = parseInt(next.dataset.lvl);

					if(nextBranchLvl == branchLvl || nextBranchLvl < branchLvl) {
						break;
					}

					if(nextBranchLvl == branchLvl + 1) {
						next.classList.add("a-show");
					}

					next = next.nextElementSibling;
				}
			} else {
				btn.classList.remove("opened");
				let next = branch.nextElementSibling;
				while(next) {
					const nextBranchLvl = parseInt(next.dataset.lvl);

					if(nextBranchLvl == branchLvl || nextBranchLvl < branchLvl) {
						break;
					}

					if(nextBranchLvl == branchLvl + 1) {
						next.classList.remove("a-show");
					}

					next = next.nextElementSibling;
				}
			}
		});
	})

	scr.ready();
}

function areasTree(sh_api) {
	return {
		title: "Areas Tree",
		alias: "areas-tree",
		renderer: () => {
			return Helper.template.mainTemplate(
				sidebarTemplate("areas-tree"), 
				`<div class="top-bar">
					<div class="row g-4">
						<div class="col">
							<h3 class="title">Areas Tree</h3>
						</div>
						<div class="col">
							<button class="btn btn-primary with-icon create-new-area-modal">
								<i class="ph ph-plus"></i>
								Create
							</button>
						</div>
					</div>
				</div>
				<div class="mt-6 tree-container"></div>
				`
			);
		},
		initer: scr => {
			sh_api.areas.list((err, resp, meta) => {
				console.log("sh_api.areas.list", err, resp, meta);

				if(meta.status_code != 200) {
					return scr.error("Server API ERROR", "");
				}

				renderingAreasTree(scr, prepareData(resp.data));
				initAreasTree(scr, sh_api);

				scr.currentScreen.DOMObject.querySelector(".create-new-area-modal:not(.inited)")?.addEventListener("click", e => {
					e.currentTarget.classList.add("inited");
					createNewAreaModal(sh_api).show();
				});

				scr.ready();
			});			
		}
	}
}

export {
	areasTree
}