321 lines
11 KiB
TypeScript
321 lines
11 KiB
TypeScript
"use client";
|
||
import { useState, FormEvent } from 'react';
|
||
import { createTicket, CreateTicketData } from '@/lib/api/supportService';
|
||
import { useTicketCategories } from '@/lib/hooks/useSupport';
|
||
|
||
const CreateTicketForm = () => {
|
||
const { categories, loading: categoriesLoading } = useTicketCategories();
|
||
|
||
const [formData, setFormData] = useState<CreateTicketData>({
|
||
title: '',
|
||
description: '',
|
||
ticket_type: 'general',
|
||
user_name: '',
|
||
user_email: '',
|
||
user_phone: '',
|
||
company: '',
|
||
category: undefined
|
||
});
|
||
|
||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||
const [submitError, setSubmitError] = useState<string | null>(null);
|
||
const [submitSuccess, setSubmitSuccess] = useState(false);
|
||
const [ticketNumber, setTicketNumber] = useState<string>('');
|
||
|
||
const handleInputChange = (
|
||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
|
||
) => {
|
||
const { name, value } = e.target;
|
||
setFormData(prev => ({
|
||
...prev,
|
||
[name]: name === 'category' ? (value ? parseInt(value) : undefined) : value
|
||
}));
|
||
};
|
||
|
||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||
e.preventDefault();
|
||
setIsSubmitting(true);
|
||
setSubmitError(null);
|
||
setSubmitSuccess(false);
|
||
|
||
try {
|
||
const response = await createTicket(formData);
|
||
setTicketNumber(response.ticket_number);
|
||
setSubmitSuccess(true);
|
||
|
||
// Reset form
|
||
setFormData({
|
||
title: '',
|
||
description: '',
|
||
ticket_type: 'general',
|
||
user_name: '',
|
||
user_email: '',
|
||
user_phone: '',
|
||
company: '',
|
||
category: undefined
|
||
});
|
||
} catch (error: any) {
|
||
console.error('Ticket creation error:', error);
|
||
|
||
// Provide user-friendly error messages based on error type
|
||
let errorMessage = 'Failed to submit ticket. Please try again.';
|
||
|
||
if (error.message) {
|
||
if (error.message.includes('email')) {
|
||
errorMessage = 'There was an issue with your email address. Please check and try again.';
|
||
} else if (error.message.includes('network') || error.message.includes('fetch')) {
|
||
errorMessage = 'Network error. Please check your connection and try again.';
|
||
} else if (error.message.includes('validation')) {
|
||
errorMessage = 'Please check all required fields and try again.';
|
||
} else if (error.message.includes('server') || error.message.includes('500')) {
|
||
errorMessage = 'Server error. Our team has been notified. Please try again later.';
|
||
} else {
|
||
// Use the actual error message if it's user-friendly
|
||
errorMessage = error.message;
|
||
}
|
||
}
|
||
|
||
setSubmitError(errorMessage);
|
||
} finally {
|
||
setIsSubmitting(false);
|
||
}
|
||
};
|
||
|
||
if (submitSuccess) {
|
||
return (
|
||
<div className="ticket-success">
|
||
<div className="success-icon">
|
||
<i className="fa-solid fa-circle-check"></i>
|
||
</div>
|
||
<h3>Ticket Created Successfully!</h3>
|
||
<p className="ticket-number">Your ticket number: <strong>{ticketNumber}</strong></p>
|
||
<p className="ticket-info">
|
||
We've received your support request and will respond as soon as possible.
|
||
Please save your ticket number for future reference.
|
||
</p>
|
||
<button
|
||
className="btn btn-primary"
|
||
onClick={() => setSubmitSuccess(false)}
|
||
>
|
||
Submit Another Ticket
|
||
</button>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="create-ticket-form">
|
||
<div className="row justify-content-center">
|
||
<div className="col-12 col-lg-10 col-xl-8">
|
||
<div className="form-header">
|
||
<h2>Submit a Support Ticket</h2>
|
||
<p>Fill out the form below and our team will get back to you shortly.</p>
|
||
<div style={{
|
||
background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.1) 0%, rgba(59, 130, 246, 0.05) 100%)',
|
||
border: '1px solid rgba(59, 130, 246, 0.3)',
|
||
borderRadius: '8px',
|
||
padding: '12px 16px',
|
||
marginTop: '1rem',
|
||
fontSize: '0.95rem',
|
||
color: '#1e293b'
|
||
}}>
|
||
<strong>ℹ️ Note:</strong> Only registered email addresses can submit tickets.
|
||
If your email is not registered, please contact support@gnxsoft.com
|
||
</div>
|
||
</div>
|
||
|
||
{submitError && (
|
||
<div className="alert alert-danger" role="alert">
|
||
<i className="fa-solid fa-triangle-exclamation me-2"></i>
|
||
{submitError}
|
||
</div>
|
||
)}
|
||
|
||
<form onSubmit={handleSubmit} className="support-form">
|
||
<div className="row g-4">
|
||
{/* Personal Information */}
|
||
<div className="col-12">
|
||
<h4 className="form-section-title">Personal Information</h4>
|
||
</div>
|
||
|
||
<div className="col-md-6">
|
||
<div className="form-group">
|
||
<label htmlFor="user_name">
|
||
Full Name <span className="required">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="user_name"
|
||
name="user_name"
|
||
value={formData.user_name}
|
||
onChange={handleInputChange}
|
||
required
|
||
className="form-control"
|
||
placeholder="John Doe"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-md-6">
|
||
<div className="form-group">
|
||
<label htmlFor="user_email">
|
||
Email Address <span className="required">*</span>
|
||
</label>
|
||
<input
|
||
type="email"
|
||
id="user_email"
|
||
name="user_email"
|
||
value={formData.user_email}
|
||
onChange={handleInputChange}
|
||
required
|
||
className="form-control"
|
||
placeholder="john@company.com"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-md-6">
|
||
<div className="form-group">
|
||
<label htmlFor="user_phone">Phone Number</label>
|
||
<input
|
||
type="tel"
|
||
id="user_phone"
|
||
name="user_phone"
|
||
value={formData.user_phone}
|
||
onChange={handleInputChange}
|
||
className="form-control"
|
||
placeholder="+1 (555) 123-4567"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-md-6">
|
||
<div className="form-group">
|
||
<label htmlFor="company">Company Name</label>
|
||
<input
|
||
type="text"
|
||
id="company"
|
||
name="company"
|
||
value={formData.company}
|
||
onChange={handleInputChange}
|
||
className="form-control"
|
||
placeholder="Your Company Inc."
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Ticket Details */}
|
||
<div className="col-12">
|
||
<h4 className="form-section-title">Ticket Details</h4>
|
||
</div>
|
||
|
||
<div className="col-md-6">
|
||
<div className="form-group">
|
||
<label htmlFor="ticket_type">
|
||
Issue Type <span className="required">*</span>
|
||
</label>
|
||
<select
|
||
id="ticket_type"
|
||
name="ticket_type"
|
||
value={formData.ticket_type}
|
||
onChange={handleInputChange}
|
||
required
|
||
className="form-control"
|
||
>
|
||
<option value="general">General Inquiry</option>
|
||
<option value="technical">Technical Issue</option>
|
||
<option value="billing">Billing Question</option>
|
||
<option value="feature_request">Feature Request</option>
|
||
<option value="bug_report">Bug Report</option>
|
||
<option value="account">Account Issue</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-md-6">
|
||
<div className="form-group">
|
||
<label htmlFor="category">Category</label>
|
||
<select
|
||
id="category"
|
||
name="category"
|
||
value={formData.category || ''}
|
||
onChange={handleInputChange}
|
||
className="form-control"
|
||
disabled={categoriesLoading}
|
||
>
|
||
<option value="">Select a category</option>
|
||
{Array.isArray(categories) && categories.map(cat => (
|
||
<option key={cat.id} value={cat.id}>
|
||
{cat.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-12">
|
||
<div className="form-group">
|
||
<label htmlFor="title">
|
||
Subject <span className="required">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="title"
|
||
name="title"
|
||
value={formData.title}
|
||
onChange={handleInputChange}
|
||
required
|
||
className="form-control"
|
||
placeholder="Brief description of your issue"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-12">
|
||
<div className="form-group">
|
||
<label htmlFor="description">
|
||
Description <span className="required">*</span>
|
||
</label>
|
||
<textarea
|
||
id="description"
|
||
name="description"
|
||
value={formData.description}
|
||
onChange={handleInputChange}
|
||
required
|
||
className="form-control"
|
||
rows={6}
|
||
placeholder="Please provide detailed information about your issue..."
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-12">
|
||
<button
|
||
type="submit"
|
||
className="btn btn-primary btn-lg"
|
||
disabled={isSubmitting}
|
||
>
|
||
{isSubmitting ? (
|
||
<>
|
||
<span className="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||
Submitting...
|
||
</>
|
||
) : (
|
||
<>
|
||
<i className="fa-solid fa-paper-plane me-2"></i>
|
||
Submit Ticket
|
||
</>
|
||
)}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default CreateTicketForm;
|
||
|