~bento/vending-machine

0416c183ad125dbeaf1a0d87acf3244f9003cd73 — Fabio Bento Luiz 8 months ago 9378fec main
improve save sections
M frontend/src/components/TheMaintenanceSection.vue => frontend/src/components/TheMaintenanceSection.vue +50 -7
@@ 1,5 1,8 @@
<template>
  <v-form ref="loadSectionForm" @submit.prevent v-model="formValid">
  <div v-if="isLoading" class="text-center">
    <v-progress-circular indeterminate></v-progress-circular>
  </div>
  <v-form v-else ref="loadSectionForm" @submit.prevent v-model="formValid">
    <v-row :class="{ edit: isEditing }">
      <v-col cols="1">
        <p>Section {{ section.sectionNumber }}</p>


@@ 11,7 14,7 @@
          variant="tonal"
          @click="machineState.setEditSection(section.sectionNumber)"
        >
          Load
          Setup
        </v-btn>
        <div v-else>
          <v-btn


@@ 26,7 29,7 @@
          <v-btn
            size="x-small"
            prepend-icon="mdi-cancel"
            color="info"
            color="warning"
            variant="tonal"
            @click="cancel"
          >


@@ 72,7 75,7 @@

  <v-row>
    <v-alert
      v-if="hasError"
      v-if="isEditing && hasError"
      color="error"
      title="Error"
      text="An unexpected error has occurred and some of your changes may not be applied."


@@ 81,9 84,9 @@
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, ref, onMounted } from 'vue'
import { vMaska } from 'maska'
import { vendingMachineStore } from '@/stores'
import { vendingMachineStore, websocketStore } from '@/stores'
import { BeverageSection } from '@/types/beverage-section'

const loadSectionForm = ref()


@@ 113,6 116,37 @@ const machineState = vendingMachineStore()
let section = machineState.getSectionByNumber(props.sectionNumber)
const isEditing = computed(() => section.sectionNumber === machineState.editSection)
let hasError = ref(false)
let isLoading = ref(false)
let sessionSetupTimeout = setTimeout(() => {}, 0)

const socketState = websocketStore()

onMounted(() => {
  initWebsocket()
})

function initWebsocket() {
  socketState.init(machineState.machineId)
  socketState.$subscribe((_, state) => {
    if (isLoading.value) {
      console.log('WS section state changed...', state.machine)

      const wsSection = state.machine.sections.find(
        (s) => s.sectionNumber === section.sectionNumber
      )
      if (wsSection?.beverageName === section.beverageName) {
        clearTimeout(sessionSetupTimeout)

        if (state.machine.processingError) {
          setError()
        } else {
          isLoading.value = false
          machineState.updateMachine(state.machine)
        }
      }
    }
  })
}

function saveSection() {
  loadSectionForm.value.validate()


@@ 120,6 154,7 @@ function saveSection() {
    return
  }

  isLoading.value = true
  hasError.value = false
  let beverageSection = new BeverageSection()
  beverageSection.beverageName = section.beverageName


@@ 127,8 162,11 @@ function saveSection() {
  beverageSection.quantity = section.quantity
  beverageSection.sectionNumber = section.sectionNumber

  sessionSetupTimeout = setTimeout(setError, 10000)

  machineState.saveSection(beverageSection).catch((error) => {
    hasError.value = true
    clearTimeout(sessionSetupTimeout)
    setError()
    console.error(error)
  })
}


@@ 139,6 177,11 @@ function cancel() {
  hasError.value = false
  machineState.resetEditSection()
}

function setError() {
  hasError.value = true
  isLoading.value = false
}
</script>

<style>

M frontend/src/components/TheNewMachineForm.vue => frontend/src/components/TheNewMachineForm.vue +23 -17
@@ 1,7 1,7 @@
<template>
  <v-sheet class="bg-deep-purple pa-12" rounded>
    <v-card class="mx-auto px-6 py-8" max-width="344">
      <h3>Create a new vending machine:</h3>
      <h3>Give a name or address for your vending machine:</h3>
      <br />
      <v-form ref="newMachineForm" @submit.prevent>
        <v-text-field


@@ 24,7 24,7 @@
          type="submit"
          @click="submit()"
        >
          Create
          Save
        </v-btn>
        <div v-else class="text-center">
          <v-progress-circular indeterminate></v-progress-circular>


@@ 45,7 45,7 @@

<script setup lang="ts">
import { vendingMachineStore, websocketStore } from '@/stores'
import { ref } from 'vue'
import { ref, onMounted } from 'vue'

const newMachineForm = ref()
let machineName = ref('')


@@ 64,22 64,28 @@ let createMachineTimeout = setTimeout(() => {}, 0)
const machineState = vendingMachineStore()

const socketState = websocketStore()
socketState.init(machineId)

socketState.$subscribe((_, state) => {
  console.log('WS machine state changed...', state)

  if (state.machine.machineId) {
    clearTimeout(createMachineTimeout)
onMounted(() => {
  initWebsocket()
})

    if (state.machine.processingError) {
      setError()
    } else {
      isLoading.value = false
      machineState.loadNewMachine(state.machine)
function initWebsocket() {
  socketState.init(machineId)
  socketState.$subscribe((_, state) => {
    console.log('WS new machine state changed...', state)

    if (isLoading.value && state.machine.machineId) {
      clearTimeout(createMachineTimeout)

      if (state.machine.processingError) {
        setError()
      } else {
        isLoading.value = false
        machineState.setNewMachine(state.machine)
      }
    }
  }
})
  })
}

function reset() {
  hasError.value = false


@@ 101,7 107,7 @@ async function submit() {

  hasError.value = false
  isLoading.value = true
  createMachineTimeout = setTimeout(setError, 5000)
  createMachineTimeout = setTimeout(setError, 10000)
  machineState.newVendindMachine(machineId, machineName.value, messageId).catch((error) => {
    clearTimeout(createMachineTimeout)
    setError()

M frontend/src/stores/vending-machine.ts => frontend/src/stores/vending-machine.ts +17 -1
@@ 27,6 27,11 @@ export const vendingMachineStore = defineStore('vending-machine', {
        sections: (state) => state.machine?.sections,
    },
    actions: {
        init() {
            if (sessionStorage.getItem("machineId")) {
                this.machine.machineId = sessionStorage.getItem("machineId")!
            }
        },
        async fetchMachine() {
            if (this.machineId) {
                const messageId = getNewUuid();


@@ 72,7 77,7 @@ export const vendingMachineStore = defineStore('vending-machine', {
            const dto = { machineId, machineName, messageId }
            await MACHINE_CMD_API.post("/machine", dto)
        },
        loadNewMachine(machine: Machine) {
        setNewMachine(machine: Machine) {
            this.machine = machine
            sessionStorage.setItem("machineId", machine.machineId)
            sessionStorage.setItem("machineName", machine.machineName)


@@ 80,6 85,17 @@ export const vendingMachineStore = defineStore('vending-machine', {
            for (let i = 1; i <= MAX_SECTION; i++) {
                this.machine.sections.push(new BeverageSection(i));
            }
        },
        updateMachine(machine: Machine) {
            this.machine = machine

            for (let i = 1; i <= MAX_SECTION; i++) {
                if (this.machine.sections[i]) {
                    continue
                }

                this.machine.sections.push(new BeverageSection(i));
            }
        }

    },

M frontend/src/stores/websocket-store.ts => frontend/src/stores/websocket-store.ts +1 -0
@@ 15,6 15,7 @@ export const websocketStore = defineStore('websocket-store', {
    },
    actions: {
        init(machineId: string) {
            console.log("Init websocket", machineId)
            if (!machineId) {
                return
            }

M frontend/src/views/MaintenanceView.vue => frontend/src/views/MaintenanceView.vue +1 -0
@@ 76,6 76,7 @@ let sectionLoadingError = ref(false)
const supportedCoinValues = ['10', '20', '50', '100', '200']

const machineState = vendingMachineStore()
machineState.init()
fetchMachine()

const coinState = coinStore()

M machine-query/src/main/java/com/vm/machine/query/domain/model/VendingMachineModel.java => machine-query/src/main/java/com/vm/machine/query/domain/model/VendingMachineModel.java +3 -1
@@ 1,7 1,9 @@
package com.vm.machine.query.domain.model;

import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;


@@ 16,7 18,7 @@ public class VendingMachineModel extends PanacheEntityBase {

  public String name;

  @OneToMany(mappedBy = "machine")
  @OneToMany(fetch = FetchType.EAGER, mappedBy = "machine", cascade = CascadeType.ALL)
  public List<SectionModel> sections;

  public VendingMachineModel() {

M machine-query/src/main/java/com/vm/machine/query/domain/queries/infra/VendingMachineEventHandler.java => machine-query/src/main/java/com/vm/machine/query/domain/queries/infra/VendingMachineEventHandler.java +7 -4
@@ 12,17 12,20 @@ public class VendingMachineEventHandler implements EventHandler{
  @Transactional
  @Override
  public VendingMachineModel on(SectionCreatedEvent event) {
    VendingMachineModel machine = VendingMachineModel.findById(event.getAggregateId());
    var sectionModel = new SectionModel();
    sectionModel.machine = VendingMachineModel.findById(event.getAggregateId());;
    sectionModel.sectionNumber = event.getSectionNumber();
    sectionModel.price = event.getBeveragePrice();
    sectionModel.beverageName = event.getBeverageName();
    sectionModel.quantity = event.getBeverageQuantity();
    sectionModel.setupDate = event.getSetupDate();
    
    sectionModel.persist();
    sectionModel.machine = machine;

    return sectionModel.machine;
    machine.sections.add(sectionModel);

    machine.persistAndFlush();

    return machine;
  }

  @Transactional

M machine-query/src/main/java/com/vm/machine/query/endpoints/WebsocketEndpoint.java => machine-query/src/main/java/com/vm/machine/query/endpoints/WebsocketEndpoint.java +4 -4
@@ 28,9 28,9 @@ public class WebsocketEndpoint {
    var existentSession = sessions.get(machineId);
    if(existentSession != null) {
      if(!existentSession.isOpen()) {
        //sessions.remove(machineId);
        sessions.remove(machineId);
      }else {
        LOGGER.info("A session with the machine " + machineId + " already exists.");
        //LOGGER.info("A session with the machine " + machineId + " already exists.");
        return;
      }
    }


@@ 53,7 53,7 @@ public class WebsocketEndpoint {

    if(!session.isOpen()){
      LOGGER.error("The session closed with the machine ID " + dto.getMachineId());
      //sessions.remove(dto.getMachineId());
      sessions.remove(dto.getMachineId());
      return;
    }



@@ 79,7 79,7 @@ public class WebsocketEndpoint {

    if(!session.isOpen()){
      LOGGER.error("The session closed with the machine ID " + dto.getMachineId());
      //sessions.remove(dto.getMachineId());
      sessions.remove(dto.getMachineId());
      return;
    }