Refactor(contact us): make code more clean
This commit is contained in:
parent
55f295cee3
commit
2b61c97cb4
|
@ -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<string, string> = {
|
||||
"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 <noreply@backspacex.tech>",
|
||||
from: "Contact Form <contact@backspacex.tech>",
|
||||
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 <noreply@backspacex.tech>",
|
||||
from: "Your Company <support@backspacex.tech>",
|
||||
to: [formData.email],
|
||||
subject: "Thank you for contacting us",
|
||||
html: userEmailHtml,
|
||||
|
|
|
@ -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<Record<string, string>>({});
|
||||
// Loading state
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
// Handle input change
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
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 (
|
||||
<Card className="w-[500px] bg-[#171717] border-none text-white">
|
||||
|
@ -150,11 +46,10 @@ export function ContactUsForm() {
|
|||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form className="space-y-4" onSubmit={handleSubmit}>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name" className="text-sm text-gray-300">
|
||||
Name
|
||||
</Label>
|
||||
<form onSubmit={handleSubmit} className="space-y-2">
|
||||
<FormField
|
||||
label="Name"
|
||||
input={
|
||||
<Input
|
||||
id="name"
|
||||
placeholder="John doe"
|
||||
|
@ -165,14 +60,12 @@ export function ContactUsForm() {
|
|||
onChange={handleChange}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
{errors.name && (
|
||||
<p className="text-red-500 text-xs mt-1">{errors.name}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email" className="text-sm text-gray-300">
|
||||
Email
|
||||
</Label>
|
||||
}
|
||||
error={errors.name}
|
||||
/>
|
||||
<FormField
|
||||
label="Email"
|
||||
input={
|
||||
<Input
|
||||
id="email"
|
||||
placeholder="example@gmail.com"
|
||||
|
@ -183,14 +76,12 @@ export function ContactUsForm() {
|
|||
onChange={handleChange}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="text-red-500 text-xs mt-1">{errors.email}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="phone" className="text-sm text-gray-300">
|
||||
Phone
|
||||
</Label>
|
||||
}
|
||||
error={errors.email}
|
||||
/>
|
||||
<FormField
|
||||
label="Phone"
|
||||
input={
|
||||
<Input
|
||||
id="phone"
|
||||
placeholder="08123456789"
|
||||
|
@ -201,14 +92,12 @@ export function ContactUsForm() {
|
|||
onChange={handleChange}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
{errors.phone && (
|
||||
<p className="text-red-500 text-xs mt-1">{errors.phone}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="typemessage" className="text-sm text-gray-300">
|
||||
Type message
|
||||
</Label>
|
||||
}
|
||||
error={errors.phone}
|
||||
/>
|
||||
<FormField
|
||||
label="Type message"
|
||||
input={
|
||||
<Select
|
||||
value={formData.typeMessage}
|
||||
onValueChange={handleSelectChange}
|
||||
|
@ -234,14 +123,12 @@ export function ContactUsForm() {
|
|||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{errors.typeMessage && (
|
||||
<p className="text-red-500 text-xs mt-1">{errors.typeMessage}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="message" className="text-sm text-gray-300">
|
||||
Message
|
||||
</Label>
|
||||
}
|
||||
error={errors.typeMessage}
|
||||
/>
|
||||
<FormField
|
||||
label="Message"
|
||||
input={
|
||||
<Textarea
|
||||
id="message"
|
||||
placeholder="Your message here..."
|
||||
|
@ -252,17 +139,16 @@ export function ContactUsForm() {
|
|||
onChange={handleChange}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
{errors.message && (
|
||||
<p className="text-red-500 text-xs mt-1">{errors.message}</p>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
error={errors.message}
|
||||
/>
|
||||
<CardFooter className="flex flex-col items-center space-y-4 px-0">
|
||||
<SubmitButton
|
||||
type="submit"
|
||||
className="w-full bg-emerald-600 hover:bg-emerald-700 text-white"
|
||||
disabled={isSubmitting}
|
||||
pendingText="Sending..."
|
||||
>
|
||||
{isSubmitting ? "Sending..." : "Send"}
|
||||
Send
|
||||
</SubmitButton>
|
||||
<div className="text-center text-lg space-x-2">
|
||||
<span className="text-gray-400">Already have an account?</span>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { Label } from "./ui/label";
|
||||
|
||||
interface FormFieldProps {
|
||||
label: string;
|
||||
input: React.ReactNode;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export function FormField({ label, input, error }: FormFieldProps) {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm text-gray-300">{label}</Label>
|
||||
{input}
|
||||
{error && <p className="text-red-500 text-xs mt-1">{error}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
export class AuthenticationError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthenticatedError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthorizedError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
export class DatabaseOperationError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class NotFoundError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class InputParseError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
import { z } from "zod";
|
||||
|
||||
// Define the message type mapping
|
||||
export 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" },
|
||||
];
|
||||
|
||||
export const typeMessageMap = new Map(
|
||||
typeMessage.map((item) => [item.value, item.label])
|
||||
);
|
||||
|
||||
export const statusEnum = {
|
||||
NEW: "new",
|
||||
READ: "read",
|
||||
REPLIED: "replied",
|
||||
RESOLVED: "resolved",
|
||||
};
|
||||
|
||||
export type StatusEnum = typeof statusEnum;
|
||||
|
||||
// Schema for what's stored in Supabase
|
||||
export const selectContactUsSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
phone: z.string(),
|
||||
message_type: z.string(),
|
||||
message_type_label: z.string(),
|
||||
message: z.string(),
|
||||
status: z.nativeEnum(statusEnum),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
});
|
||||
|
||||
export type ContactUs = z.infer<typeof selectContactUsSchema>;
|
||||
|
||||
// Schema for form input
|
||||
export const insertContactUsSchema = z.object({
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
phone: z.string(),
|
||||
typeMessage: z.string(),
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
export type ContactUsInsert = z.infer<typeof insertContactUsSchema>;
|
||||
|
||||
// Type for the response from the server action
|
||||
export interface ContactUsResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
errors?: Record<string, string>;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import {
|
||||
ContactUs,
|
||||
ContactUsInsert,
|
||||
ContactUsResponse,
|
||||
} from "../entities/models/contact-us.model";
|
||||
|
||||
export interface ContactUsRepository {
|
||||
createContactUs(contact: ContactUsInsert): Promise<ContactUsResponse>;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import {
|
||||
ContactUs,
|
||||
ContactUsInsert,
|
||||
ContactUsResponse,
|
||||
} from "../../entities/models/contact-us.model";
|
||||
import { ContactUsRepository } from "../../repositories/contact-us.repository";
|
||||
|
||||
export class CreateContactUseCase {
|
||||
constructor(private contactRepository: ContactUsRepository) {}
|
||||
|
||||
async execute(contact: ContactUsInsert): Promise<ContactUsResponse> {
|
||||
return this.contactRepository.createContactUs(contact);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
import { toast } from "@/hooks/use-toast";
|
||||
import { ContactUsInsert } from "@/src/applications/entities/models/contact-us.model";
|
||||
import { useState } from "react";
|
||||
import { ContactRepositoryImpl } from "../repositories/contact-us.repository.impl";
|
||||
import { validateContactForm } from "../validators/contact-us.validator";
|
||||
|
||||
export const useContactForm = () => {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [formData, setFormData] = useState<ContactUsInsert>({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
typeMessage: "",
|
||||
message: "",
|
||||
});
|
||||
const [errors, setErrors] = useState<
|
||||
Partial<Record<keyof ContactUsInsert, string>>
|
||||
>({});
|
||||
|
||||
const contactRepository = new ContactRepositoryImpl();
|
||||
|
||||
// Handle input change
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
const { id, value } = e.target;
|
||||
setFormData((prev) => ({ ...prev, [id]: value }));
|
||||
|
||||
if (errors[id as keyof ContactUsInsert]) {
|
||||
setErrors((prev) => {
|
||||
const newErrors = { ...prev };
|
||||
delete newErrors[id as keyof ContactUsInsert];
|
||||
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;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Client-side validation
|
||||
const validation = validateContactForm(formData);
|
||||
|
||||
if (!validation.success) {
|
||||
setErrors(validation.errors);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const response = await contactRepository.createContactUs(formData);
|
||||
|
||||
if (!response.success) {
|
||||
if (response.errors) {
|
||||
setErrors(response.errors);
|
||||
} else {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: response.error || "Failed to send message",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "Success",
|
||||
description:
|
||||
response.message || "Your message has been sent successfully!",
|
||||
});
|
||||
|
||||
// Reset form
|
||||
setFormData({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
typeMessage: "",
|
||||
message: "",
|
||||
});
|
||||
setErrors({});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "An unexpected error occurred. Please try again later.",
|
||||
variant: "destructive",
|
||||
});
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
formData,
|
||||
errors,
|
||||
isSubmitting,
|
||||
setFormData,
|
||||
handleChange,
|
||||
handleSelectChange,
|
||||
handleSubmit,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
// src/infrastructure/repositories/contact-us.repository.impl.ts
|
||||
import { sendContactEmail } from "@/actions/auth/contact-us";
|
||||
import {
|
||||
ContactUsInsert,
|
||||
ContactUsResponse,
|
||||
} from "@/src/applications/entities/models/contact-us.model";
|
||||
import { ContactUsRepository } from "@/src/applications/repositories/contact-us.repository";
|
||||
|
||||
export class ContactRepositoryImpl implements ContactUsRepository {
|
||||
async createContactUs(contact: ContactUsInsert): Promise<ContactUsResponse> {
|
||||
try {
|
||||
return await sendContactEmail(contact);
|
||||
} catch (error) {
|
||||
console.error("Error in ContactRepositoryImpl:", error);
|
||||
return {
|
||||
success: false,
|
||||
error: "An unexpected error occurred. Please try again later.",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import { ContactUsInsert } from "@/src/applications/entities/models/contact-us.model";
|
||||
import { TValidator } from "@/utils/validator";
|
||||
|
||||
/**
|
||||
* Validate the contact form
|
||||
* @param {Object} formData - The form data to validate
|
||||
* @returns {Object} - Validation result with success flag and errors object
|
||||
*/
|
||||
export const validateContactForm = (
|
||||
formData: ContactUsInsert
|
||||
): { success: boolean; errors: Record<string, string> } => {
|
||||
const errors: Record<string, string> = {};
|
||||
let isValid = true;
|
||||
|
||||
// Validate name
|
||||
const nameResult = TValidator.validateEmptyValue(formData.name, "Name");
|
||||
if (!nameResult.success) {
|
||||
errors.name = nameResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate email
|
||||
const emailResult = TValidator.validateEmail(formData.email);
|
||||
if (!emailResult.success) {
|
||||
errors.email = emailResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate phone
|
||||
const phoneResult = TValidator.validatePhone(formData.phone);
|
||||
if (!phoneResult.success) {
|
||||
errors.phone = phoneResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate type message
|
||||
const typeMessageResult = TValidator.validateEmptyValue(
|
||||
formData.typeMessage,
|
||||
"Type message"
|
||||
);
|
||||
if (!typeMessageResult.success) {
|
||||
errors.typeMessage = typeMessageResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate message
|
||||
const messageResult = TValidator.validateEmptyValue(
|
||||
formData.message,
|
||||
"Message"
|
||||
);
|
||||
if (!messageResult.success) {
|
||||
errors.message = messageResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
return {
|
||||
success: isValid,
|
||||
errors: isValid ? {} : errors,
|
||||
};
|
||||
};
|
|
@ -81,62 +81,5 @@ export class TValidator {
|
|||
success: true,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Validate the contact form
|
||||
* @param {Object} formData - The form data to validate
|
||||
* @returns {Object} - Validation result with success flag and errors object
|
||||
*/
|
||||
static validateContactForm(formData: {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
typeMessage: string;
|
||||
message: string;
|
||||
}) {
|
||||
const errors: Record<string, string> = {};
|
||||
let isValid = true;
|
||||
|
||||
// Validate name
|
||||
const nameResult = this.validateEmptyValue(formData.name, "Name");
|
||||
if (!nameResult.success) {
|
||||
errors.name = nameResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate email
|
||||
const emailResult = this.validateEmail(formData.email);
|
||||
if (!emailResult.success) {
|
||||
errors.email = emailResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate phone
|
||||
const phoneResult = this.validatePhone(formData.phone);
|
||||
if (!phoneResult.success) {
|
||||
errors.phone = phoneResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate type message
|
||||
const typeMessageResult = this.validateEmptyValue(
|
||||
formData.typeMessage,
|
||||
"Type message"
|
||||
);
|
||||
if (!typeMessageResult.success) {
|
||||
errors.typeMessage = typeMessageResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validate message
|
||||
const messageResult = this.validateEmptyValue(formData.message, "Message");
|
||||
if (!messageResult.success) {
|
||||
errors.message = messageResult.error!;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
return {
|
||||
success: isValid,
|
||||
errors: isValid ? {} : errors,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue