Skip to content

Commit 95d394f

Browse files
authored
Merge pull request #65 from FSDSTR0225/feature/contact
Feature/contact
2 parents 4e1599c + 108851a commit 95d394f

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed

src/pages/Contact.jsx

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import React, { useState } from 'react';
2+
import { SectionContainer } from '../components/SectionContainer';
3+
4+
const API_URL = import.meta.env.VITE_BASE_URL; // Ajusta según tu configuración
5+
6+
export const Contact = () => {
7+
const [formData, setFormData] = useState({
8+
name: '',
9+
email: '',
10+
category: '',
11+
subject: '',
12+
message: ''
13+
});
14+
15+
const [isSubmitting, setIsSubmitting] = useState(false);
16+
const [submitStatus, setSubmitStatus] = useState(null);
17+
const [errorMessage, setErrorMessage] = useState('');
18+
19+
const categories = [
20+
{ value: 'bug', label: 'Bug Report' },
21+
{ value: 'feature', label: 'Feature Request' },
22+
{ value: 'improvement', label: 'Improvement Suggestion' },
23+
{ value: 'support', label: 'Technical Support' },
24+
{ value: 'feedback', label: 'General Feedback' },
25+
{ value: 'business', label: 'Business Inquiry' },
26+
{ value: 'other', label: 'Other' }
27+
];
28+
29+
const handleInputChange = (e) => {
30+
const { name, value } = e.target;
31+
setFormData(prev => ({
32+
...prev,
33+
[name]: value
34+
}));
35+
};
36+
37+
const handleSubmit = async (e) => {
38+
e.preventDefault();
39+
setIsSubmitting(true);
40+
setErrorMessage('');
41+
42+
try {
43+
const response = await fetch(`${API_URL}/contact`, {
44+
method: 'POST',
45+
headers: {
46+
'Content-Type': 'application/json',
47+
},
48+
body: JSON.stringify(formData)
49+
});
50+
51+
if (response.ok) {
52+
setSubmitStatus('success');
53+
// Reset form
54+
setFormData({
55+
name: '',
56+
email: '',
57+
category: '',
58+
subject: '',
59+
message: ''
60+
});
61+
} else {
62+
const errorData = await response.json();
63+
setErrorMessage(errorData.message || 'Failed to send message. Please try again.');
64+
setSubmitStatus('error');
65+
}
66+
} catch (error) {
67+
setErrorMessage('Network error. Please check your connection and try again.');
68+
setSubmitStatus('error');
69+
} finally {
70+
setIsSubmitting(false);
71+
}
72+
};
73+
74+
return (
75+
<SectionContainer classProps="max-w-4xl mx-auto">
76+
<div className="text-center mb-8">
77+
<h1 className='bg-gradient-to-r from-primary-50 to-secondary-50 text-transparent bg-clip-text leading-normal inline-block text-3xl sm:text-4xl lg:text-5xl font-bold mb-2'>
78+
Support Tickets
79+
</h1>
80+
<p className="text-neutral-20 text-lg">
81+
Help us improve by submitting your feedback, bug reports, or feature requests
82+
</p>
83+
</div>
84+
85+
{submitStatus === 'success' && (
86+
<div className="bg-primary-50 bg-opacity-20 border border-primary-50 rounded-lg p-4 mb-6">
87+
<p className="text-primary-10 font-semibold">✓ Message sent successfully!</p>
88+
<p className="text-neutral-10 text-sm">We'll get back to you within 24-48 hours.</p>
89+
</div>
90+
)}
91+
92+
{submitStatus === 'error' && (
93+
<div className="bg-red-500 bg-opacity-20 border border-red-500 rounded-lg p-4 mb-6">
94+
<p className="text-red-300 font-semibold">✗ Error sending message</p>
95+
<p className="text-neutral-10 text-sm">{errorMessage}</p>
96+
</div>
97+
)}
98+
99+
<form onSubmit={handleSubmit} className="bg-neutral-80 rounded-xl p-6 shadow-lg border border-neutral-70">
100+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
101+
{/* Name Field */}
102+
<div>
103+
<label htmlFor="name" className="block text-neutral-0 font-semibold mb-2">
104+
Full Name *
105+
</label>
106+
<input
107+
type="text"
108+
id="name"
109+
name="name"
110+
value={formData.name}
111+
onChange={handleInputChange}
112+
required
113+
className="w-full p-3 bg-neutral-70 border border-neutral-60 rounded-lg text-neutral-0 focus:outline-none focus:ring-2 focus:ring-primary-50 focus:border-transparent transition-all duration-300"
114+
placeholder="Enter your full name"
115+
/>
116+
</div>
117+
118+
{/* Email Field */}
119+
<div>
120+
<label htmlFor="email" className="block text-neutral-0 font-semibold mb-2">
121+
Email Address *
122+
</label>
123+
<input
124+
type="email"
125+
id="email"
126+
name="email"
127+
value={formData.email}
128+
onChange={handleInputChange}
129+
required
130+
className="w-full p-3 bg-neutral-70 border border-neutral-60 rounded-lg text-neutral-0 focus:outline-none focus:ring-2 focus:ring-primary-50 focus:border-transparent transition-all duration-300"
131+
placeholder="your.email@example.com"
132+
/>
133+
</div>
134+
</div>
135+
136+
{/* Category Field */}
137+
<div className="mb-6">
138+
<label htmlFor="category" className="block text-neutral-0 font-semibold mb-2">
139+
Category *
140+
</label>
141+
<select
142+
id="category"
143+
name="category"
144+
value={formData.category}
145+
onChange={handleInputChange}
146+
required
147+
className="w-full p-3 bg-neutral-70 border border-neutral-60 rounded-lg text-neutral-0 focus:outline-none focus:ring-2 focus:ring-primary-50 focus:border-transparent transition-all duration-300"
148+
>
149+
<option value="">Select a category</option>
150+
{categories.map(cat => (
151+
<option key={cat.value} value={cat.value}>{cat.label}</option>
152+
))}
153+
</select>
154+
</div>
155+
156+
{/* Subject Field */}
157+
<div className="mb-6">
158+
<label htmlFor="subject" className="block text-neutral-0 font-semibold mb-2">
159+
Subject *
160+
</label>
161+
<input
162+
type="text"
163+
id="subject"
164+
name="subject"
165+
value={formData.subject}
166+
onChange={handleInputChange}
167+
required
168+
className="w-full p-3 bg-neutral-70 border border-neutral-60 rounded-lg text-neutral-0 focus:outline-none focus:ring-2 focus:ring-primary-50 focus:border-transparent transition-all duration-300"
169+
placeholder="Brief description of your issue or request"
170+
/>
171+
</div>
172+
173+
{/* Message Field */}
174+
<div className="mb-6">
175+
<label htmlFor="message" className="block text-neutral-0 font-semibold mb-2">
176+
Detailed Description *
177+
</label>
178+
<textarea
179+
id="message"
180+
name="message"
181+
value={formData.message}
182+
onChange={handleInputChange}
183+
required
184+
rows={6}
185+
className="w-full p-3 bg-neutral-70 border border-neutral-60 rounded-lg text-neutral-0 focus:outline-none focus:ring-2 focus:ring-primary-50 focus:border-transparent transition-all duration-300 resize-vertical"
186+
placeholder="Please provide as much detail as possible about your issue, suggestion, or feedback..."
187+
/>
188+
</div>
189+
190+
191+
{/* Submit Button */}
192+
<div className="text-center">
193+
<button
194+
type="submit"
195+
disabled={isSubmitting}
196+
className={`btn px-8 py-3 rounded-lg font-semibold text-neutral-0 transition-all duration-300 transform hover:scale-105 ${
197+
isSubmitting
198+
? 'bg-neutral-50 cursor-not-allowed'
199+
: 'bg-gradient hover:shadow-lg'
200+
}`}
201+
>
202+
{isSubmitting ? (
203+
<span className="flex items-center">
204+
<svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
205+
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
206+
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
207+
</svg>
208+
Submitting...
209+
</span>
210+
) : (
211+
'Submit Ticket'
212+
)}
213+
</button>
214+
</div>
215+
</form>
216+
217+
{/* Additional Info */}
218+
<div className="mt-8 text-center">
219+
<div className="bg-neutral-80 rounded-lg p-6 border border-neutral-70">
220+
<h3 className="text-xl font-bold text-neutral-0 mb-3">Contact Information</h3>
221+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 text-sm">
222+
<div className="text-center">
223+
<span className="text-primary-50 font-semibold">Response Time</span>
224+
<p className="text-neutral-20">We typically respond within 24-48 hours</p>
225+
</div>
226+
<div className="text-center">
227+
<span className="text-secondary-50 font-semibold">Email Support</span>
228+
<p className="text-neutral-20">codepply@protonmail.com</p>
229+
</div>
230+
</div>
231+
</div>
232+
</div>
233+
</SectionContainer>
234+
);
235+
};

src/router/AppRouter.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { Onboarding } from "../pages/Onboarding/Onboarding";
3030
import { Home } from "../pages/Home";
3131
import { SettingsPage } from "../pages/SettingsPage";
3232
import { TermsPage, PrivacyPage, CookiesPage, AboutPage } from "./LegalRoutes";
33+
import { Contact } from "../pages/Contact";
3334

3435
const router = createBrowserRouter([
3536
{
@@ -61,6 +62,7 @@ const router = createBrowserRouter([
6162
{ path: "legal/terms", element: <TermsPage /> },
6263
{ path: "legal/privacy", element: <PrivacyPage /> },
6364
{ path: "legal/cookies", element: <CookiesPage /> },
65+
{ path: "contact", element: <Contact /> },
6466

6567
// --- Private Dev (developers) ---
6668
{

0 commit comments

Comments
 (0)