Napisałem aplikację w Vue.js. Zamierzam dodać dla PrinterPosnet funkcjonalność wyświetlania jej statusu. Napisz pełną implementację plików, które są niezbędne do dodania tej funkcjonalności. Wzoruj się przy tym na wyświetlaniu statusu zaimplementowanym dla Printer. Nie zmieniaj przy tym istniejących funkcjonalności i widoków już zaimplementowanych dla PrinterPosnet poza zmianami niezbędnymi do dodania nowej funkcjonalności.

/// printer-posnet-row.vue

<template>
  <v-row align="center">
    <v-col>
      <v-row dense>
        <v-col cols="auto">
          <span class="text-body-2 text--bold" v-text="value.displayName"></span>
        </v-col>
        <v-col cols="auto">
          <span
            :class="{
              'text-body-2': true
            }">
            <v-icon small class="mr-1">mdi-map-marker</v-icon>
            {{ stateMappings.orgUnitName(value.organizationUnitId) }}
          </span>
        </v-col>
      </v-row>
    </v-col>
    <v-col cols="auto">
      <div class="text-body-2" style="min-width: 100px">{{ targetName }}</div>
    </v-col>
    <v-col cols="1" class="px-2">
      <span class="text-body-2"><strong>{{ value.name }}</strong>
      </span>
      <div class="text-caption">
        IP: {{ value.ipAddress }}
      </div>
    </v-col>

    <v-col cols="auto" class="pt-2">
      <edit-async-delete-buttons :readonly="readonly" :delete-action="onDelete" @select="select" />
    </v-col>
  </v-row>
</template>

<script lang="ts">
import type { PropType } from "@vue/composition-api";
import { defineComponent, inject, ref } from "@vue/composition-api";
import axios from "@/lib/axios";
import AppState from "@/views/main-wrap/app-state";
import StateMappings from "@/views/main-wrap/state-mappings";
import SubmitButton from "@/components/action-buttons/submit-button.vue";
import TooltipIcon from "@/components/simple/tooltip-icon.vue";
import InlineIcon from "@/components/simple/inline-icon.vue";
import TextUtils from "@/lib/text-utils";
import type PrinterPosnet from "@/views/commerce/printers-posnet/printer-posnet";
import EditAsyncDeleteButtons from "@/components/action-buttons/edit-async-delete-buttons.vue";
import PrinterTarget from "./../printers/printer-target";

const PrinterPosnetRow = defineComponent({
  components: {
    EditAsyncDeleteButtons,
    InlineIcon,
    TooltipIcon,
    SubmitButton
  },
  props: {
    value: {
      type: Object as PropType<PrinterPosnet>,
      required: true
    },
    readonly: {
      type: Boolean,
      required: false,
      default: false
    }
  },

  emits: ["update", "select"],

  setup(props, context) {
    const appState = inject(AppState.Key) as AppState;
    const stateMappings = ref(StateMappings.create(appState));
    const targetName = ref(PrinterTarget.getById(props.value.targetId)?.name);

    const onDelete = async () => {
      await axios.delete(`/api/services/app/PrinterPosnet/${props.value.id}`);
      context.emit("update");
    };

    return {
      stateMappings,
      targetName,
      onDelete,
      trim: TextUtils.trim,
      select: () => context.emit("select")
    };
  }
});

export default PrinterPosnetRow;
</script>

/// printer-posnet.ts

import { GenericNamedGuidEntity } from "@/views/commerce/common/named-item";

export default class PrinterPosnet extends GenericNamedGuidEntity {
  printerId: string | null = null;
  ipAddress: string | null = null;
  targetId: number;
  organizationUnitId: number;
  isActive: boolean = false;

  public static fromDto(dto: any): PrinterPosnet {
    const entity = new PrinterPosnet();
    entity.readDto(dto);
    return entity;
  }

  public static empty(): PrinterPosnet {
    const entity = new PrinterPosnet();
    return entity;
  }

  protected readDto(dto: any) {
    super.readDto(dto);
    this.printerId = dto.printerId;
    this.ipAddress = dto.ipAddress;
    this.targetId = dto.target;
    this.organizationUnitId = dto.organizationUnitId;
    this.isActive = dto.isActive;
  }

  get displayName() {
    return `${this.name} (${this.id})`;
  }

  get dto(): any {
    const baseDto: any = {
      name: this.name,
      isActive: this.isActive,
      printerId: this.printerId,
      ipAddress: this.ipAddress,
      organizationUnitId: this.organizationUnitId,
      target: this.targetId
    };

    if (this.id !== null && this.id !== undefined) {
      baseDto.id = this.id;
    }

    return baseDto;
  }
}

/// printer-posnet-view.vue

<template>
  <loading-container :is-loaded="pagedState.isLoaded">
    <v-overlay v-if="pagedState.isCardVisible" z-index="10" :dark="false">
      <printer-posnet-card
        :readonly="pagedState.readonly"
        :value="pagedState.selectedId"
        @close="v => pagedState.onCardClose(v)" />
    </v-overlay>
    <v-row dense align="center">
      <v-col cols="6">
        <organization-unit-selector v-model="pagedState.query.organizationUnitId" />
      </v-col>
      <v-col cols="6">
        <show-active-only-switch v-model="pagedState.query.activeOnly" />
      </v-col>
      <v-col cols="6">
        <search-input v-model="pagedState.query.searchPhrase" />
      </v-col>
      <v-col cols="6">
        <printer-posnet-target-selector v-model="pagedState.query.target" />
      </v-col>
    </v-row>

    <paged-data-iterator v-model="pagedState.query.pagedModel" :paged-items="pagedState">
      <template #default="{ item, idx }">
        <printer-posnet-row
          :key="item.id"
          :value="item"
          :readonly="pagedState.readonly"
          @select="() => pagedState.select(item.id)"
          @update="() => pagedState.onSearchUpdate()" />
      </template>
    </paged-data-iterator>
  </loading-container>
</template>

<script lang="ts">
import { defineComponent } from "@vue/composition-api";
import LoadingContainer from "@/components/loading/loading-container.vue";
import SearchInput from "@/components/simple/search-input.vue";
import AddItemButton from "@/components/simple/add-item-button.vue";
import PrinterPosnet from "@/views/commerce/printers-posnet/printer-posnet";
import PrinterPosnetCard from "@/views/commerce/printers-posnet/printer-posnet-card.vue";
import PrinterPosnetRow from "@/views/commerce/printers-posnet/printer-posnet-row.vue";
import PagedDataIterator from "@/components/paging/paged-data-iterator.vue";
import { usePagedSearch } from "@/components/paging/paged-view-helpers";
import { PermissionNames } from "@/lib/permissions";
import type { PagedSearchOptions } from "@/components/paging/paged-search-options";
import { PrinterPosnetQuery } from "@/views/commerce/printers-posnet/printers-posnet-query";
import PrinterPosnetTargetSelector from "@/views/commerce/printers-posnet/printer-posnet-target-selector.vue";
import OrganizationUnitSelector from "@/views/commerce/common/selectors/organization-unit-selector.vue";

const PrintersPosnetsView = defineComponent({
  components: {
    PagedDataIterator,
    PrinterPosnetRow,
    PrinterPosnetCard,
    PrinterPosnetTargetSelector,
    OrganizationUnitSelector,
    AddItemButton,
    SearchInput,
    LoadingContainer
  },

  props: {},

  setup(props, context) {
    const options: PagedSearchOptions<PrinterPosnetQuery> = {
      addItemButton: true,
      editPermission: PermissionNames.Printers_Manage,
      fixedQuerySetup: q => { }
    };

    const pagedState = usePagedSearch(
      PrinterPosnet.fromDto,
      PrinterPosnetQuery,
      "/api/services/app/PrinterPosnet/Search",
      context,
      options
    );

    return {
      pagedState
    };
  }
});

export default PrintersPosnetsView;
</script>

/// printer-device-state.ts

export default class PrinterDeviceState {
  name: string;
  id: number;

  public static instance = {
    ready: new PrinterDeviceState(0, "Gotowa"),
    inMenu: new PrinterDeviceState(1, "Otwarte menu"),
    waitForKey: new PrinterDeviceState(2, "Oczekiwanie na przycisk"),
    waitForUserInput: new PrinterDeviceState(3, "Oczekwianie na użytkownia")
  };

  public static readonly All: PrinterDeviceState[] = Object.values(PrinterDeviceState.instance);

  constructor(id: number, name: string) {
    this.name = name;
    this.id = id;
  }

  static getById(id: number | null): PrinterDeviceState {
    return PrinterDeviceState.All.find(v => v.id === id) ?? PrinterDeviceState.instance.ready;
  }
}

/// printer-job-status-response.ts

import { GenericEntity } from "@/views/commerce/common/named-item";
import PrinterJobStatus from "@/views/commerce/printers/printer-job-status";

export default class PrinterJobStatusResponse extends GenericEntity {
  status: PrinterJobStatus = PrinterJobStatus.None;

  public static fromDto(dto: any): PrinterJobStatusResponse {
    const entity = new PrinterJobStatusResponse();
    entity.readDto(dto);
    return entity;
  }

  protected readDto(dto: any) {
    super.readDto(dto);
    this.status = PrinterJobStatus.getById(dto.status);
  }

  get dto(): any {
    return {
      status: this.status.id
    };
  }
}


/// printer-job-status.ts

export default class PrinterJobStatus {
  name: string;
  color: string;
  id: number;

  public static None = new PrinterJobStatus("Nieznany", "error--text", 0);
  public static Started = new PrinterJobStatus(
    "W trakcie wydruku",
    "primary--text text--darken-3",
    1
  );
  public static Completed = new PrinterJobStatus("Wydruk zakończony", "success--text", 2);
  public static Expired = new PrinterJobStatus("Brak odpowiedzi", "error--text", 3);
  public static Error = new PrinterJobStatus("Błąd drukarki", "error--text", 4);

  public static readonly All: PrinterJobStatus[] = [
    PrinterJobStatus.None,
    PrinterJobStatus.Started,
    PrinterJobStatus.Completed,
    PrinterJobStatus.Expired,
    PrinterJobStatus.Error
  ];

  constructor(name: string, color: string, id: number) {
    this.name = name;
    this.id = id;
  }

  static getById(id: number | null): PrinterJobStatus {
    return PrinterJobStatus.All.find(v => v.id === id) ?? PrinterJobStatus.None;
  }
}


/// printer-staus-card.vue

<template>
  <titled-card
    toolbar
    :title="value.displayName"
    close-button
    high
    color="primary darken-2"
    @close="close">
    <loading-container :is-loaded="isLoaded" style="min-width: 500px">
      <printer-status-content v-if="printerStatus.hasValidStatus" :value="printerStatus" />
      <template v-else>
        <div style="width: 100%; text-align: center">
          <v-icon x-large color="error">
            mdi-alert
          </v-icon>
        </div>
        <div style="width: 100%; text-align: center" class="error--text text-body-2">
          Błąd komunikacji z drukarką
        </div>
      </template>
      <v-row dense justify="space-between" align="end">
        <v-col cols="auto">
          <submit-button :action="restart">
            Restart
          </submit-button>
        </v-col>
        <v-col v-if="printerStatus.lastRestartTime" cols="auto" class="text-caption">
          Ostatni restart: {{ printerStatus.lastRestartTime | formatTime }}
        </v-col>
      </v-row>
    </loading-container>
  </titled-card>
</template>
<script lang="ts">
import type { PropType} from "@vue/composition-api";
import { defineComponent, onMounted, ref } from "@vue/composition-api";
import TitledCard from "@/components/simple/titled-card.vue";
import LoadingContainer from "@/components/loading/loading-container.vue";
import TerminalHelloDataContent from "@/views/commerce/terminals/terminal-hello-data-content.vue";
import axios from "@/lib/axios";
import PrinterStatusContent from "@/views/commerce/printers/printer-status-content.vue";
import Printer from "@/views/commerce/printers/printer";
import PrinterStatus from "@/views/commerce/printers/printer-status";
import SubmitButton from "@/components/action-buttons/submit-button.vue";

const TerminalStatusCard = defineComponent({
  components: {
    SubmitButton,
    PrinterStatusContent,
    TerminalHelloDataContent,
    LoadingContainer,
    TitledCard
  },

  props: {
    value: {
      type: Object as PropType<Printer>,
      required: true
    }
  },

  emits: ["close"],

  setup(props, context) {
    const printerStatus = ref(PrinterStatus.empty() as PrinterStatus);
    const isLoaded = ref(false);

    onMounted(async () => {
      try {
        await load();
      } finally {
        isLoaded.value = true;
      }
    });

    const restart = async () => {
      const response = await axios.post("/api/services/app/Printers/RestartProxy", {
        id: props.value.id
      });
      printerStatus.value = Printer.fromDto(response.data.result).status;
    };

    const load = async () => {
      const response = await axios.get("/api/services/app/Printers/GetPrinter", {
        params: { id: props.value.id }
      });
      printerStatus.value = Printer.fromDto(response.data.result).status;
    };

    const close = () => context.emit("close", true);
    return { close, isLoaded, printerStatus, restart };
  }
});

export default TerminalStatusCard;
</script>


/// printer-status-content.vue

<template>
  <div>
    <v-row justify="space-between">
      <v-col cols="auto" class="text-body-2" :class="{ 'warn--text': !!value.deviceState.id }">
        Status: <strong>{{ value.deviceState.name }}</strong>
        <div v-if="responseTimeFormatted">
          Czas odpowiedzi: {{ responseTimeFormatted }} sec.
        </div>
      </v-col>
      <v-col v-if="value.isLowPaper" cols="auto">
        <span class="error--text text-body-2">
          <inline-icon small color="error">mdi-alert</inline-icon>
          Niski poziom papieru
        </span>
      </v-col>
    </v-row>
    <v-row>
      <v-col cols="5">
        <titled-card title="Stawki VAT">
          <template #actions>
            <tooltip-icon
              v-if="value.areVatLevelsOk"
              color="success"
              icon="mdi-check"
              tooltip="Stawki VAT zgodne z wartościami skonfigurowanymi w portalu" />
            <tooltip-icon
              v-else
              color="error"
              icon="mdi-alert"
              tooltip="Stawki VAT nie pokrywają się z wartościami skonfigurowanymi w portalu" />
          </template>
          <div v-for="(item, idx) in value.vatLevels" :key="idx">
            <span class="text--bold text-body-2">PTU {{ item.name.toUpperCase() }}:</span>
            <span class="ml-1 text-body-2">{{ item.formattedValue }}</span>
          </div>
        </titled-card>
      </v-col>
      <v-col>
        <titled-card title="Liczniki">
          <div v-for="(item, idx) in value.counters.list" :key="idx">
            <span class="text--bold text-body-2">{{ item.name }}:</span>
            <span class="ml-1 text-body-2">{{ item.val }}</span>
          </div>
        </titled-card>
      </v-col>
    </v-row>
  </div>
</template>
<script lang="ts">
import type { PropType } from "@vue/composition-api";
import { computed, defineComponent } from "@vue/composition-api";
import TitledCard from "@/components/simple/titled-card.vue";
import LoadingContainer from "@/components/loading/loading-container.vue";
import type PrinterStatus from "@/views/commerce/printers/printer-status";
import TooltipIcon from "@/components/simple/tooltip-icon.vue";
import InlineIcon from "@/components/simple/inline-icon.vue";

const PrinterStatusContent = defineComponent({
  components: { InlineIcon, TooltipIcon, LoadingContainer, TitledCard },

  props: {
    value: {
      type: Object as PropType<PrinterStatus>,
      required: true
    }
  },
  setup(props) {
    const responseTimeFormatted = computed(() => {
      const raw = props.value.responseTime;
      if (!raw) return null;
      return Math.round(raw / 10) / 100;
    });
    return { responseTimeFormatted };
  }
});

export default PrinterStatusContent;
</script>

/// printer-status.ts

import { NoVatString } from "@/views/commerce/vat-settings/vat-level-entry";
import PrinterDeviceState from "@/views/commerce/printers/printer-device-state";

export class PrinterVatLevel {
  name: string;
  value: number | null;

  get formattedValue() {
    return this.value !== null ? `${this.value}%` : NoVatString;
  }
  public static fromDto(dto: any): PrinterVatLevel {
    const entity = new PrinterVatLevel();
    entity.readDto(dto);
    return entity;
  }

  protected readDto(dto: any) {
    this.name = dto.name;
    this.value = dto.value;
  }
}

export class PrinterCounters {
  rd: string | null;
  hn: string | null;
  bn: string | null;
  fn: string | null;
  nu: string | null;
  bt: string | null;
  bc: string | null;
  fc: string | null;

  public static fromDto(dto: any): PrinterCounters {
    const entity = new PrinterCounters();
    entity.readDto(dto);
    return entity;
  }

  get list() {
    const items = [] as Array<{ name: string; val: string }>;
    if (this.rd) items.push({ name: "rd", val: this.rd });
    if (this.hn) items.push({ name: "hn", val: this.hn });
    if (this.bn) items.push({ name: "bn", val: this.bn });
    if (this.fn) items.push({ name: "fn", val: this.fn });
    if (this.nu) items.push({ name: "nu", val: this.nu });
    if (this.bc) items.push({ name: "bc", val: this.bc });
    if (this.bt) items.push({ name: "bt", val: this.bt });
    if (this.fc) items.push({ name: "fc", val: this.fc });
    return items;
  }

  public static empty(): PrinterCounters {
    return new PrinterCounters();
  }

  protected readDto(dto: any) {
    this.rd = dto.rd;
    this.hn = dto.hn;
    this.bn = dto.bn;
    this.fn = dto.fn;
    this.nu = dto.nu;
    this.bt = dto.bt;
    this.bc = dto.bc;
    this.fc = dto.fc;
  }
}

export default class PrinterStatus {
  public static readonly DataStatusUnknown = 0;
  public static readonly DataStatusValid = 1;
  public static readonly DataStatusError = 2;

  vatLevels: PrinterVatLevel[] = [];
  areVatLevelsOk = false;
  isLowPaper = false;
  deviceState: PrinterDeviceState = PrinterDeviceState.instance.ready;
  counters: PrinterCounters = PrinterCounters.empty();

  serialNumber: string | null = null;

  dataStatus = PrinterStatus.DataStatusError;
  lastRestartTime: string | null = null;
  responseTime: number | null = null;

  public static fromDto(dto: any): PrinterStatus {
    const entity = new PrinterStatus();
    entity.readDto(dto);
    return entity;
  }

  get hasValidStatus() {
    return this.dataStatus === PrinterStatus.DataStatusValid;
  }

  get isUnknown() {
    return this.dataStatus === PrinterStatus.DataStatusUnknown;
  }

  get isNoConnection() {
    return this.dataStatus === PrinterStatus.DataStatusError;
  }

  get error() {
    if (this.dataStatus === PrinterStatus.DataStatusError) return "Brak komunikacji z drukarką";
    if (this.dataStatus === PrinterStatus.DataStatusUnknown) return "Status nieznany";

    const issues = [] as string[];

    if (!this.areVatLevelsOk)
      issues.push("Stawki VAT zgodne z wartościami skonfigurowanymi w portalu");
    if (this.isLowPaper) issues.push("Niski poziom papieru");

    if (this.responseTime && this.responseTime > 4000)
      issues.push(`Długi czas odpowiedzi (${this.responseTime} ms)`);
    return issues.join(", ");
  }

  public static empty(): PrinterStatus {
    return new PrinterStatus();
  }

  protected readDto(dto: any) {
    this.vatLevels = dto.vatLevels ? dto.vatLevels.map(PrinterVatLevel.fromDto) : [];
    this.counters = dto.counters ? PrinterCounters.fromDto(dto.counters) : PrinterCounters.empty();
    this.areVatLevelsOk = dto.areVatLevelsOk;
    this.deviceState = PrinterDeviceState.getById(dto.deviceState);
    this.isLowPaper = dto.isLowPaper;
    this.dataStatus = dto.dataStatus;
    this.serialNumber = dto.serialNumber;
    this.responseTime = dto.responseTime;
    this.lastRestartTime = dto.lastRestartTime;
  }
}


/// printer.ts

import { GenericEntity } from "@/views/commerce/common/named-item";
import PrinterStatus from "@/views/commerce/printers/printer-status";
import PrinterTarget from "@/views/commerce/printers/printer-target";
import type { SelectPanelOption } from "@/components/action-buttons/select-panel-option";

export default class Printer extends GenericEntity implements SelectPanelOption {
  id: string;
  orgUnitId: number;
  name: string | null;
  target: PrinterTarget = PrinterTarget.instance.reception;
  status: PrinterStatus = PrinterStatus.empty();

  public static fromDto(dto: any): Printer {
    const entity = new Printer();
    entity.readDto(dto);
    return entity;
  }

  protected readDto(dto: any) {
    super.readDto(dto);
    this.id = dto.id;
    this.orgUnitId = dto.orgUnitId;
    this.name = dto.name;
    this.target = PrinterTarget.getById(dto.target);
    this.status = dto.status ? PrinterStatus.fromDto(dto.status) : PrinterStatus.empty();
  }

  get displayName() {
    if (this.name) return `${this.name} (${this.id})`;
    return this.id;
  }

  get dto(): any {
    return {
      id: this.id
    };
  }
}

/// printer-view-row.vue

<template>
  <v-row align="center">
    <v-col>
      <v-row dense>
        <v-col cols="auto">
          <span :class="{ 'text-body-2': true, 'text--bold': true }" v-text="value.displayName"></span>
        </v-col>
        <v-col cols="auto">
          <span
            :class="{
              'text-body-2': true
            }">
            <v-icon small class="mr-1">mdi-map-marker</v-icon>
            {{ stateMappings.orgUnitName(value.orgUnitId) }}
          </span>
        </v-col>
      </v-row>
    </v-col>
    <v-col cols="auto">
      <span v-if="value.status.serialNumber" class="text-body-2 primary--text text--darken-2">
        {{ value.status.serialNumber }}
      </span>
    </v-col>
    <v-col cols="auto">
      <div class="text-body-2" style="min-width: 100px" v-text="value.target.name"></div>
    </v-col>
    <v-col cols="auto">
      <tooltip-icon
        :icon="icon"
        :color="color"
        :tooltip="value.status.error"
        :show-tooltip="value.status.error" />
    </v-col>
    <v-col cols="auto">
      <v2-btn color="primary" small @click="select">
        <v-icon>mdi-eye</v-icon>
      </v2-btn>
    </v-col>
  </v-row>
</template>
<script lang="ts">
import type { PropType} from "@vue/composition-api";
import { computed, defineComponent, inject, ref } from "@vue/composition-api";
import AppState from "@/views/main-wrap/app-state";
import StateMappings from "@/views/main-wrap/state-mappings";
import type Printer from "@/views/commerce/printers/printer";
import V2Btn from "@/compatibility-layer/components/v2-btn.vue";
import TooltipIcon from "@/components/simple/tooltip-icon.vue";

const TerminalsView = defineComponent({
  components: {
    TooltipIcon,
    V2Btn
  },

  props: {
    value: {
      type: Object as PropType<Printer>,
      required: true
    }
  },

  setup(props, context) {
    const appState = inject(AppState.Key) as AppState;
    const stateMappings = ref(StateMappings.create(appState));

    const icon = computed(() => {
      if (props.value.status.isUnknown) return "mdi-map-marker-question-outline";
      if (props.value.status.isNoConnection) return "mdi-close-circle";
      if (props.value.status.error) return "mdi-alert";
      return "mdi-check";
    });

    const color = computed(() => {
      if (props.value.status.isUnknown) return "primary darken-2";
      if (props.value.status.isNoConnection) return "error";
      if (props.value.status.error) return "orange";
      return "success";
    });

    return {
      stateMappings,
      icon,
      color,
      select: () => context.emit("select")
    };
  }
});

export default TerminalsView;
</script>

/// printers-view.vue

<template>
  <loading-container :is-loaded="isLoaded" fluid class="ma-0 pa-0">
    <v-overlay v-if="selectedItem" z-index="20" :dark="false">
      <printer-status-card :value="selectedItem" @close="onCardClose" />
    </v-overlay>
    <v-row dense align="center" justify="space-between">
      <v-col cols="4">
        <organization-unit-selector v-model="query.orgUnitId" />
      </v-col>
      <v-col cols="auto">
        <submit-button :action="refresh">
          Odśwież
        </submit-button>
      </v-col>
    </v-row>
    <loading-bar :value="isSearchLoading" />

    <template v-for="(item, idx) in items">
      <printers-view-row :key="idx" :value="item" @select="() => (selectedItem = item)" />

      <v-divider v-if="idx < items.length - 1" :key="idx" class="my-2" />
    </template>
  </loading-container>
</template>
<script lang="ts">
import { computed, defineComponent, inject, onMounted, ref, watch } from "@vue/composition-api";
import axios from "@/lib/axios";
import debounce from "lodash/debounce";
import MedicaRouter from "@/views/main-wrap/medica-router";
import AppState from "@/views/main-wrap/app-state";
import type { Terminal } from "@/views/commerce/terminals/terminal";
import LoadingContainer from "@/components/loading/loading-container.vue";
import StateMappings from "@/views/main-wrap/state-mappings";
import PrinterStatusCard from "@/views/commerce/printers/printer-status-card.vue";
import Printer from "@/views/commerce/printers/printer";
import { PrintersQuery } from "@/views/commerce/printers/printers-query";
import OrganizationUnitSelector from "@/views/commerce/common/selectors/organization-unit-selector.vue";
import LoadingBar from "@/components/simple/loading-bar.vue";
import TooltipIcon from "@/components/simple/tooltip-icon.vue";
import SubmitButton from "@/components/action-buttons/submit-button.vue";
import PrintersViewRow from "@/views/commerce/printers/printers-view-row.vue";

const TerminalsView = defineComponent({
  components: {
    PrintersViewRow,
    SubmitButton,
    TooltipIcon,
    LoadingBar,
    OrganizationUnitSelector,
    PrinterStatusCard,

    LoadingContainer
  },

  props: {},

  setup(props, context) {
    const router = ref(MedicaRouter.forContext(context));
    const appState = inject(AppState.Key) as AppState;
    const stateMappings = ref(StateMappings.create(appState));
    const items = ref([] as Printer[]);
    const isLoaded = ref(false);
    const isSearchLoading = ref(false);
    const query = ref(new PrintersQuery());
    const selectedItem = ref(null as Terminal | null);

    onMounted(async () => {
      router.value.getParams(query.value);
      await loadData();
    });

    const loadData = async () => {
      isLoaded.value = false;
      await executeSearch();
      isLoaded.value = true;
    };

    const setQueryParams = async () => {
      await router.value.setParams(query.value.serializableQuery);
    };

    const prevPage = ref(1);
    watch(
      query,
      async (_1, _2) => {
        query.value.handleUpdate(prevPage, onSearchUpdate);
        if (isLoaded.value) await setQueryParams();
      },
      {
        deep: true
      }
    );

    const executeSearch = async () => {
      const response = await axios.post("/api/services/app/Printers/Search", query.value.dto);
      items.value = response.data.result.map(Printer.fromDto);
    };
    const refresh = async () => {
      const response = await axios.post(
        "/api/services/app/Printers/CheckAll",
        {},
        { timeout: 240000 }
      );
      items.value = response.data.result.map(Printer.fromDto);
    };

    const searchDebounce = debounce(async () => {
      await executeSearch();
      isSearchLoading.value = false;
    }, 500);

    const onSearchUpdate = () => {
      isSearchLoading.value = true;
      searchDebounce();
    };

    const allOrgUnits = computed(() => appState.orgUnits);

    const onCardClose = (needUpdate: boolean) => {
      selectedItem.value = null;
      if (needUpdate) onSearchUpdate();
    };

    return {
      items,

      query,
      refresh,
      allOrgUnits,

      isLoaded,
      isSearchLoading,
      onCardClose,
      stateMappings,
      selectedItem
    };
  }
});

export default TerminalsView;
</script>