V 1.0.0 erste sauber lauffähige Version
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "beoanswer_react",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
112
src/App.jsx
112
src/App.jsx
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { FormProvider, useFormData } from './FormContext'
|
||||
import packageJson from '../package.json'
|
||||
import './App.css'
|
||||
import FandStattVer from './components/FandStattVer.jsx'
|
||||
import BesucherBar from './components/BesucherBar.jsx'
|
||||
@@ -16,16 +17,18 @@ function AppContent() {
|
||||
const [name, setName] = useState("")
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState(null)
|
||||
const [mitsend, setMitsend] = useState(false)
|
||||
const [mitback, setMitback] = useState(false)
|
||||
|
||||
const version = "1.0.0"
|
||||
const vdate = "2025-11-23"
|
||||
const version = packageJson.version
|
||||
const vdate = new Date().toLocaleDateString('de-DE')
|
||||
|
||||
// States
|
||||
const [schritt, setSchritt] = useState(0)
|
||||
const [pfad, setPfad] = useState('')
|
||||
|
||||
// Hole formData aus dem Context
|
||||
const { formData } = useFormData()
|
||||
const { formData, updateFormData } = useFormData()
|
||||
|
||||
// URL-Parameter und Backend-Aufruf
|
||||
useEffect(() => {
|
||||
@@ -106,24 +109,76 @@ function AppContent() {
|
||||
|
||||
// Callbacks:
|
||||
const handleFandStattVerNext = (auswahl) => {
|
||||
setPfad(auswahl)
|
||||
setSchritt(1)
|
||||
auswahl && setPfad(auswahl)
|
||||
handleNext()
|
||||
}
|
||||
|
||||
const handleNext = () => {
|
||||
setSchritt((schritt) => schritt + 1)
|
||||
}
|
||||
|
||||
const handleBack = () => {
|
||||
if (schritt > 0) {
|
||||
const neuerSchritt = schritt - 1
|
||||
setSchritt(neuerSchritt)
|
||||
|
||||
// Entsprechende FormData-Felder zurücksetzen je nach Schritt und Pfad
|
||||
if (pfad === 'ja') {
|
||||
// JA-Pfad rückwärts
|
||||
if (schritt === 1) {
|
||||
// Von Besucher zurück zu ja/nein → Pfad löschen
|
||||
setPfad('')
|
||||
updateFormData('stattgefunden', '')
|
||||
} else if (schritt === 2) {
|
||||
// Von Spende zurück zu Besucher → Besucher löschen
|
||||
updateFormData('besucher', '')
|
||||
} else if (schritt === 3) {
|
||||
// Von Betrag/Bemerkungen zurück zu Spende → Spende löschen
|
||||
updateFormData('spendenArt', '')
|
||||
} else if (schritt === 4) {
|
||||
// Von Bemerkungen zurück → Betrag löschen (bei Bar-Spende)
|
||||
updateFormData('betrag', '')
|
||||
} else if (schritt === 5) {
|
||||
// Von Senden zurück → Bemerkungen löschen
|
||||
updateFormData('bemerkungen', '')
|
||||
}
|
||||
} else if (pfad === 'nein') {
|
||||
// NEIN-Pfad rückwärts
|
||||
if (schritt === 1) {
|
||||
// Von abgesagt/verschoben zurück zu ja/nein → Pfad löschen
|
||||
setPfad('')
|
||||
updateFormData('stattgefunden', '')
|
||||
} else if (schritt === 2) {
|
||||
// Von Datum/Senden zurück zu abgesagt/verschoben → abgesagt löschen
|
||||
updateFormData('abgesagt', '')
|
||||
} else if (schritt === 3) {
|
||||
// Von Senden zurück → neues Datum löschen (bei verschoben)
|
||||
updateFormData('neuesDatum', '')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const setBackButton = () => {
|
||||
setMitback(true)
|
||||
}
|
||||
|
||||
// Welche Komponeneten werden angezeigt:
|
||||
const renderCoponents = () => {
|
||||
const components = []
|
||||
|
||||
// Schritt 0: ja/nein - Auswahl
|
||||
components.push(
|
||||
<FandStattVer key="fandstatt" left='ja' right='nein' title='Fand die Führung statt?' onNext={handleFandStattVerNext} iscompleted={schritt > 1} />
|
||||
<FandStattVer key="fandstatt" left='ja' right='nein' title='Fand die Führung statt?'
|
||||
onNext={handleFandStattVerNext}
|
||||
setbackButton={setBackButton}
|
||||
iscompleted={schritt > 1} />
|
||||
)
|
||||
if (schritt === 0)
|
||||
if (schritt === 0) {
|
||||
// Bei ja/nein Auswahl: Kein Zurück-Button, kein Senden-Button
|
||||
components.push(<LastButtons key='lastbutt' mitSend={false} mitBack={false} handleBack={handleBack}/>)
|
||||
return components
|
||||
}
|
||||
|
||||
// JA-Pfad:
|
||||
if (pfad === 'ja') {
|
||||
@@ -152,13 +207,6 @@ function AppContent() {
|
||||
)
|
||||
}
|
||||
|
||||
// Schritt 5 (bei Bar-Spende) oder Schritt 4 (bei anderen Spenden): unterste Buttons
|
||||
const endeSchritt = (formData.spendenArt === 'bar') ? 5 : 4
|
||||
if (schritt >= endeSchritt) {
|
||||
components.push(<LastButtons key='lastbutt' />
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
// NEIN - Pfad
|
||||
if (pfad === 'nein') {
|
||||
@@ -166,7 +214,10 @@ function AppContent() {
|
||||
// Schritt 1: abgesagt / verschoben
|
||||
if (schritt >= 1) {
|
||||
components.push(
|
||||
<FandStattVer key="abgesagt" left='abgesagt' right='verschoben' title='Die Führung wurde' radioName='abgesagt' onNext={handleNext} iscompleted={schritt > 1} />
|
||||
<FandStattVer key="abgesagt" left='abgesagt' right='verschoben' title='Die Führung wurde' radioName='abgesagt'
|
||||
onNext={handleNext}
|
||||
setbackButton={setBackButton}
|
||||
iscompleted={schritt > 1} />
|
||||
)
|
||||
}
|
||||
|
||||
@@ -176,14 +227,31 @@ function AppContent() {
|
||||
)
|
||||
}
|
||||
|
||||
// Schritt 4 (bei verschoben) oder Schritt 3 (bei absage): unterste Buttons
|
||||
const endeNeinSchritt = (formData.abgesagt === 'verschoben') ? 3 : 2
|
||||
if (schritt >= endeNeinSchritt) {
|
||||
components.push(<LastButtons key='lastbutt' />
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Zurück-Button nur anzeigen wenn nicht bei ja/nein Auswahl
|
||||
const backVerfuegbar = schritt > 0
|
||||
|
||||
// LastButtons IMMER anzeigen, aber Senden-Button nur wenn bereit
|
||||
const sendenBereit = () => {
|
||||
if (pfad === 'ja') {
|
||||
// JA-Pfad: vollständig wenn Bemerkungen-Schritt erreicht
|
||||
const bemerkungsSchritt = (formData.spendenArt === 'bar') ? 4 : 3
|
||||
return schritt >= bemerkungsSchritt
|
||||
} else if (pfad === 'nein') {
|
||||
// NEIN-Pfad: vollständig wenn abgesagt ODER verschoben mit Datum
|
||||
if (formData.abgesagt === 'abgesagt') {
|
||||
return schritt >= 2
|
||||
} else if (formData.abgesagt === 'verschoben') {
|
||||
return schritt >= 3 && formData.neuesDatum
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// LastButtons immer anzeigen
|
||||
components.push(<LastButtons key='lastbutt' mitSend={sendenBereit()} mitBack={backVerfuegbar} handleBack={handleBack} />)
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { createContext, useContext, useState } from 'react'
|
||||
const FormContext = createContext()
|
||||
|
||||
export function FormProvider({ children }) {
|
||||
console.log('🚀 FormProvider initialisiert')
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
stattgefunden: '',
|
||||
@@ -20,19 +19,16 @@ export function FormProvider({ children }) {
|
||||
})
|
||||
|
||||
const updateFormData = (field, value) => {
|
||||
console.log('📝 FormContext UPDATE:', field, '=', value)
|
||||
setFormData(prev => {
|
||||
const newData = {
|
||||
...prev,
|
||||
[field]: value
|
||||
}
|
||||
console.log('📊 FormContext NEU:', newData)
|
||||
return newData
|
||||
})
|
||||
}
|
||||
|
||||
const resetFormData = () => {
|
||||
console.log('🔄 FormContext RESET')
|
||||
|
||||
setFormData({
|
||||
stattgefunden: '',
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react'
|
||||
import { useFormData } from '../FormContext'
|
||||
import Modal from './Modal'
|
||||
|
||||
export default function FandStattVer({left, right, title, onNext, radioName = "fst"}) {
|
||||
export default function FandStattVer({left, right, title, onNext, radioName = "fst", setbackButton}) {
|
||||
const { formData, updateFormData } = useFormData()
|
||||
|
||||
// Bestimme das Feld basierend auf radioName
|
||||
@@ -11,9 +11,14 @@ export default function FandStattVer({left, right, title, onNext, radioName = "f
|
||||
|
||||
const handleRadioChange = (e) => {
|
||||
const value = e.target.value
|
||||
setAuswahl(value)
|
||||
updateFormData(fieldName, value)
|
||||
onNext(value)
|
||||
setbackButton(true)
|
||||
if(radioName !== 'abgesagt') {
|
||||
setAuswahl(value)
|
||||
onNext(value)
|
||||
} else {
|
||||
onNext()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,51 +3,52 @@ import { useFormData } from '../FormContext'
|
||||
import Modal from './Modal'
|
||||
import ConfirmModal from './ConfirmModal'
|
||||
|
||||
export default function LastButtons() {
|
||||
|
||||
const { formData } = useFormData()
|
||||
export default function LastButtons({ mitSend, mitBack, handleBack}) {
|
||||
|
||||
const { formData, resetFormData } = useFormData()
|
||||
const [isSending, setIsSending] = useState(false)
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [modalMessage, setModalMessage] = useState('')
|
||||
const [modalType, setModalType] = useState('error') // 'error' oder 'success'
|
||||
const [showConfirmModal, setShowConfirmModal] = useState(false)
|
||||
|
||||
const [isSuccessModal, setIsSuccessModal] = useState(false)
|
||||
|
||||
const handleSenden = async () => {
|
||||
console.log("Alle Formulardaten: ", formData)
|
||||
|
||||
|
||||
setIsSending(true)
|
||||
|
||||
|
||||
try {
|
||||
// API URL und Auth-Daten aus Environment
|
||||
const APIURL = import.meta.env.VITE_API_URL
|
||||
const username = import.meta.env.VITE_API_USERNAME
|
||||
const password = import.meta.env.VITE_API_PASSWORD
|
||||
|
||||
|
||||
if (!APIURL) {
|
||||
throw new Error('API URL nicht konfiguriert.')
|
||||
}
|
||||
|
||||
|
||||
// URL-Parameter für ID auslesen
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const id = urlParams.get('id')
|
||||
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Keine ID in der URL gefunden.')
|
||||
}
|
||||
|
||||
|
||||
// FormData für PHP Backend erstellen
|
||||
const backendData = new FormData()
|
||||
backendData.append('cmd', 'UPDATEAFTER')
|
||||
backendData.append('id', id)
|
||||
|
||||
|
||||
// Formulardaten zu Backend-Feldern mappen
|
||||
// Basis-Status
|
||||
if (formData.stattgefunden === 'ja') {
|
||||
backendData.append('stattgefunden', '1')
|
||||
|
||||
|
||||
// Spenden-Informationen
|
||||
if (formData.spendenArt) {
|
||||
switch(formData.spendenArt) {
|
||||
switch (formData.spendenArt) {
|
||||
case 'bar':
|
||||
backendData.append('bezahlt', `Kasse ${formData.betrag}€)`)
|
||||
break
|
||||
@@ -62,7 +63,7 @@ export default function LastButtons() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else if (formData.stattgefunden === 'nein') {
|
||||
backendData.append('stattgefunden', '0')
|
||||
backendData.append('bezahlt', 'keine')
|
||||
@@ -71,19 +72,19 @@ export default function LastButtons() {
|
||||
if (formData.abgesagt === 'abgesagt') {
|
||||
backendData.append('status', 3)
|
||||
} else if (formData.abgesagt === 'verschoben') {
|
||||
backendData.append('wtermin', formData.neuesDatum || '1900-01-01 00:00:00')
|
||||
backendData.append('wtermin', formData.neuesDatum || '1900-01-01 00:00:00')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Bemerkungen
|
||||
backendData.append('remark', formData.bemerkungen || '')
|
||||
// Besucher
|
||||
backendData.append('besucher', formData.besucher || '0')
|
||||
|
||||
|
||||
// // Bearbeitungsdatum setzen
|
||||
// const now = new Date().toISOString().slice(0, 19).replace('T', ' ')
|
||||
// backendData.append('bearbeitet_am', now)
|
||||
|
||||
|
||||
// Debug: FormData kann nicht direkt geloggt werden, deshalb iterieren
|
||||
console.log("=== FORM DATA DEBUG ===")
|
||||
console.log("Original formData aus Context:", formData)
|
||||
@@ -93,46 +94,60 @@ export default function LastButtons() {
|
||||
console.log(` ${key}: ${value}`)
|
||||
}
|
||||
console.log("========================")
|
||||
/*
|
||||
|
||||
// HTTP Basic Authentication Header
|
||||
const headers = {}
|
||||
if (username && password) {
|
||||
const credentials = btoa(`${username}:${password}`)
|
||||
headers['Authorization'] = `Basic ${credentials}`
|
||||
}
|
||||
|
||||
|
||||
// Backend-Aufruf
|
||||
const response = await fetch(APIURL, {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: backendData
|
||||
})
|
||||
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server-Fehler: ${response.status}`)
|
||||
}
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
if (result.success) {
|
||||
|
||||
// Backend Response auslesen
|
||||
const responseText = await response.text()
|
||||
console.log('Backend Response (raw):', responseText)
|
||||
|
||||
let result
|
||||
try {
|
||||
// Versuche JSON zu parsen
|
||||
result = JSON.parse(responseText)
|
||||
console.log('Backend Response (parsed):', result)
|
||||
} catch (e) {
|
||||
// Falls kein JSON, behandle als einfachen Text
|
||||
console.log('Backend Response ist kein JSON, behandle als Text')
|
||||
result = { success: responseText.trim() === 'true', raw: responseText }
|
||||
}
|
||||
|
||||
// Erfolg prüfen - sowohl JSON als auch Text-Format unterstützen
|
||||
const isSuccess = result.success === true ||
|
||||
result.success === 'true' ||
|
||||
responseText.trim() === 'true'
|
||||
|
||||
if (isSuccess) {
|
||||
setModalType('success')
|
||||
setModalMessage('✅ Daten erfolgreich gespeichert!')
|
||||
setIsSuccessModal(true)
|
||||
setShowModal(true)
|
||||
|
||||
// Nach erfolgreicher Speicherung könnte man zur Übersicht zurück
|
||||
setTimeout(() => {
|
||||
// Optional: Weiterleitung oder Formular zurücksetzen
|
||||
console.log('Erfolgreich gespeichert:', result)
|
||||
}, 2000)
|
||||
|
||||
|
||||
} else {
|
||||
throw new Error(result.message || 'Unbekannter Fehler beim Speichern')
|
||||
throw new Error(result.message || result.error || 'Unbekannter Fehler beim Speichern')
|
||||
}
|
||||
*/
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern:', error)
|
||||
setModalType('error')
|
||||
setModalMessage(`❌ Fehler beim Speichern: ${error.message}`)
|
||||
setIsSuccessModal(false)
|
||||
setShowModal(true)
|
||||
} finally {
|
||||
setIsSending(false)
|
||||
@@ -145,8 +160,17 @@ export default function LastButtons() {
|
||||
|
||||
const confirmAbbruch = () => {
|
||||
setShowConfirmModal(false)
|
||||
// Zurück zur vorherigen Seite oder Startseite
|
||||
window.history.back()
|
||||
|
||||
// Versuche das Browser-Fenster zu schließen (wie beim Speichern)
|
||||
window.close()
|
||||
|
||||
// Fallback: Falls window.close() nicht funktioniert
|
||||
setTimeout(() => {
|
||||
if (!window.closed) {
|
||||
// Wenn das Fenster nicht geschlossen werden kann, zur vorherigen Seite
|
||||
window.location.reload()
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
const cancelAbbruch = () => {
|
||||
@@ -176,10 +200,50 @@ export default function LastButtons() {
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
setShowModal(false)
|
||||
setModalMessage('')
|
||||
if (isSuccessModal) {
|
||||
// Bei erfolgreichem Speichern: Browser-Fenster schließen
|
||||
console.log('Schließe Browser-Fenster nach erfolgreichem Speichern...')
|
||||
|
||||
// Formular zurücksetzen (für den Fall, dass das Schließen nicht funktioniert)
|
||||
resetFormData()
|
||||
|
||||
// Browser-Fenster schließen
|
||||
window.close()
|
||||
|
||||
// Fallback: Falls window.close() nicht funktioniert (z.B. bei direkt aufgerufenen URLs)
|
||||
// Nach 100ms prüfen, ob das Fenster noch offen ist
|
||||
setTimeout(() => {
|
||||
// Wenn das Fenster noch offen ist, zur vorherigen Seite oder Neustart
|
||||
if (!window.closed) {
|
||||
console.log('Fenster konnte nicht geschlossen werden, führe Neustart durch...')
|
||||
window.location.reload()
|
||||
}
|
||||
}, 100)
|
||||
|
||||
} else {
|
||||
// Normales Modal schließen
|
||||
setShowModal(false)
|
||||
setModalMessage('')
|
||||
setIsSuccessModal(false)
|
||||
}
|
||||
}
|
||||
|
||||
const sendeButton = mitSend ?
|
||||
<button
|
||||
className="btnsend"
|
||||
onClick={handleSenden}
|
||||
disabled={isSending}
|
||||
>
|
||||
{isSending ? 'Speichert...' : 'Senden'}
|
||||
</button>
|
||||
: null
|
||||
|
||||
const backButton = mitBack ?
|
||||
<button className="btnback" onClick={handleBack}>
|
||||
Zurück
|
||||
</button>
|
||||
: null
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="lastbuttons">
|
||||
@@ -189,23 +253,18 @@ export default function LastButtons() {
|
||||
<button className="btnanleit" onClick={handleAnleitung}>
|
||||
Anleitung
|
||||
</button>
|
||||
<button
|
||||
className="btnsend"
|
||||
onClick={handleSenden}
|
||||
disabled={isSending}
|
||||
>
|
||||
{isSending ? 'Speichert...' : 'Senden'}
|
||||
</button>
|
||||
{backButton}
|
||||
{sendeButton}
|
||||
</div>
|
||||
|
||||
|
||||
{showModal && (
|
||||
<Modal
|
||||
<Modal
|
||||
message={modalMessage}
|
||||
onClose={closeModal}
|
||||
type={modalType}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
{showConfirmModal && (
|
||||
<ConfirmModal
|
||||
message={`Möchten Sie wirklich abbrechen?
|
||||
|
||||
Reference in New Issue
Block a user