234 lines
7.2 KiB
JavaScript
234 lines
7.2 KiB
JavaScript
import { useEffect, useState, useRef } from 'react'
|
|
import { createEvent, uploadImage } from '../api/api'
|
|
import './EventForm.css'
|
|
|
|
const he = {
|
|
createNewEvent: 'צור אירוע חדש',
|
|
eventNameRequired: 'שם האירוע נדרש',
|
|
failedCreate: 'נכשל בהוספת אירוע',
|
|
eventName: 'שם האירוע',
|
|
eventDate: 'תאריך',
|
|
location: 'מיקום',
|
|
invitationImage: 'תמונת הזמנה (רקע)',
|
|
invitationImageHint: 'העלה תמונה או הדבק קישור לתמונה שתשמש כרקע להזמנה',
|
|
uploadImage: '📁 העלה תמונה',
|
|
uploading: 'מעלה...',
|
|
orPasteUrl: 'או הדבק כתובת URL:',
|
|
create: 'צור',
|
|
cancel: 'ביטול',
|
|
guestFormFields: 'שדות שיוצגו לאורח בדף ה-RSVP',
|
|
}
|
|
|
|
const GUEST_FIELD_OPTIONS = [
|
|
{ key: 'mealPref', label: 'העדפת ארוחה' },
|
|
{ key: 'companions', label: 'כמה תהיו? (מספר מגיעים)' },
|
|
]
|
|
|
|
function EventForm({ onEventCreated, onCancel }) {
|
|
const [formData, setFormData] = useState({
|
|
name: '',
|
|
date: '',
|
|
location: '',
|
|
invitation_image_url: ''
|
|
})
|
|
// Which fields the guest sees on the RSVP page — default: both shown
|
|
const [guestFields, setGuestFields] = useState(new Set(['mealPref', 'companions']))
|
|
|
|
const toggleGuestField = (key) => {
|
|
setGuestFields(prev => {
|
|
const next = new Set(prev)
|
|
next.has(key) ? next.delete(key) : next.add(key)
|
|
return next
|
|
})
|
|
}
|
|
const [loading, setLoading] = useState(false)
|
|
const [uploading, setUploading] = useState(false)
|
|
const [error, setError] = useState('')
|
|
const fileInputRef = useRef(null)
|
|
|
|
useEffect(() => {
|
|
const previousOverflow = document.body.style.overflow
|
|
document.body.style.overflow = 'hidden'
|
|
|
|
return () => {
|
|
document.body.style.overflow = previousOverflow
|
|
}
|
|
}, [])
|
|
|
|
const handleChange = (e) => {
|
|
const { name, value } = e.target
|
|
setFormData(prev => ({
|
|
...prev,
|
|
[name]: value
|
|
}))
|
|
}
|
|
|
|
const handleFileChange = async (e) => {
|
|
const file = e.target.files[0]
|
|
if (!file) return
|
|
setUploading(true)
|
|
setError('')
|
|
try {
|
|
const result = await uploadImage(file)
|
|
setFormData(prev => ({ ...prev, invitation_image_url: result.url }))
|
|
} catch (err) {
|
|
setError(err.response?.data?.detail || 'נכשל בהעלאת התמונה')
|
|
} finally {
|
|
setUploading(false)
|
|
}
|
|
}
|
|
|
|
const handleSubmit = async (e) => {
|
|
e.preventDefault()
|
|
if (!formData.name.trim()) {
|
|
setError(he.eventNameRequired)
|
|
return
|
|
}
|
|
|
|
setLoading(true)
|
|
setError('')
|
|
|
|
try {
|
|
const payload = { ...formData, guest_form_fields: JSON.stringify([...guestFields]) }
|
|
const newEvent = await createEvent(payload)
|
|
setFormData({ name: '', date: '', location: '', invitation_image_url: '' })
|
|
setGuestFields(new Set(['mealPref', 'companions']))
|
|
onEventCreated(newEvent)
|
|
} catch (err) {
|
|
setError(err.response?.data?.detail || he.failedCreate)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="event-form-container">
|
|
<div
|
|
className="event-form-overlay"
|
|
onMouseDown={(e) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
onCancel()
|
|
}}
|
|
></div>
|
|
<div className="event-form" onMouseDown={(e) => e.stopPropagation()}>
|
|
<h2>{he.createNewEvent}</h2>
|
|
{error && <div className="error-message">{error}</div>}
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
<div className="form-group">
|
|
<label htmlFor="name">{he.eventName} *</label>
|
|
<input
|
|
type="text"
|
|
id="name"
|
|
name="name"
|
|
value={formData.name}
|
|
onChange={handleChange}
|
|
placeholder="לדוגמה: חתונה, יום הולדת, מפגש"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label htmlFor="date">{he.eventDate}</label>
|
|
<input
|
|
type="datetime-local"
|
|
id="date"
|
|
name="date"
|
|
value={formData.date}
|
|
onChange={handleChange}
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label htmlFor="location">{he.location}</label>
|
|
<input
|
|
type="text"
|
|
id="location"
|
|
name="location"
|
|
value={formData.location}
|
|
onChange={handleChange}
|
|
placeholder="לדוגמה: תל אביב, ישראל"
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label>{he.invitationImage}</label>
|
|
<div className="image-upload-area">
|
|
<input
|
|
type="file"
|
|
ref={fileInputRef}
|
|
accept="image/jpeg,image/png,image/gif,image/webp"
|
|
style={{ display: 'none' }}
|
|
onChange={handleFileChange}
|
|
/>
|
|
<button
|
|
type="button"
|
|
className="btn-upload-image"
|
|
onClick={() => fileInputRef.current.click()}
|
|
disabled={uploading}
|
|
>
|
|
{uploading ? he.uploading : he.uploadImage}
|
|
</button>
|
|
{formData.invitation_image_url && (
|
|
<button
|
|
type="button"
|
|
className="btn-remove-image"
|
|
onClick={() => setFormData(prev => ({ ...prev, invitation_image_url: '' }))}
|
|
>
|
|
✕
|
|
</button>
|
|
)}
|
|
</div>
|
|
<small className="form-hint">{he.invitationImageHint}</small>
|
|
<label className="url-input-label">{he.orPasteUrl}</label>
|
|
<input
|
|
type="url"
|
|
name="invitation_image_url"
|
|
value={formData.invitation_image_url}
|
|
onChange={handleChange}
|
|
placeholder="https://example.com/invitation.jpg"
|
|
/>
|
|
{formData.invitation_image_url && (
|
|
<div className="image-preview">
|
|
<img
|
|
src={formData.invitation_image_url}
|
|
alt="תצוגה מקדימה"
|
|
onError={(e) => { e.target.style.display = 'none' }}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label>{he.guestFormFields}</label>
|
|
<div className="guest-fields-list">
|
|
{GUEST_FIELD_OPTIONS.map(opt => (
|
|
<label key={opt.key} className="guest-field-checkbox">
|
|
<input
|
|
type="checkbox"
|
|
checked={guestFields.has(opt.key)}
|
|
onChange={() => toggleGuestField(opt.key)}
|
|
/>
|
|
{opt.label}
|
|
</label>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="form-actions">
|
|
<button type="button" onClick={onCancel} className="btn-cancel">
|
|
{he.cancel}
|
|
</button>
|
|
<button type="submit" disabled={loading} className="btn-submit">
|
|
{loading ? 'יוצר...' : he.create}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default EventForm
|