From 2b61c97cb41d8c60011e7e09e736e3b96c60cc2c Mon Sep 17 00:00:00 2001 From: vergiLgood1 Date: Wed, 19 Feb 2025 23:28:15 +0700 Subject: [PATCH] Refactor(contact us): make code more clean --- sigap-website/actions/auth/contact-us.ts | 26 +- sigap-website/components/auth/contact-us.tsx | 332 ++++++------------ sigap-website/components/form-field.tsx | 17 + .../src/applications/entities/errors/auth.ts | 17 + .../applications/entities/errors/common.ts | 17 + .../entities/models/contact-us.model.ts | 57 +++ .../repositories/contact-us.repository.ts | 9 + .../contact-us/create-contact-us.usecase.ts | 14 + .../hooks/use-contact-us-form.ts | 116 ++++++ .../contact-us.repository.impl.ts | 21 ++ .../validators/contact-us.validator.ts | 60 ++++ sigap-website/utils/validator.ts | 57 --- 12 files changed, 442 insertions(+), 301 deletions(-) create mode 100644 sigap-website/components/form-field.tsx create mode 100644 sigap-website/src/applications/entities/errors/auth.ts create mode 100644 sigap-website/src/applications/entities/errors/common.ts create mode 100644 sigap-website/src/applications/entities/models/contact-us.model.ts create mode 100644 sigap-website/src/applications/repositories/contact-us.repository.ts create mode 100644 sigap-website/src/applications/usecases/contact-us/create-contact-us.usecase.ts create mode 100644 sigap-website/src/infrastructure/hooks/use-contact-us-form.ts create mode 100644 sigap-website/src/infrastructure/repositories/contact-us.repository.impl.ts create mode 100644 sigap-website/src/infrastructure/validators/contact-us.validator.ts diff --git a/sigap-website/actions/auth/contact-us.ts b/sigap-website/actions/auth/contact-us.ts index 5c86530..000e2f0 100644 --- a/sigap-website/actions/auth/contact-us.ts +++ b/sigap-website/actions/auth/contact-us.ts @@ -1,19 +1,11 @@ "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", -}; +import { typeMessageMap } from "@/src/applications/entities/models/contact-us.model"; export async function sendContactEmail(formData: { name: string; @@ -27,17 +19,9 @@ export async function sendContactEmail(formData: { 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"; + const messageTypeLabel = + typeMessageMap.get(formData.typeMessage) || "Unknown"; // Save to Supabase const { data: contactData, error: contactError } = await supabase @@ -76,7 +60,7 @@ export async function sendContactEmail(formData: { // Send email to admin const { data: emailData, error: emailError } = await resend.emails.send({ - from: "Contact Form ", + from: "Contact Form ", to: ["xdamazon17@gmail.com"], subject: `New Contact Form Submission: ${messageTypeLabel}`, html: adminEmailHtml, @@ -98,7 +82,7 @@ export async function sendContactEmail(formData: { // Send confirmation email to user const { data: confirmationData, error: confirmationError } = await resend.emails.send({ - from: "Your Company ", + from: "Your Company ", to: [formData.email], subject: "Thank you for contacting us", html: userEmailHtml, diff --git a/sigap-website/components/auth/contact-us.tsx b/sigap-website/components/auth/contact-us.tsx index 7e9f494..bab5b26 100644 --- a/sigap-website/components/auth/contact-us.tsx +++ b/sigap-website/components/auth/contact-us.tsx @@ -1,8 +1,6 @@ "use client"; import * as React from "react"; -import { useState } from "react"; - import { Card, CardContent, @@ -12,7 +10,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; import { Select, SelectContent, @@ -23,123 +20,22 @@ 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"; +import { useContactForm } from "@/src/infrastructure/hooks/use-contact-us-form"; +import { FormField } from "../form-field"; +import { typeMessage } from "@/src/applications/entities/models/contact-us.model"; +import { Form } from "../ui/form"; export function ContactUsForm() { - const typeMessage = [ - { value: "1", label: "Request to become a user" }, - { value: "2", label: "OTP problem" }, - { value: "3", label: "Request for a feature" }, - { 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); - } - }; + const { + formData, + errors, + isSubmitting, + setFormData, + handleChange, + handleSelectChange, + handleSubmit, + } = useContactForm(); return ( @@ -150,119 +46,109 @@ export function ContactUsForm() { -
-
- - - {errors.name && ( -

{errors.name}

- )} -
-
- - - {errors.email && ( -

{errors.email}

- )} -
-
- - - {errors.phone && ( -

{errors.phone}

- )} -
-
- - - {errors.typeMessage && ( -

{errors.typeMessage}

- )} -
-
- -