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;
}