diff --git a/sigap-website/actions/auth/contact-us.ts b/sigap-website/actions/auth/contact-us.ts new file mode 100644 index 0000000..5c86530 --- /dev/null +++ b/sigap-website/actions/auth/contact-us.ts @@ -0,0 +1,123 @@ +"use server"; + +import { Resend } from "resend"; +import { TValidator } from "@/utils/validator"; +import AdminNotification from "@/components/email-templates/admin-notification"; +import { render } from "@react-email/components"; +import UserConfirmation from "@/components/email-templates/user-confirmation"; +import { createClient } from "@/utils/supabase/server"; +import { useResend } from "@/hooks/use-resend"; + +const typeMessageMap: Record = { + "1": "Request to become a user", + "2": "OTP problem", + "3": "Request for a feature", + "4": "Other", +}; + +export async function sendContactEmail(formData: { + name: string; + email: string; + phone: string; + typeMessage: string; + message: string; +}) { + try { + // Initialize Supabase + const supabase = await createClient(); + const { resend } = useResend(); + + // Validate form data + const validation = TValidator.validateContactForm(formData); + if (!validation.success) { + return { + success: false, + errors: validation.errors, + }; + } + + // Get message type label + const messageTypeLabel = typeMessageMap[formData.typeMessage] || "Unknown"; + + // Save to Supabase + const { data: contactData, error: contactError } = await supabase + .from("contact_messages") + .insert([ + { + name: formData.name, + email: formData.email, + phone: formData.phone, + message_type: formData.typeMessage, + message_type_label: messageTypeLabel, + message: formData.message, + status: "new", + }, + ]) + .select(); + + if (contactError) { + console.error("Error saving contact message to Supabase:", contactError); + return { + success: false, + error: "Failed to save your message. Please try again later.", + }; + } + + // Render admin email template + const adminEmailHtml = await render( + AdminNotification({ + name: formData.name, + email: formData.email, + phone: formData.phone, + messageType: messageTypeLabel, + message: formData.message, + }) + ); + + // Send email to admin + const { data: emailData, error: emailError } = await resend.emails.send({ + from: "Contact Form ", + to: ["xdamazon17@gmail.com"], + subject: `New Contact Form Submission: ${messageTypeLabel}`, + html: adminEmailHtml, + }); + + if (emailError) { + console.error("Error sending email via Resend:", emailError); + // Note: We don't return error here since the data is already saved to Supabase + } + + const userEmailHtml = await render( + UserConfirmation({ + name: formData.name, + messageType: messageTypeLabel, + message: formData.message, + }) + ); + + // Send confirmation email to user + const { data: confirmationData, error: confirmationError } = + await resend.emails.send({ + from: "Your Company ", + to: [formData.email], + subject: "Thank you for contacting us", + html: userEmailHtml, + }); + + if (confirmationError) { + console.error("Error sending confirmation email:", confirmationError); + // Note: We don't return error here either + } + + return { + success: true, + message: "Your message has been sent successfully!", + }; + } catch (error) { + console.error("Unexpected error in sendContactEmail:", error); + return { + success: false, + error: "An unexpected error occurred. Please try again later.", + }; + } +} diff --git a/sigap-website/components/auth/contact-us.tsx b/sigap-website/components/auth/contact-us.tsx index a026045..7e9f494 100644 --- a/sigap-website/components/auth/contact-us.tsx +++ b/sigap-website/components/auth/contact-us.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; +"use client"; + +import * as React from "react"; +import { useState } from "react"; -import { Button } from "@/components/ui/button"; import { Card, CardContent, @@ -21,6 +23,9 @@ import { import { Textarea } from "../ui/textarea"; import { SubmitButton } from "../submit-button"; import Link from "next/link"; +import { toast } from "@/hooks/use-toast"; +import { sendContactEmail } from "@/actions/auth/contact-us"; +import { TValidator } from "@/utils/validator"; export function ContactUsForm() { const typeMessage = [ @@ -30,6 +35,112 @@ export function ContactUsForm() { { value: "4", label: "Other" }, ]; + // State untuk form data + const [formData, setFormData] = useState({ + name: "", + email: "", + phone: "", + typeMessage: "", + message: "", + }); + + // State untuk error messages + const [errors, setErrors] = useState>({}); + // Loading state + const [isSubmitting, setIsSubmitting] = useState(false); + + // Handle input change + const handleChange = ( + e: React.ChangeEvent + ) => { + const { id, value } = e.target; + setFormData((prev) => ({ ...prev, [id]: value })); + + // Clear error when typing + if (errors[id]) { + setErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors[id]; + return newErrors; + }); + } + }; + + // Handle select change + const handleSelectChange = (value: string) => { + setFormData((prev) => ({ ...prev, typeMessage: value })); + + // Clear error when selecting + if (errors.typeMessage) { + setErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors.typeMessage; + return newErrors; + }); + } + }; + + // Handle form submission + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + // Client-side validation + const validation = TValidator.validateContactForm(formData); + + if (!validation.success) { + setErrors(validation.errors); + return; + } + + try { + setIsSubmitting(true); + + // Call server action to send email + const result = await sendContactEmail(formData); + + if (!result.success) { + // Handle server-side validation errors + if (result.errors) { + setErrors(result.errors); + } else { + toast({ + title: "Error", + description: + result.error || "Failed to send message. Please try again.", + variant: "destructive", + }); + } + return; + } + + // Success! + toast({ + title: "Success", + description: + result.message || "Your message has been sent successfully!", + }); + + // Reset form and errors after successful submission + setFormData({ + name: "", + email: "", + phone: "", + typeMessage: "", + message: "", + }); + setErrors({}); + } catch (error) { + console.error("Error submitting form:", error); + toast({ + title: "Error", + description: "An unexpected error occurred. Please try again later.", + variant: "destructive", + }); + } finally { + setIsSubmitting(false); + } + }; + return ( @@ -39,7 +150,7 @@ export function ContactUsForm() { -
+
+ {errors.phone && ( +

{errors.phone}

+ )}
- @@ -93,6 +234,9 @@ export function ContactUsForm() { ))} + {errors.typeMessage && ( +

{errors.typeMessage}

+ )}