Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/app/contact/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client";

import ContactForm from "@/components/contact/ContactForm";
import ContactMethods from "@/components/contact/ContactMethods";
import SupportHours from "@/components/contact/SupportHours";
import QuickHelp from "@/components/contact/QuickHelp";
import OfficeLocations from "@/components/contact/OfficeLocations";
import { ThemeToggle } from "@/components/theme-toggle";
import Link from "next/link";
import { Send } from "lucide-react";

export default function ContactPage() {
return (
<div className="min-h-screen bg-slate-50/95 dark:bg-slate-900/95">
<header className="border-b bg-white/80 backdrop-blur-sm dark:bg-gray-900/80">
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
<Link href="/" className="flex items-center space-x-2">
<div className="w-8 h-8 bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg flex items-center justify-center">
<Send className="w-4 h-4 text-white" />
</div>
<span className="text-xl font-bold">ChainRemit</span>
</Link>
<div className="flex items-center space-x-4">
<Link
href="/"
className="text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white"
>
Home
</Link>
<ThemeToggle />
</div>
</div>
</header>

<div className="container mx-auto px-4 py-12">
<div className="text-center mb-12">
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-4">
Get in Touch
</h1>
<p className="text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
Have questions or need help? We're here to assist you. Reach out to
our team and we'll get back to you as soon as possible.
</p>
</div>
<div className="grid lg:grid-cols-3 gap-8 mb-16">
<div className="lg:col-span-2">
<ContactForm />
</div>
<div className="space-y-8">
<ContactMethods />
<SupportHours />
</div>
</div>
<QuickHelp />
<OfficeLocations />
</div>
</div>
);
}
174 changes: 174 additions & 0 deletions src/components/contact/ContactForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
"use client";

import { useState } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Send, Loader2, CheckCircle, AlertCircle } from "lucide-react";
import { useContactForm } from "@/hooks/useContactForm";

const ContactForm = () => {
const [formData, setFormData] = useState({
fullName: "",
email: "",
category: "",
subject: "",
message: "",
});
const { submitForm, loading, success, error } = useContactForm();

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

const res = await submitForm(formData);
if (res.success) {
setFormData({
fullName: "",
email: "",
category: "",
subject: "",
message: "",
});
}
};

// Just a helper to update fields
const updateField = (field: string, value: string) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};

return (
<Card className="bg-white/80 backdrop-blur-sm dark:bg-black border-1 border-white dark:border-white">
<CardHeader>
<CardTitle className="text-2xl">Send us a Message</CardTitle>
<p className="text-gray-600 dark:text-gray-300">
Fill out the form below and we'll respond within 24 hours
</p>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-6">
<div className="grid md:grid-cols-2 gap-4">
<div>
<Label htmlFor="fullName">Full Name *</Label>
<Input
id="fullName"
value={formData.fullName}
onChange={(e) => updateField("fullName", e.target.value)}
placeholder="Your full name"
className="mt-1"
disabled={loading}
required
/>
</div>
<div>
<Label htmlFor="email">Email Address *</Label>
<Input
id="email"
type="email"
value={formData.email}
onChange={(e) => updateField("email", e.target.value)}
placeholder="your@email.com"
className="mt-1"
disabled={loading}
required
/>
</div>
</div>

<div className="grid md:grid-cols-2 gap-4">
<div>
<Label htmlFor="category">Category</Label>
<Select
value={formData.category}
onValueChange={(value) => updateField("category", value)}
>
<SelectTrigger className="mt-1">
<SelectValue placeholder="Select category" />
</SelectTrigger>
<SelectContent>
<SelectItem value="general">General Support</SelectItem>
<SelectItem value="technical">Technical Issues</SelectItem>
<SelectItem value="billing">Billing & Payments</SelectItem>
<SelectItem value="partnership">Partnership</SelectItem>
<SelectItem value="media">Media Inquiry</SelectItem>
<SelectItem value="security">Security Concern</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="subject">Subject</Label>
<Input
id="subject"
value={formData.subject}
onChange={(e) => updateField("subject", e.target.value)}
placeholder="Brief description of your inquiry"
className="mt-1"
disabled={loading}
/>
</div>
</div>

<div>
<Label htmlFor="message">Message *</Label>
<Textarea
id="message"
value={formData.message}
onChange={(e) => updateField("message", e.target.value)}
placeholder="Please provide details about your inquiry..."
rows={6}
className="mt-1"
disabled={loading}
required
minLength={10}
/>
</div>
{success && (
<div className="flex items-center space-x-2 text-green-600 bg-green-50 dark:bg-green-900/20 p-3 rounded-lg">
<CheckCircle className="w-5 h-5" />
<span>
Message sent successfully! We'll get back to you soon.
</span>
</div>
)}

{error && (
<div className="flex items-center space-x-2 text-red-600 bg-red-50 dark:bg-red-900/20 p-3 rounded-lg">
<AlertCircle className="w-5 h-5" />
<span>{error}</span>
</div>
)}

<Button
type="submit"
className="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
disabled={loading}
size="lg"
>
{loading ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
Sending...
</>
) : (
<>
<Send className="w-4 h-4 mr-2" />
Send Message
</>
)}
</Button>
</form>
</CardContent>
</Card>
);
};

export default ContactForm;
86 changes: 86 additions & 0 deletions src/components/contact/ContactMethods.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use client";

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Mail, MessageCircle, Phone } from "lucide-react";

const ContactMethods = () => {
// TODO: Move to config file if this grows
const contactMethods = [
{
icon: Mail,
title: "Email Support",
description: "Get help via email",
contact: "support@chainremit.com",
action: "Send Email",
href: "mailto:support@chainremit.com",
bgColor: "bg-blue-600",
},
{
icon: MessageCircle,
title: "Live Chat",
description: "Chat with our team",
contact: "Available 24/7",
action: "Start Chat",
href: "#",
bgColor: "bg-green-600",
},
{
icon: Phone,
title: "Phone Support",
description: "Call us directly",
contact: "+1 (555) 123-4567",
action: "Call Now",
href: "tel:+15551234567",
bgColor: "bg-purple-600",
},
];

return (
<Card className="bg-white/80 backdrop-blur-sm dark:bg-black border-1 border-white dark:border-white">
<CardHeader>
<CardTitle>Contact Methods</CardTitle>
<p className="text-sm text-gray-600 dark:text-gray-300">
Choose your preferred way to reach us
</p>
</CardHeader>
<CardContent className="space-y-4">
{contactMethods.map((method, idx) => (
<div
key={idx}
className="border border-gray-200 dark:border-white rounded-lg p-4"
>
<div className="flex items-start space-x-3">
<div
className={`w-10 h-10 ${method.bgColor} rounded-lg flex items-center justify-center flex-shrink-0`}
>
<method.icon className="w-5 h-5 text-white" />
</div>
<div className="flex-1 min-w-0">
<h3 className="font-medium text-gray-900 dark:text-white">
{method.title}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-300 mb-1">
{method.description}
</p>
<p className="text-sm font-medium text-gray-900 dark:text-white">
{method.contact}
</p>
<Button
asChild
variant="outline"
size="sm"
className="mt-2 w-full"
>
<a href={method.href}>{method.action}</a>
</Button>
</div>
</div>
</div>
))}
</CardContent>
</Card>
);
};

export default ContactMethods;
75 changes: 75 additions & 0 deletions src/components/contact/OfficeLocations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"use client";

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { MapPin, Clock } from "lucide-react";

const OfficeLocations = () => {
// Not using a map yet, just static data for now
const offices = [
{
city: "San Francisco",
address: "123 Market Street, Suite 400",
country: "United States",
timezone: "PST",
},
{
city: "London",
address: "456 Oxford Street, Floor 5",
country: "United Kingdom",
timezone: "GMT",
},
{
city: "Singapore",
address: "789 Marina Bay, Tower 2",
country: "Singapore",
timezone: "SGT",
},
];

return (
<div>
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
Our Offices
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300">
Visit us at one of our global locations
</p>
</div>

<div className="grid md:grid-cols-3 gap-6">
{offices.map((office, idx) => (
<Card
key={idx}
className="hover:shadow-lg transition-shadow dark:bg-black border-1 border-white dark:border-white"
>
<CardContent className="p-6">
<div className="flex items-center space-x-2 mb-4">
<MapPin className="w-6 h-6 text-blue-400" />
<h3 className="text-xl font-semibold">{office.city}</h3>
</div>
<div className="space-y-2 text-sm">
<div className="flex items-start space-x-2">
<div>
<p>{office.address}</p>
<p className="text-gray-600 dark:text-gray-300">
{office.country}
</p>
</div>
</div>
<div className="flex items-center space-x-2">
<Clock className="w-4 h-4 text-gray-500" />
<span className="text-gray-600 dark:text-gray-300">
{office.timezone}
</span>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
};

export default OfficeLocations;
Loading
Loading