Refactor ContactSection and submitContactForm to streamline form submission process. Simplify input handling by using a single object for contact data and enhance error messaging for better user feedback. Update appointment detail rendering in Booking … #36
@ -2,7 +2,7 @@
|
||||
|
||||
import { motion, useInView } from "framer-motion";
|
||||
import { useRef, useState } from "react";
|
||||
import { Send, Loader2 } from "lucide-react";
|
||||
import { Send } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
@ -29,20 +29,15 @@ export function ContactSection() {
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
await submitContactForm({
|
||||
name: formData.name,
|
||||
email: formData.email,
|
||||
phone: formData.phone,
|
||||
message: formData.message,
|
||||
});
|
||||
|
||||
await submitContactForm(formData);
|
||||
toast.success("Message Sent Successfully", {
|
||||
description: "Thank you for reaching out. We'll get back to you soon!",
|
||||
});
|
||||
setFormData({ name: "", email: "", phone: "", message: "" });
|
||||
} catch (error) {
|
||||
toast.error("Failed to Send Message", {
|
||||
description: error instanceof Error ? error.message : "Please try again later.",
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to send message. Please try again.";
|
||||
toast.error("Error Sending Message", {
|
||||
description: errorMessage,
|
||||
});
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
@ -227,17 +222,8 @@ export function ContactSection() {
|
||||
className="w-full cursor-pointer bg-gradient-to-r from-rose-500 to-pink-600 text-white transition-all hover:from-rose-600 hover:to-pink-700 hover:scale-[1.02] disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
size="lg"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-5 w-5 animate-spin" />
|
||||
Sending...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Send className="mr-2 h-5 w-5" />
|
||||
Send Message
|
||||
</>
|
||||
)}
|
||||
{isSubmitting ? "Sending..." : "Send Message"}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
|
||||
@ -9,6 +9,7 @@ import type {
|
||||
ResetPasswordInput,
|
||||
TokenRefreshInput,
|
||||
UpdateProfileInput,
|
||||
ContactInput,
|
||||
} from "@/lib/schema/auth";
|
||||
import type { AuthResponse, ApiError, AuthTokens, User } from "@/lib/models/auth";
|
||||
|
||||
@ -439,67 +440,18 @@ export async function updateProfile(input: UpdateProfileInput): Promise<User> {
|
||||
throw new Error("Invalid profile response format");
|
||||
}
|
||||
|
||||
export interface ContactFormInput {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface ContactFormResponse {
|
||||
message?: string;
|
||||
success?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit contact form (public endpoint - no authentication required)
|
||||
* Submit contact form
|
||||
*/
|
||||
export async function submitContactForm(
|
||||
data: ContactFormInput
|
||||
): Promise<ContactFormResponse> {
|
||||
try {
|
||||
export async function submitContactForm(input: ContactInput): Promise<{ message: string }> {
|
||||
const response = await fetch(API_ENDPOINTS.auth.contact, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: data.name.trim(),
|
||||
email: data.email.trim().toLowerCase(),
|
||||
phone: data.phone.trim(),
|
||||
message: data.message.trim(),
|
||||
}),
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
|
||||
// Handle empty responses
|
||||
const contentType = response.headers.get("content-type");
|
||||
let responseData: any;
|
||||
|
||||
if (contentType && contentType.includes("application/json")) {
|
||||
const text = await response.text();
|
||||
responseData = text ? JSON.parse(text) : {};
|
||||
} else {
|
||||
const text = await response.text();
|
||||
responseData = text ? { message: text } : {};
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
// Check for authentication error specifically
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
throw new Error("Contact form submission requires authentication. Please contact support if this is a public form.");
|
||||
}
|
||||
|
||||
const error: ApiError = responseData;
|
||||
throw new Error(extractErrorMessage(error));
|
||||
}
|
||||
|
||||
return responseData;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error("Failed to submit contact form. Please try again later.");
|
||||
}
|
||||
return handleResponse<{ message: string }>(response);
|
||||
}
|
||||
|
||||
|
||||
@ -87,3 +87,13 @@ export const updateProfileSchema = z.object({
|
||||
|
||||
export type UpdateProfileInput = z.infer<typeof updateProfileSchema>;
|
||||
|
||||
// Contact Form Schema
|
||||
export const contactSchema = z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
email: z.string().email("Invalid email address"),
|
||||
phone: z.string().min(1, "Phone number is required"),
|
||||
message: z.string().min(1, "Message is required"),
|
||||
});
|
||||
|
||||
export type ContactInput = z.infer<typeof contactSchema>;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user