Files
smoothschedule/frontend/src/components/BookingForm.jsx
poduck 2e111364a2 Initial commit: SmoothSchedule multi-tenant scheduling platform
This commit includes:
- Django backend with multi-tenancy (django-tenants)
- React + TypeScript frontend with Vite
- Platform administration API with role-based access control
- Authentication system with token-based auth
- Quick login dev tools for testing different user roles
- CORS and CSRF configuration for local development
- Docker development environment setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 01:43:20 -05:00

134 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import { format } from 'date-fns';
import './BookingForm.css';
const BookingForm = ({ service, resources, onSubmit, onCancel, loading }) => {
const [formData, setFormData] = useState({
resource: resources?.[0]?.id || '',
date: '',
time: '',
});
const [errors, setErrors] = useState({});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
// Clear error for this field
if (errors[name]) {
setErrors(prev => ({ ...prev, [name]: '' }));
}
};
const validate = () => {
const newErrors = {};
if (!formData.resource) {
newErrors.resource = 'Please select a resource';
}
if (!formData.date) {
newErrors.date = 'Please select a date';
}
if (!formData.time) {
newErrors.time = 'Please select a time';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (!validate()) {
return;
}
// Combine date and time into ISO format
const startDateTime = new Date(`${formData.date}T${formData.time}`);
const endDateTime = new Date(startDateTime.getTime() + service.duration * 60000);
const appointmentData = {
service: service.id,
resource: parseInt(formData.resource),
start_time: startDateTime.toISOString(),
end_time: endDateTime.toISOString(),
};
onSubmit(appointmentData);
};
return (
<div className="booking-form-container">
<div className="booking-form-header">
<h2>Book: {service.name}</h2>
<button onClick={onCancel} className="close-btn">×</button>
</div>
<div className="service-summary">
<p><strong>Duration:</strong> {service.duration} minutes</p>
<p><strong>Price:</strong> ${service.price}</p>
</div>
<form onSubmit={handleSubmit} className="booking-form">
<div className="form-group">
<label htmlFor="resource">Select Provider</label>
<select
id="resource"
name="resource"
value={formData.resource}
onChange={handleChange}
className={errors.resource ? 'error' : ''}
>
<option value="">Choose a provider...</option>
{resources?.map((resource) => (
<option key={resource.id} value={resource.id}>
{resource.name}
</option>
))}
</select>
{errors.resource && <span className="error-message">{errors.resource}</span>}
</div>
<div className="form-group">
<label htmlFor="date">Date</label>
<input
type="date"
id="date"
name="date"
value={formData.date}
onChange={handleChange}
min={format(new Date(), 'yyyy-MM-dd')}
className={errors.date ? 'error' : ''}
/>
{errors.date && <span className="error-message">{errors.date}</span>}
</div>
<div className="form-group">
<label htmlFor="time">Time</label>
<input
type="time"
id="time"
name="time"
value={formData.time}
onChange={handleChange}
className={errors.time ? 'error' : ''}
/>
{errors.time && <span className="error-message">{errors.time}</span>}
</div>
<div className="form-actions">
<button type="button" onClick={onCancel} className="btn-cancel">
Cancel
</button>
<button type="submit" className="btn-submit" disabled={loading}>
{loading ? 'Booking...' : 'Confirm Booking'}
</button>
</div>
</form>
</div>
);
};
export default BookingForm;