Newer
Older
smart-home-server / webclient-vue / src / features / areas / pages / AreaTreePage.vue
@Eugene Sukhodolskiy Eugene Sukhodolskiy 23 hours ago 2 KB Add script detail pages with scope grouping
<template>
  <section class="page">
    <GnPageHeader title="Tree" kicker="Areas">
      <template #actions>
        <GnButton variant="primary" icon="ph-plus" @click="openCreate">Create area</GnButton>
      </template>
    </GnPageHeader>

    <AppLoadingState v-if="areasStore.isLoading" text="Loading areas tree" />

    <AppErrorState
      v-else-if="areasStore.error"
      title="Areas loading failed"
      :message="areasStore.error.message"
      :retry="areasStore.loadAreas"
    />

    <AppEmptyState
      v-else-if="areasStore.areaTree.length === 0"
      title="No areas"
      message="No areas found. Create one to get started."
    />

    <ul v-else class="area-tree">
      <AreaTreeNode
        v-for="area in areasStore.areaTree"
        :key="area.id"
        :area="area"
      />
    </ul>

    <GnModal :open="showCreateModal" title="Create area" @update:open="showCreateModal = $event">
      <div class="form-group">
        <GnInput v-model="createForm.type" label="Type" placeholder="room" />
      </div>
      <div class="form-group">
        <GnInput v-model="createForm.alias" label="Alias" placeholder="kitchen" />
      </div>
      <div class="form-group">
        <GnInput v-model="createForm.display_name" label="Display name" placeholder="Kitchen" />
      </div>
      <div v-if="createError" class="form-group">
        <GnAlert variant="danger">{{ createError }}</GnAlert>
      </div>
      <template #footer>
        <GnButton variant="secondary" @click="showCreateModal = false">Cancel</GnButton>
        <GnButton variant="primary" icon="ph-plus" :loading="createLoading" @click="submitCreate">Create</GnButton>
      </template>
    </GnModal>
  </section>
</template>

<script setup>
import { ref, reactive, onMounted } from "vue";
import { useAreasStore } from "../../../stores/areas";
import {
  GnPageHeader,
  GnButton,
  GnModal,
  GnInput,
  GnAlert,
} from "gnexus-ui-kit/vue";
import AreaTreeNode from "../components/AreaTreeNode.vue";
import AppLoadingState from "../../../components/feedback/AppLoadingState.vue";
import AppErrorState from "../../../components/feedback/AppErrorState.vue";
import AppEmptyState from "../../../components/feedback/AppEmptyState.vue";

const areasStore = useAreasStore();

const showCreateModal = ref(false);
const createLoading = ref(false);
const createError = ref("");
const createForm = reactive({ type: "", alias: "", display_name: "" });

function openCreate() {
  createForm.type = "";
  createForm.alias = "";
  createForm.display_name = "";
  createError.value = "";
  showCreateModal.value = true;
}

async function submitCreate() {
  createLoading.value = true;
  createError.value = "";

  const result = await areasStore.createArea({ ...createForm });
  createLoading.value = false;

  if (!result.ok) {
    createError.value = result.error?.message || "Failed to create area";
    return;
  }

  showCreateModal.value = false;
}

onMounted(() => {
  areasStore.loadAreas();
});
</script>

<style scoped>
.form-group {
  margin-bottom: 16px;
}
</style>