diff --git a/client/src/pages/SurgeryPage.js b/client/src/pages/SurgeryPage.js
index 71c26fa..8aecd18 100644
--- a/client/src/pages/SurgeryPage.js
+++ b/client/src/pages/SurgeryPage.js
@@ -1,6 +1,6 @@
-// src/pages/SurgeryPage.jsx
import React, { useState } from 'react';
import axios from 'axios';
+import { FaSpinner, FaCheckCircle, FaExclamationCircle, FaUpload } from 'react-icons/fa';
import styles from './SurgeryPage.module.css';
function SurgeryPage() {
@@ -13,28 +13,114 @@ function SurgeryPage() {
surgeryType: '',
prescription: null,
});
+
+ const [errors, setErrors] = useState({});
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [submitStatus, setSubmitStatus] = useState({ success: false, message: '' });
+ const [selectedFile, setSelectedFile] = useState(null);
+
+ const validateForm = () => {
+ const newErrors = {};
+
+ if (!formData.name.trim()) newErrors.name = 'Name is required';
+
+ if (!formData.email) {
+ newErrors.email = 'Email is required';
+ } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
+ newErrors.email = 'Email is invalid';
+ }
+
+ if (!formData.phone) {
+ newErrors.phone = 'Phone number is required';
+ } else if (!/^\d{10}$/.test(formData.phone)) {
+ newErrors.phone = 'Phone number must be 10 digits';
+ }
+
+ if (!formData.doctor.trim()) newErrors.doctor = 'Doctor\'s name is required';
+ if (!formData.date) newErrors.date = 'Please select a date';
+ if (!selectedFile) newErrors.prescription = 'Please upload a prescription';
+
+ setErrors(newErrors);
+ return Object.keys(newErrors).length === 0;
+ };
+
+ const handleFileChange = (e) => {
+ const file = e.target.files[0];
+ if (file) {
+ const validTypes = ['application/pdf', 'image/jpeg', 'image/png'];
+ const maxSize = 5 * 1024 * 1024; // 5MB
+
+ if (!validTypes.includes(file.type)) {
+ setErrors({
+ ...errors,
+ prescription: 'Please upload a valid file type (PDF, JPG, or PNG)'
+ });
+ return;
+ }
+
+ if (file.size > maxSize) {
+ setErrors({
+ ...errors,
+ prescription: 'File size should be less than 5MB'
+ });
+ return;
+ }
+
+ setSelectedFile(file);
+ setFormData({ ...formData, prescription: file });
+ setErrors({ ...errors, prescription: null });
+ }
+ };
const handleChange = (e) => {
- if (e.target.name === 'prescription') {
- setFormData({ ...formData, prescription: e.target.files[0] });
- } else {
- setFormData({ ...formData, [e.target.name]: e.target.value });
+ const { name, value } = e.target;
+ setFormData({
+ ...formData,
+ [name]: value
+ });
+
+ // Clear error when user types
+ if (errors[name]) {
+ setErrors({
+ ...errors,
+ [name]: null
+ });
}
};
const handleSubmit = async (e) => {
e.preventDefault();
-
+
+ if (!validateForm()) return;
+
+ setIsSubmitting(true);
+ setSubmitStatus({ success: false, message: '' });
+
const submissionData = new FormData();
- for (let key in formData) {
- submissionData.append(key, formData[key]);
- }
+ Object.keys(formData).forEach(key => {
+ if (formData[key] !== null) {
+ submissionData.append(key, formData[key]);
+ }
+ });
try {
- await axios.post(`${process.env.REACT_APP_API_URL}/api/surgery/book`, submissionData, {
- headers: { 'Content-Type': 'multipart/form-data' },
+ const response = await axios.post(
+ `${process.env.REACT_APP_API_URL || 'http://localhost:5000'}/api/surgery/book`,
+ submissionData,
+ {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ 'Authorization': `Bearer ${localStorage.getItem('token')}`
+ },
+ }
+ );
+
+ setSubmitStatus({
+ success: true,
+ message: 'Surgery appointment booked successfully! We will contact you soon.'
});
- alert('Surgery appointment booked!');
+
+ // Reset form
setFormData({
name: '',
email: '',
@@ -44,24 +130,139 @@ function SurgeryPage() {
surgeryType: '',
prescription: null,
});
+ setSelectedFile(null);
+ document.getElementById('prescription-upload').value = '';
+
} catch (error) {
- alert('Booking failed.');
- console.error(error);
+ console.error('Booking failed:', error);
+ const errorMessage = error.response?.data?.error || 'Failed to book appointment. Please try again.';
+ setSubmitStatus({
+ success: false,
+ message: errorMessage
+ });
+ } finally {
+ setIsSubmitting(false);
}
};
return (
);
diff --git a/client/src/pages/SurgeryPage.module.css b/client/src/pages/SurgeryPage.module.css
index aef413d..7638b9a 100644
--- a/client/src/pages/SurgeryPage.module.css
+++ b/client/src/pages/SurgeryPage.module.css
@@ -1,22 +1,45 @@
.surgeryContainer {
- max-width: 600px;
- margin: 40px auto;
- padding: 30px;
- background-color: #f9f9f9;
- border-radius: 12px;
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
+ max-width: 800px;
+ margin: 2rem auto;
+ padding: 2.5rem;
+ background: #ffffff;
+ border-radius: 16px;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.surgeryContainer h1 {
text-align: center;
- margin-bottom: 25px;
- color: #2c3e50;
+ margin: 0 0 2rem 0;
+ color: #2d3748;
+ font-size: 2.2rem;
+ font-weight: 700;
+ position: relative;
+ padding-bottom: 1rem;
+}
+
+.surgeryContainer h1::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 80px;
+ height: 4px;
+ background: linear-gradient(90deg, #4f46e5, #7c3aed);
+ border-radius: 2px;
}
.surgeryForm {
display: flex;
flex-direction: column;
- gap: 15px;
+ gap: 1.5rem;
+}
+
+.formGroup {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
}
.surgeryForm input[type="text"],
@@ -24,29 +47,180 @@
.surgeryForm input[type="tel"],
.surgeryForm input[type="date"],
.surgeryForm input[type="file"] {
- padding: 10px 15px;
- font-size: 16px;
- border: 1px solid #ccc;
- border-radius: 8px;
+ padding: 0.8rem 1.2rem;
+ font-size: 1rem;
+ border: 2px solid #e2e8f0;
+ border-radius: 10px;
outline: none;
- transition: border 0.3s ease;
+ transition: all 0.3s ease;
+ background-color: #f8fafc;
+ color: #1a202c;
}
.surgeryForm input:focus {
- border-color: #3498db;
+ border-color: #4f46e5;
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
+}
+
+.errorInput {
+ border-color: #ef4444 !important;
+ background-color: #fef2f2 !important;
+}
+
+.errorText {
+ color: #ef4444;
+ font-size: 0.85rem;
+ margin-top: 0.25rem;
+ margin-left: 0.25rem;
+}
+
+.fileUpload {
+ position: relative;
+ margin: 1rem 0;
+}
+
+.fileInput {
+ position: absolute;
+ width: 0.1px;
+ height: 0.1px;
+ opacity: 0;
+ overflow: hidden;
+ z-index: -1;
+}
+
+.uploadLabel {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.75rem;
+ padding: 1rem 1.5rem;
+ background-color: #f8fafc;
+ border: 2px dashed #cbd5e0;
+ border-radius: 10px;
+ color: #4a5568;
+ font-size: 1rem;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.uploadLabel:hover {
+ background-color: #f1f5f9;
+ border-color: #93c5fd;
+}
+
+.uploadIcon {
+ font-size: 1.25rem;
+ color: #4f46e5;
}
-.surgeryForm button {
- padding: 12px 20px;
- font-size: 16px;
- background-color: #3498db;
+.errorUpload .uploadLabel {
+ border-color: #ef4444;
+ background-color: #fef2f2;
+}
+
+.submitButton {
+ margin-top: 1rem;
+ padding: 1rem 2rem;
+ font-size: 1.1rem;
+ font-weight: 600;
color: white;
+ background: linear-gradient(90deg, #4f46e5, #7c3aed);
border: none;
- border-radius: 8px;
+ border-radius: 10px;
cursor: pointer;
- transition: background-color 0.3s ease;
+ transition: all 0.3s ease;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.75rem;
+}
+
+.submitButton:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
+}
+
+.submitButton:disabled {
+ background: #cbd5e0;
+ cursor: not-allowed;
+ transform: none;
+ box-shadow: none;
+}
+
+.spinner {
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
+
+.alert {
+ padding: 1rem 1.5rem;
+ margin-bottom: 1.5rem;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ font-size: 0.95rem;
+ line-height: 1.5;
+}
+
+.success {
+ background-color: #f0fdf4;
+ color: #166534;
+ border-left: 4px solid #22c55e;
+}
+
+.error {
+ background-color: #fef2f2;
+ color: #991b1b;
+ border-left: 4px solid #ef4444;
+}
+
+.icon {
+ font-size: 1.25rem;
+ flex-shrink: 0;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .surgeryContainer {
+ margin: 1rem;
+ padding: 1.5rem;
+ }
+
+ .surgeryContainer h1 {
+ font-size: 1.75rem;
+ }
+
+ .surgeryForm {
+ gap: 1.25rem;
+ }
+
+ .submitButton {
+ padding: 0.9rem 1.5rem;
+ font-size: 1rem;
+ }
}
-.surgeryForm button:hover {
- background-color: #2980b9;
+@media (max-width: 480px) {
+ .surgeryContainer {
+ padding: 1.25rem;
+ }
+
+ .surgeryContainer h1 {
+ font-size: 1.5rem;
+ }
+
+ .uploadLabel {
+ padding: 0.75rem 1rem;
+ font-size: 0.9rem;
+ }
+
+ .alert {
+ padding: 0.75rem 1rem;
+ font-size: 0.9rem;
+ }
}