Client: Kunden-Datenhaltung auf Server-REST-Endpunkte umgestellt
In-Memory-Datenhaltung (kundenDaten, getNewKundeId, addKunde, updateKunde, getKunden) aus kunde.ts entfernt. Die Kundenliste und das Formular nutzen jetzt fetchKunden/createKundeREST/updateKundeREST asynchron vom Server. projekt.ts, kontakt.ts, call_log.ts: getKunden() durch asynchrones fetchKunden() im oninit ersetzt, Kundenliste im Closure-State gehalten. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
1 parent
13eaaec9c1
commit
15d4e2ac48
5 files changed
+56
-76
No files matched your search
@@ -4,7 +4,7 @@ import { Input, iInput, Textarea, iTextarea} from "./widgets/inputs"
|
||||
import {Select, iSelect, iSelectOption} from "./widgets/select"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iCallLog, getCallLogsByProjektId, getNewCallLogId, addCallLogData, updateCallLogData} from "../models/call_log"
|
||||
import {iKunde, getKunden} from "../models/kunde"
|
||||
import {iKunde, fetchKunden} from "../models/kunde"
|
||||
import {getProjekteByKundenId, getProjektById} from "../models/projekt"
|
||||
import {getKontaktadressenByProjektId, getKontaktadresseById} from "../models/kontaktadresse"
|
||||
|
||||
@@ -190,6 +190,8 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
// ohne Redraw aktualisieren kann (ein Redraw würde die übrigen Felder
|
||||
// mit den veralteten currentLog-Werten überschreiben).
|
||||
let dauerInput: HTMLInputElement | null = null
|
||||
// Kundenliste asynchron vom Server laden, für Select-Optionen.
|
||||
let kundenListe: iKunde[] = []
|
||||
|
||||
/**
|
||||
* Formatiert verstrichene Sekunden als mm:ss (Minuten:Sekunden).
|
||||
@@ -246,6 +248,10 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
}, DAUER_UPDATE_INTERVALL)
|
||||
}
|
||||
}
|
||||
// Kundenliste asynchron vom Server laden.
|
||||
fetchKunden().then((result) => {
|
||||
kundenListe = result
|
||||
})
|
||||
},
|
||||
onremove: (vnode) => {
|
||||
// Timer stoppen, damit er nach Verlassen des Views nicht weiterläuft.
|
||||
@@ -253,7 +259,7 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
},
|
||||
view: (vnode) => {
|
||||
// Select-Optionen aus Kunden- und Projektliste aufbauen.
|
||||
const kundenOptionen: iSelectOption[] = getKunden().map((k: iKunde) => {
|
||||
const kundenOptionen: iSelectOption[] = kundenListe.map((k: iKunde) => {
|
||||
return {value: k.id, label: k.name}
|
||||
})
|
||||
// Projekt-Optionen sind vom gewählten Kunden abhängig.
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Input, iInput, Textarea, iTextarea} from "./widgets/inputs"
|
||||
import {Select, iSelect, iSelectOption} from "./widgets/select"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iKontakt, getKontakteByKundenId, getNewKontaktId, addKontakt, updateKontakt} from "../models/kontakt"
|
||||
import {iKunde, getKunden} from "../models/kunde"
|
||||
import {iKunde, fetchKunden} from "../models/kunde"
|
||||
|
||||
function createKontaktTreenodes(kundenId: number | null = null): iTreenode[] {
|
||||
let filteredKontakte = getKontakteByKundenId(kundenId)
|
||||
@@ -18,6 +18,9 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
|
||||
let treenodes: iTreenode[] = createKontaktTreenodes()
|
||||
let selectedNode: iTreenode | null = null
|
||||
let filterKundenId: number | null = null
|
||||
// Kundenliste asynchron vom Server laden, für die Kundenauflösung
|
||||
// beim Anlegen eines neuen Kontakts.
|
||||
let kundenListe: iKunde[] = []
|
||||
|
||||
const handleRowMarked = (node: iTreenode) => {
|
||||
selectedNode = node
|
||||
@@ -35,7 +38,7 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
|
||||
}
|
||||
// Nur bei kundengefilterter Liste den Kunden vorbelegen.
|
||||
if (filterKundenId !== null) {
|
||||
const kunde = getKunden().find((k: iKunde) => k.id === filterKundenId)
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
|
||||
if (kunde) {
|
||||
params.kundenId = kunde.id
|
||||
params.kundenname = kunde.name
|
||||
@@ -91,6 +94,10 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
|
||||
filterKundenId = null
|
||||
}
|
||||
treenodes = createKontaktTreenodes(filterKundenId)
|
||||
// Kundenliste asynchron vom Server laden.
|
||||
fetchKunden().then((result) => {
|
||||
kundenListe = result
|
||||
})
|
||||
},
|
||||
view: (vnode) => {
|
||||
return m("div.w3-container.w3-auto", {
|
||||
@@ -145,6 +152,9 @@ export const Kontakt: m.ClosureComponent = (vnode) => {
|
||||
}
|
||||
// Ist der Kunde voreingestellt (gefilterte Kontaktliste)?
|
||||
let kundeVoreingestellt: boolean = false
|
||||
// Kundenliste asynchron vom Server laden, für Select-Optionen und
|
||||
// Namensauflösung im submit-Handler.
|
||||
let kundenListe: iKunde[] = []
|
||||
|
||||
return {
|
||||
oninit: (vnode) => {
|
||||
@@ -164,13 +174,16 @@ export const Kontakt: m.ClosureComponent = (vnode) => {
|
||||
notiz: routeParams.notiz || ""
|
||||
}
|
||||
}
|
||||
fetchKunden().then((result) => {
|
||||
kundenListe = result
|
||||
})
|
||||
},
|
||||
view: (vnode) => {
|
||||
const submit = (form: HTMLFormElement): boolean => {
|
||||
const formData = new FormData(form)
|
||||
const kundenId = parseInt(formData.get("kundenId") as string)
|
||||
// Kundennamen zur gewählten kundenId auflösen.
|
||||
const kunde = getKunden().find((k: iKunde) => k.id === kundenId)
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === kundenId)
|
||||
const gespeicherterKontakt: iKontakt = {
|
||||
id: currentKontakt.id,
|
||||
kundenId: kundenId,
|
||||
@@ -195,7 +208,7 @@ export const Kontakt: m.ClosureComponent = (vnode) => {
|
||||
m.route.set("/kontaktliste")
|
||||
}
|
||||
// Select-Optionen aus der Kundenliste aufbauen.
|
||||
const kundenOptionen: iSelectOption[] = getKunden().map((k: iKunde) => {
|
||||
const kundenOptionen: iSelectOption[] = kundenListe.map((k: iKunde) => {
|
||||
return {value: k.id, label: k.name}
|
||||
})
|
||||
return m("div.w3-container.w3-auto.form-view-container",
|
||||
|
||||
+11
-18
@@ -2,7 +2,7 @@ import m from "mithril"
|
||||
import {Form, iForm} from "./widgets/form"
|
||||
import { Input, iInput} from "./widgets/inputs"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iKunde, kundenDaten, getNewKundeId, addKunde, updateKunde} from "../models/kunde"
|
||||
import {iKunde, fetchKunden, createKundeREST, updateKundeREST} from "../models/kunde"
|
||||
|
||||
export const kunde: m.ClosureComponent = (vnode) => {
|
||||
let currentKunde: iKunde = {
|
||||
@@ -40,12 +40,10 @@ export const kunde: m.ClosureComponent = (vnode) => {
|
||||
land: (formData.get("land") as string) || ""
|
||||
}
|
||||
if (currentKunde.id === -1) {
|
||||
gespeicherterKunde.id = getNewKundeId()
|
||||
addKunde(gespeicherterKunde)
|
||||
createKundeREST(gespeicherterKunde).then(() => m.route.set("/kundenliste"))
|
||||
} else {
|
||||
updateKunde(gespeicherterKunde)
|
||||
updateKundeREST(gespeicherterKunde).then(() => m.route.set("/kundenliste"))
|
||||
}
|
||||
m.route.set("/kundenliste")
|
||||
return true
|
||||
}
|
||||
const cancel = (e: Event) => {
|
||||
@@ -74,20 +72,8 @@ export const kunde: m.ClosureComponent = (vnode) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt aus der Kundendatenliste die Treenode-Struktur für die Treetable der
|
||||
* Kundenliste. Jeder Kunde wird zu einem expandierten Treenode ohne Kinder
|
||||
* (expand=true, children=[]) - d.h. ein Blattknoten, der sofort in der
|
||||
* Tabelle sichtbar ist und sich nicht weiter aufklappen lässt.
|
||||
*/
|
||||
function createKundenTreenodes(): iTreenode[] {
|
||||
return kundenDaten.map((kunde: iKunde) => {
|
||||
return new Treenode(kunde, true, [])
|
||||
})
|
||||
}
|
||||
|
||||
export const kundenliste: m.ClosureComponent = (vnode) => {
|
||||
let treenodes: iTreenode[] = createKundenTreenodes()
|
||||
let treenodes: iTreenode[] = []
|
||||
let selectedNode: iTreenode | null = null
|
||||
|
||||
const handleRowMarked = (node: iTreenode) => {
|
||||
@@ -141,6 +127,13 @@ export const kundenliste: m.ClosureComponent = (vnode) => {
|
||||
}
|
||||
|
||||
return {
|
||||
oninit: (vnode) => {
|
||||
// Kundenliste asynchron vom Server laden. m.request löst nach
|
||||
// Promise-Auflösung automatisch ein Redraw aus.
|
||||
fetchKunden().then((kunden: iKunde[]) => {
|
||||
treenodes = kunden.map((kunde: iKunde) => new Treenode(kunde, true, []))
|
||||
})
|
||||
},
|
||||
view: (vnode) => {
|
||||
return m("div.w3-container.w3-auto", {
|
||||
style: {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Input, iInput} from "./widgets/inputs"
|
||||
import {Select, iSelect, iSelectOption} from "./widgets/select"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iProjekt, getProjekteByKundenId, getNewProjektId, addProjekt, updateProjekt} from "../models/projekt"
|
||||
import {iKunde, getKunden} from "../models/kunde"
|
||||
import {iKunde, fetchKunden} from "../models/kunde"
|
||||
|
||||
function createProjektTreenodes(kundenId: number | null = null): iTreenode[] {
|
||||
let filteredProjekte = getProjekteByKundenId(kundenId)
|
||||
@@ -18,6 +18,9 @@ export const projektliste: m.ClosureComponent = (vnode) => {
|
||||
let treenodes: iTreenode[] = createProjektTreenodes()
|
||||
let selectedNode: iTreenode | null = null
|
||||
let filterKundenId: number | null = null
|
||||
// Kundenliste asynchron vom Server laden, für die Kundenauflösung
|
||||
// beim Anlegen eines neuen Projekts.
|
||||
let kundenListe: iKunde[] = []
|
||||
|
||||
const handleRowMarked = (node: iTreenode) => {
|
||||
selectedNode = node
|
||||
@@ -34,7 +37,7 @@ export const projektliste: m.ClosureComponent = (vnode) => {
|
||||
}
|
||||
// Nur bei kundengefilterter Liste den Kunden vorbelegen.
|
||||
if (filterKundenId !== null) {
|
||||
const kunde = getKunden().find((k: iKunde) => k.id === filterKundenId)
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
|
||||
if (kunde) {
|
||||
params.kundenId = kunde.id
|
||||
params.kundenname = kunde.name
|
||||
@@ -125,6 +128,10 @@ export const projektliste: m.ClosureComponent = (vnode) => {
|
||||
filterKundenId = null
|
||||
}
|
||||
treenodes = createProjektTreenodes(filterKundenId)
|
||||
// Kundenliste asynchron vom Server laden.
|
||||
fetchKunden().then((result) => {
|
||||
kundenListe = result
|
||||
})
|
||||
},
|
||||
view: (vnode) => {
|
||||
return m("div.w3-container.w3-auto", {
|
||||
@@ -175,6 +182,9 @@ export const Projekt: m.ClosureComponent = (vnode) => {
|
||||
}
|
||||
// Ist der Kunde voreingestellt (gefilterte Projektliste)?
|
||||
let kundeVoreingestellt: boolean = false
|
||||
// Kundenliste asynchron vom Server laden, für Select-Optionen und
|
||||
// Namensauflösung im submit-Handler.
|
||||
let kundenListe: iKunde[] = []
|
||||
|
||||
return {
|
||||
oninit: (vnode) => {
|
||||
@@ -192,13 +202,16 @@ export const Projekt: m.ClosureComponent = (vnode) => {
|
||||
startdatum: routeParams.startdatum || ""
|
||||
}
|
||||
}
|
||||
fetchKunden().then((result) => {
|
||||
kundenListe = result
|
||||
})
|
||||
},
|
||||
view: (vnode) => {
|
||||
const submit = (form: HTMLFormElement): boolean => {
|
||||
const formData = new FormData(form)
|
||||
const kundenId = parseInt(formData.get("kundenId") as string)
|
||||
// Kundennamen zur gewählten kundenId auflösen.
|
||||
const kunde = getKunden().find((k: iKunde) => k.id === kundenId)
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === kundenId)
|
||||
const gespeichertesProjekt: iProjekt = {
|
||||
id: currentProjekt.id,
|
||||
kundenId: kundenId,
|
||||
@@ -221,7 +234,7 @@ export const Projekt: m.ClosureComponent = (vnode) => {
|
||||
m.route.set("/projektliste")
|
||||
}
|
||||
// Select-Optionen aus der Kundenliste aufbauen.
|
||||
const kundenOptionen: iSelectOption[] = getKunden().map((k: iKunde) => {
|
||||
const kundenOptionen: iSelectOption[] = kundenListe.map((k: iKunde) => {
|
||||
return {value: k.id, label: k.name}
|
||||
})
|
||||
return m("div.w3-container.w3-auto.form-view-container",
|
||||
|
||||
+3
-48
@@ -12,57 +12,11 @@ export interface iKunde {
|
||||
land: string
|
||||
}
|
||||
|
||||
/**
|
||||
* In-Memory-Datenspeicher für Kunden. Wird als Fallback solange verwendet,
|
||||
* bis die serverseitigen REST-Endpunkte verfügbar sind.
|
||||
*/
|
||||
export const kundenDaten: iKunde[] = [
|
||||
{id: 1, name: "Musterfirma GmbH", strasse: "Musterstraße 1", plz: "12345", ort: "Musterstadt", land: "Deutschland"},
|
||||
{id: 2, name: "Beispiel AG", strasse: "Beispielweg 2", plz: "54321", ort: "Beispielstadt", land: "Deutschland"},
|
||||
{id: 3, name: "Test Unternehmen", strasse: "Testallee 3", plz: "67890", ort: "Testdorf", land: "Österreich"}
|
||||
]
|
||||
|
||||
/**
|
||||
* Liefert die nächste freie Kunden-ID auf Basis des In-Memory-Speichers.
|
||||
* Sobald die serverseitige ID-Vergabe verfügbar ist, entfällt diese Funktion.
|
||||
*/
|
||||
export function getNewKundeId(): number {
|
||||
if (kundenDaten.length === 0) {
|
||||
return 1
|
||||
}
|
||||
return Math.max(...kundenDaten.map((kunde: iKunde) => kunde.id)) + 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt einen neuen Kunden dem In-Memory-Speicher hinzu.
|
||||
*/
|
||||
export function addKunde(kunde: iKunde): void {
|
||||
kundenDaten.push(kunde)
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert einen bestehenden Kunden im In-Memory-Speicher.
|
||||
*/
|
||||
export function updateKunde(kunde: iKunde): void {
|
||||
const index = kundenDaten.findIndex((k: iKunde) => k.id === kunde.id)
|
||||
if (index !== -1) {
|
||||
kundenDaten[index] = kunde
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert eine Kopie aller Kunden aus dem In-Memory-Speicher.
|
||||
*/
|
||||
export function getKunden(): iKunde[] {
|
||||
return [...kundenDaten]
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* REST-API-Aufrufe (Client-Seite) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Die folgenden Funktionen kapseln die Kommunikation mit den */
|
||||
/* serverseitigen REST-Endpunkten. Die Endpunkte sind noch nicht */
|
||||
/* implementiert und werden später nachgereicht. */
|
||||
/* serverseitigen REST-Endpunkten (/xhr/kunde/*). */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
@@ -92,7 +46,8 @@ export function fetchKundeById(id: number): Promise<iKunde> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Legt einen neuen Kunden serverseitig an.
|
||||
* Legt einen neuen Kunden serverseitig an. Die ID wird vom Server
|
||||
* vergeben und im zurückgegebenen Kundenobjekt gesetzt.
|
||||
*/
|
||||
export function createKundeREST(kunde: iKunde): Promise<iKunde> {
|
||||
return m.request({
|
||||
|
||||
Reference in new issue
Block a user