'Senden'-Button kam zu früh - ist behoben
Anleitung als HTML extern
This commit is contained in:
275
README.md
275
README.md
@@ -1,16 +1,273 @@
|
||||
# React + Vite
|
||||
# BeoAnswer React App
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
Eine React-Anwendung zur Nachbearbeitung von Sonderführungen mit Backend-Integration.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
## 📋 Features
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
- **Interaktive Formulare** für Führungsnachbearbeitung
|
||||
- **Backend-Integration** mit PHP über FormData
|
||||
- **HTTP Basic Authentication** Support
|
||||
- **Professionelle Modal-Dialoge** anstatt Browser-Alerts
|
||||
- **Intelligente Navigation** mit Zurück-Button
|
||||
- **Automatisches Fenster schließen** nach Aktionen
|
||||
- **Environment-Variable Konfiguration**
|
||||
- **Responsive Design**
|
||||
|
||||
## React Compiler
|
||||
## 🚀 Quick Start
|
||||
|
||||
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||
### Voraussetzungen
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
- Node.js (v16 oder höher)
|
||||
- npm oder yarn
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Repository klonen
|
||||
git clone <repository-url>
|
||||
cd beoanswer_react
|
||||
|
||||
# Dependencies installieren
|
||||
npm install
|
||||
|
||||
# Terser für Production Builds installieren
|
||||
npm install --save-dev terser
|
||||
|
||||
# Environment-Datei erstellen
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### Konfiguration
|
||||
|
||||
Erstelle eine `.env` Datei und passe die Werte an:
|
||||
|
||||
```env
|
||||
# Backend API Configuration
|
||||
VITE_API_URL=/api/intern/sofue/php/sofueDB.php
|
||||
|
||||
# HTTP Basic Authentication für geschütztes Backend
|
||||
VITE_API_USERNAME=dein_username
|
||||
VITE_API_PASSWORD=dein_passwort
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Development Server starten
|
||||
npm run dev
|
||||
|
||||
# App öffnet sich auf http://localhost:5173
|
||||
# Mit URL-Parameter: http://localhost:5173/?id=123
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```bash
|
||||
# Production Build erstellen
|
||||
npm run build:prod
|
||||
|
||||
# Production Preview
|
||||
npm run preview:prod
|
||||
|
||||
# Build-Dateien befinden sich in ./dist/
|
||||
```
|
||||
|
||||
## 📦 Versionsverwaltung
|
||||
|
||||
Die App zeigt automatisch die Version aus der `package.json` und das aktuelle Build-Datum an.
|
||||
|
||||
### Version erhöhen
|
||||
|
||||
```bash
|
||||
# Patch-Version erhöhen (1.0.0 → 1.0.1)
|
||||
npm version patch
|
||||
|
||||
# Minor-Version erhöhen (1.0.0 → 1.1.0)
|
||||
npm version minor
|
||||
|
||||
# Major-Version erhöhen (1.0.0 → 2.0.0)
|
||||
npm version major
|
||||
```
|
||||
|
||||
### Manuell in package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.2.3"
|
||||
}
|
||||
```
|
||||
|
||||
**Wichtig:** Nach Versionänderungen den Development Server neu starten:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 🛠 Scripts
|
||||
|
||||
```bash
|
||||
npm run dev # Development Server
|
||||
npm run build # Standard Build
|
||||
npm run build:prod # Production Build
|
||||
npm run preview # Preview des Builds
|
||||
npm run preview:prod # Preview des Production Builds
|
||||
npm run lint # Code Linting
|
||||
```
|
||||
|
||||
## 🌐 Deployment
|
||||
|
||||
### 1. Environment Variables setzen
|
||||
|
||||
Für Production eine `.env.production` erstellen:
|
||||
|
||||
```env
|
||||
VITE_API_URL=https://dein-server.com/intern/sofue/php/sofueDB.php
|
||||
VITE_API_USERNAME=production_user
|
||||
VITE_API_PASSWORD=production_password
|
||||
```
|
||||
|
||||
### 2. Build erstellen
|
||||
|
||||
```bash
|
||||
npm run build:prod
|
||||
```
|
||||
|
||||
### 3. Dateien auf Server kopieren
|
||||
|
||||
```bash
|
||||
# Beispiel mit rsync
|
||||
rsync -avz dist/ user@server:/var/www/html/beoanswer/
|
||||
|
||||
# Oder mit scp
|
||||
scp -r dist/* user@server:/var/www/html/beoanswer/
|
||||
```
|
||||
|
||||
### 4. Webserver konfigurieren
|
||||
|
||||
Siehe [DEPLOYMENT.md](./DEPLOYMENT.md) für detaillierte Anweisungen.
|
||||
|
||||
## 📱 Verwendung
|
||||
|
||||
### URL-Parameter
|
||||
|
||||
Die App erwartet einen `id` URL-Parameter:
|
||||
|
||||
```
|
||||
https://dein-server.com/beoanswer/?id=123
|
||||
```
|
||||
|
||||
### Workflow
|
||||
|
||||
1. **Link aus E-Mail** öffnen
|
||||
2. **Formular ausfüllen**:
|
||||
- Ja/Nein ob Führung stattfand
|
||||
- Bei "Ja": Besucherzahl, Spenden-Art, etc.
|
||||
- Bei "Nein": Absage oder Verschiebung
|
||||
3. **Daten speichern** - Fenster schließt automatisch
|
||||
|
||||
### Navigation
|
||||
|
||||
- **Zurück-Button**: Schrittweise Navigation rückwärts
|
||||
- **Abbruch**: Bestätigung mit Modal, dann Fenster schließen
|
||||
- **Anleitung**: Hilfe-Modal mit Workflow-Beschreibung
|
||||
|
||||
## 🔧 Entwicklung
|
||||
|
||||
### Projektstruktur
|
||||
|
||||
```
|
||||
src/
|
||||
├── App.jsx # Hauptkomponente mit Routing-Logik
|
||||
├── FormContext.jsx # Globaler State für Formulardaten
|
||||
├── main.jsx # React App Entry Point
|
||||
├── App.css # Haupt-Styling
|
||||
├── components/
|
||||
│ ├── BesucherBar.jsx # Eingabe für Besucher/Betrag
|
||||
│ ├── Bemerkungen.jsx # Textarea für Bemerkungen
|
||||
│ ├── FandStattVer.jsx # Radio-Button Komponente
|
||||
│ ├── LastButtons.jsx # Abbruch/Anleitung/Senden Buttons
|
||||
│ ├── LastLine.jsx # Version/Datum Anzeige
|
||||
│ ├── Modal.jsx # Standard Modal Dialog
|
||||
│ ├── ConfirmModal.jsx # Bestätigungs Modal
|
||||
│ ├── Spende.jsx # Spenden-Art Auswahl
|
||||
│ └── Verschoben.jsx # Datum-Eingabe für Verschiebung
|
||||
```
|
||||
|
||||
### FormContext
|
||||
|
||||
Zentrale State-Verwaltung für alle Formulardaten:
|
||||
|
||||
```javascript
|
||||
const { formData, updateFormData, resetFormData } = useFormData()
|
||||
|
||||
// Daten setzen
|
||||
updateFormData('besucher', '15')
|
||||
|
||||
// Daten lesen
|
||||
console.log(formData.besucher)
|
||||
|
||||
// Formular zurücksetzen
|
||||
resetFormData()
|
||||
```
|
||||
|
||||
### Backend Integration
|
||||
|
||||
Die App sendet Daten via FormData an das PHP Backend:
|
||||
|
||||
```javascript
|
||||
const backendData = new FormData()
|
||||
backendData.append('cmd', 'UPDATEAFTER')
|
||||
backendData.append('id', id)
|
||||
backendData.append('besucher', formData.besucher)
|
||||
// ...weitere Felder
|
||||
```
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Build-Fehler: "terser not found"
|
||||
|
||||
```bash
|
||||
npm install --save-dev terser
|
||||
```
|
||||
|
||||
### CORS-Fehler im Development
|
||||
|
||||
Vite Proxy ist konfiguriert für `localhost:8080`. Anpassen in `vite.config.js`:
|
||||
|
||||
```javascript
|
||||
proxy: {
|
||||
'/api': 'http://localhost:8080'
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Variables werden nicht geladen
|
||||
|
||||
1. Development Server neu starten
|
||||
2. Variablen müssen mit `VITE_` beginnen
|
||||
3. `.env` Datei im Projektroot erstellen
|
||||
|
||||
### Modal-Buttons haben keinen Abstand
|
||||
|
||||
Browser-Cache leeren oder Hard-Refresh (`Ctrl+F5`).
|
||||
|
||||
## 📄 Weitere Dokumentation
|
||||
|
||||
- [DEPLOYMENT.md](./DEPLOYMENT.md) - Detaillierte Deployment-Anweisungen
|
||||
- [.env.example](./.env.example) - Environment Variable Template
|
||||
|
||||
## 🤝 Beitragen
|
||||
|
||||
1. Feature Branch erstellen
|
||||
2. Änderungen committen
|
||||
3. Version mit `npm version` erhöhen
|
||||
4. Build testen: `npm run build:prod`
|
||||
5. Pull Request erstellen
|
||||
|
||||
## 📝 Lizenz
|
||||
|
||||
Private Projekt - Alle Rechte vorbehalten.
|
||||
|
||||
---
|
||||
|
||||
**Version:** Automatisch aus package.json
|
||||
**Build-Datum:** Automatisch generiert
|
||||
**Letztes Update:** Oktober 2025
|
||||
|
||||
1558
package-lock.json
generated
1558
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.22",
|
||||
"globals": "^16.4.0",
|
||||
"terser": "^5.44.0",
|
||||
"vite": "^7.1.7"
|
||||
}
|
||||
}
|
||||
|
||||
147
public/anleitung.html
Normal file
147
public/anleitung.html
Normal file
@@ -0,0 +1,147 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BeoAnswer - Anleitung</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
border-bottom: 2px solid #007bff;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
h2 {
|
||||
color: #555;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.step {
|
||||
background: #f8f9fa;
|
||||
border-left: 4px solid #007bff;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
.step h3 {
|
||||
margin-top: 0;
|
||||
color: #007bff;
|
||||
}
|
||||
.highlight {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
li {
|
||||
margin: 8px 0;
|
||||
}
|
||||
.tip {
|
||||
background: #d1ecf1;
|
||||
border: 1px solid #bee5eb;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.tip::before {
|
||||
content: "💡 ";
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>📋 BeoAnswer - Anleitung</h1>
|
||||
|
||||
<div class="highlight">
|
||||
<strong>Willkommen!</strong> Diese Anleitung hilft Ihnen bei der Nachbearbeitung von Sonderführungen.
|
||||
</div>
|
||||
|
||||
<h2>🚀 Schnellstart</h2>
|
||||
<p>Die Anwendung führt Sie Schritt für Schritt durch die Nachbearbeitung. Folgen Sie einfach den Anweisungen auf dem Bildschirm.</p>
|
||||
|
||||
<h2>📝 Workflow</h2>
|
||||
|
||||
<div class="step">
|
||||
<h3>1. Grundfrage beantworten</h3>
|
||||
<p><strong>"Fand die Führung statt?"</strong></p>
|
||||
<ul>
|
||||
<li><strong>Ja:</strong> Weiter zu Schritt 2</li>
|
||||
<li><strong>Nein:</strong> Weiter zu Schritt 5</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<h3>2. Besucherzahl eingeben (nur bei "Ja")</h3>
|
||||
<p>Geben Sie die Anzahl der Teilnehmer ein und klicken Sie auf "OK".</p>
|
||||
<div class="tip">Sie können auch die Enter-Taste drücken.</div>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<h3>3. Spenden-Art auswählen (nur bei "Ja")</h3>
|
||||
<p>Wählen Sie aus:</p>
|
||||
<ul>
|
||||
<li><strong>Barspende:</strong> Weiter zu Schritt 4</li>
|
||||
<li><strong>Wird überwiesen:</strong> Weiter zu Schritt 5</li>
|
||||
<li><strong>Spendenkässle:</strong> Weiter zu Schritt 5</li>
|
||||
<li><strong>Keine Spende:</strong> Weiter zu Schritt 5</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<h3>4. Spendenbetrag eingeben (nur bei Barspende)</h3>
|
||||
<p>Geben Sie den Betrag der Barspende in Euro ein.</p>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<h3>5. Bemerkungen hinzufügen (optional)</h3>
|
||||
<p>Hier können Sie zusätzliche Informationen zur Führung eingeben:</p>
|
||||
<ul>
|
||||
<li>Besonderheiten</li>
|
||||
<li>Probleme</li>
|
||||
<li>Feedback der Teilnehmer</li>
|
||||
<li>Sonstige Anmerkungen</li>
|
||||
</ul>
|
||||
<div class="tip">Verwenden Sie Strg+Enter (oder Cmd+Enter) zum schnellen Speichern.</div>
|
||||
</div>
|
||||
|
||||
<h2>❌ Bei abgesagten/verschobenen Führungen</h2>
|
||||
|
||||
<div class="step">
|
||||
<h3>1. Grund auswählen</h3>
|
||||
<p><strong>"Die Führung wurde"</strong></p>
|
||||
<ul>
|
||||
<li><strong>Abgesagt:</strong> Direkt zum Senden</li>
|
||||
<li><strong>Verschoben:</strong> Weiter zu Schritt 2</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<h3>2. Neues Datum eingeben (nur bei "Verschoben")</h3>
|
||||
<p>Wählen Sie das neue Datum und die Uhrzeit für die verschobene Führung.</p>
|
||||
</div>
|
||||
|
||||
<h2>🔄 Navigation</h2>
|
||||
<ul>
|
||||
<li><strong>Zurück-Button:</strong> Geht einen Schritt zurück und löscht die entsprechenden Eingaben</li>
|
||||
<li><strong>Abbruch:</strong> Bricht den Vorgang ab (mit Sicherheitsabfrage)</li>
|
||||
<li><strong>Anleitung:</strong> Zeigt diese Hilfe an</li>
|
||||
<li><strong>Senden:</strong> Speichert alle Daten und schließt das Fenster</li>
|
||||
</ul>
|
||||
|
||||
<h2>✅ Abschluss</h2>
|
||||
<p>Nach dem Klick auf "Senden" werden die Daten gespeichert und das Fenster schließt sich automatisch. Sie kehren zur ursprünglichen Anwendung zurück.</p>
|
||||
|
||||
<div class="highlight">
|
||||
<strong>Fragen oder Probleme?</strong> Wenden Sie sich an den Administrator.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -235,15 +235,15 @@ function AppContent() {
|
||||
// LastButtons IMMER anzeigen, aber Senden-Button nur wenn bereit
|
||||
const sendenBereit = () => {
|
||||
if (pfad === 'ja') {
|
||||
// JA-Pfad: vollständig wenn Bemerkungen-Schritt erreicht
|
||||
// JA-Pfad: vollständig wenn Bemerkungen-Schritt ABGESCHLOSSEN ist
|
||||
const bemerkungsSchritt = (formData.spendenArt === 'bar') ? 4 : 3
|
||||
return schritt >= bemerkungsSchritt
|
||||
return schritt > bemerkungsSchritt // NACH dem Bemerkungsschritt, nicht beim Erreichen
|
||||
} else if (pfad === 'nein') {
|
||||
// NEIN-Pfad: vollständig wenn abgesagt ODER verschoben mit Datum
|
||||
if (formData.abgesagt === 'abgesagt') {
|
||||
return schritt >= 2
|
||||
return schritt >= 2 // Beim Erreichen von Schritt 2 (nach Auswahl abgesagt)
|
||||
} else if (formData.abgesagt === 'verschoben') {
|
||||
return schritt >= 3 && formData.neuesDatum
|
||||
return schritt >= 3 && formData.neuesDatum // Beim Erreichen von Schritt 3 mit Datum
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -10,6 +10,7 @@ export default function LastButtons({ mitSend, mitBack, handleBack}) {
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [modalMessage, setModalMessage] = useState('')
|
||||
const [modalType, setModalType] = useState('error') // 'error' oder 'success'
|
||||
const [isModalHtml, setIsModalHtml] = useState(false)
|
||||
const [showConfirmModal, setShowConfirmModal] = useState(false)
|
||||
const [isSuccessModal, setIsSuccessModal] = useState(false)
|
||||
|
||||
@@ -122,7 +123,7 @@ export default function LastButtons({ mitSend, mitBack, handleBack}) {
|
||||
// Versuche JSON zu parsen
|
||||
result = JSON.parse(responseText)
|
||||
console.log('Backend Response (parsed):', result)
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Falls kein JSON, behandle als einfachen Text
|
||||
console.log('Backend Response ist kein JSON, behandle als Text')
|
||||
result = { success: responseText.trim() === 'true', raw: responseText }
|
||||
@@ -178,8 +179,23 @@ export default function LastButtons({ mitSend, mitBack, handleBack}) {
|
||||
}
|
||||
|
||||
const handleAnleitung = () => {
|
||||
setModalType('info')
|
||||
setModalMessage(`
|
||||
// Öffne die HTML-Anleitung in einem neuen Fenster/Tab
|
||||
const anleitungUrl = '/anleitung.html'
|
||||
const windowFeatures = 'width=800,height=600,scrollbars=yes,resizable=yes,toolbar=no,menubar=no,location=no'
|
||||
|
||||
try {
|
||||
// Versuche ein Popup-Fenster zu öffnen
|
||||
const anleitungWindow = window.open(anleitungUrl, 'anleitung', windowFeatures)
|
||||
|
||||
// Fallback: Wenn Popup blockiert wird, öffne in neuem Tab
|
||||
if (!anleitungWindow) {
|
||||
window.open(anleitungUrl, '_blank')
|
||||
}
|
||||
} catch (error) {
|
||||
// Letzter Fallback: Als Modal anzeigen
|
||||
console.warn('Anleitung konnte nicht in neuem Fenster geöffnet werden:', error)
|
||||
setModalType('info')
|
||||
setModalMessage(`
|
||||
📋 Anleitung:
|
||||
|
||||
1. **Fand statt?** - Wählen Sie "ja" oder "nein"
|
||||
@@ -195,8 +211,10 @@ export default function LastButtons({ mitSend, mitBack, handleBack}) {
|
||||
- Bei verschoben: neues Datum eingeben
|
||||
|
||||
4. **Senden** - Speichert alle Daten im System
|
||||
`)
|
||||
setShowModal(true)
|
||||
`)
|
||||
setIsModalHtml(false)
|
||||
setShowModal(true)
|
||||
}
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
@@ -224,6 +242,7 @@ export default function LastButtons({ mitSend, mitBack, handleBack}) {
|
||||
// Normales Modal schließen
|
||||
setShowModal(false)
|
||||
setModalMessage('')
|
||||
setIsModalHtml(false)
|
||||
setIsSuccessModal(false)
|
||||
}
|
||||
}
|
||||
@@ -262,6 +281,7 @@ export default function LastButtons({ mitSend, mitBack, handleBack}) {
|
||||
message={modalMessage}
|
||||
onClose={closeModal}
|
||||
type={modalType}
|
||||
isHtml={isModalHtml}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react'
|
||||
// Import des CSS direkt hier
|
||||
import './Modal.css'
|
||||
|
||||
export default function Modal({ isOpen = true, onClose, title, children, message, type = 'info' }) {
|
||||
export default function Modal({ isOpen = true, onClose, title, children, message, type = 'info', isHtml = false }) {
|
||||
if (!isOpen) return null
|
||||
|
||||
const handleOverlayClick = (e) => {
|
||||
@@ -37,7 +37,23 @@ export default function Modal({ isOpen = true, onClose, title, children, message
|
||||
}
|
||||
|
||||
const displayTitle = title || getDefaultTitle()
|
||||
const displayContent = message ? <p style={{whiteSpace: 'pre-line'}}>{message}</p> : children
|
||||
|
||||
// Content-Behandlung: HTML oder normaler Text
|
||||
const getDisplayContent = () => {
|
||||
if (children) return children
|
||||
|
||||
if (message) {
|
||||
if (isHtml) {
|
||||
// HTML-Inhalt sicher anzeigen
|
||||
return <div dangerouslySetInnerHTML={{ __html: message }} />
|
||||
} else {
|
||||
// Normaler Text mit Zeilenumbrüchen
|
||||
return <p style={{whiteSpace: 'pre-line'}}>{message}</p>
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="modal-overlay" onClick={handleOverlayClick} onKeyDown={handleKeyDown} tabIndex={0}>
|
||||
@@ -47,7 +63,7 @@ export default function Modal({ isOpen = true, onClose, title, children, message
|
||||
<button className="modal-close" onClick={onClose}>×</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
{displayContent}
|
||||
{getDisplayContent()}
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button className="modal-button" onClick={onClose} autoFocus>OK</button>
|
||||
|
||||
Reference in New Issue
Block a user