diff --git a/client/src/containers/User/IT-Ticket/CreateTicket.tsx b/client/src/containers/User/IT-Ticket/CreateTicket.tsx index 2e3edf2..d08f710 100644 --- a/client/src/containers/User/IT-Ticket/CreateTicket.tsx +++ b/client/src/containers/User/IT-Ticket/CreateTicket.tsx @@ -29,12 +29,20 @@ interface Ticket { } const CreateTicket = () => { + // ===================================================== + // USER INFO + // ===================================================== + const [name, setName] = useState(""); const [email, setEmail] = useState(""); + // ===================================================== + // FORM + // ===================================================== + const [subject, setSubject] = useState(""); @@ -46,6 +54,10 @@ const CreateTicket = () => { const [priority, setPriority] = useState("normal"); + // ===================================================== + // UI STATE + // ===================================================== + const [loading, setLoading] = useState(false); @@ -55,6 +67,13 @@ const CreateTicket = () => { const [error, setError] = useState(""); + const [infoMessage, setInfoMessage] = + useState(""); + + // ===================================================== + // TICKETS + // ===================================================== + const [tickets, setTickets] = useState([]); @@ -66,34 +85,172 @@ const CreateTicket = () => { setSortBy, ] = useState("newest"); - // ----------------------------------- + // ===================================================== + // AUTO LOAD USER + // ===================================================== + + useEffect(() => { + const storedUser = + localStorage.getItem("user"); + + if (!storedUser) return; + + try { + const parsed = + JSON.parse(storedUser); + + setName( + parsed.name || + parsed.fullName || + "" + ); + + setEmail( + parsed.email || "" + ); + } catch (err) { + console.error( + "User Parse Error:", + err + ); + } + }, []); + + // ===================================================== // FETCH USER TICKETS - // ----------------------------------- + // ===================================================== const fetchTickets = async ( userEmail: string ) => { try { + if ( + !userEmail || + !userEmail.trim() + ) { + return; + } + + const cleanEmail = + userEmail + .toLowerCase() + .trim(); + const res = await axios.get( - "/api/it-help/view" + "/api/it-help/view", + { + withCredentials: true, + } ); + const allTickets = + Array.isArray(res.data) + ? res.data + : []; + const filtered = - res.data.filter( + allTickets.filter( (ticket: Ticket) => - ticket.email === - userEmail + ticket.email + ?.toLowerCase() + .trim() === + cleanEmail ); setTickets(filtered); } catch (err) { - console.error(err); + console.error( + "Fetch Tickets Error:", + err + ); + } + }; + + // ===================================================== + // LOAD TICKETS WHEN EMAIL EXISTS + // ===================================================== + + useEffect(() => { + if (email.trim()) { + fetchTickets(email); + } + }, [email]); + + // ===================================================== + // VALIDATION + // ===================================================== + + const validateForm = () => { + if (!name.trim()) { + setError( + "Your full name is required before creating a support ticket." + ); + + return false; + } + + if (!email.trim()) { + setError( + "Your email address is required so support can identify and track your tickets." + ); + + return false; + } + + if ( + !email.includes("@") || + !email.includes(".") + ) { + setError( + "Please enter a valid email address." + ); + + return false; + } + + if (!subject.trim()) { + setError( + "A ticket subject is required." + ); + + return false; + } + + if ( + subject.trim().length < 5 + ) { + setError( + "Ticket subject must be at least 5 characters long." + ); + + return false; + } + + if (!description.trim()) { + setError( + "Please explain the issue before submitting your ticket." + ); + + return false; + } + + if ( + description.trim() + .length < 15 + ) { + setError( + "Please provide a more detailed explanation of the issue." + ); + + return false; } + + return true; }; - // ----------------------------------- + // ===================================================== // SUBMIT - // ----------------------------------- + // ===================================================== const submitTicket = async ( @@ -102,73 +259,136 @@ const CreateTicket = () => { e.preventDefault(); setLoading(true); + setSuccess(""); + setError(""); + setInfoMessage(""); + try { + const valid = + validateForm(); + + if (!valid) { + setLoading(false); + return; + } + + const payload = { + name: + name.trim(), + + email: + email + .toLowerCase() + .trim(), + + subject: + subject.trim(), + + description: + description.trim(), + + priority, + + status: "open", + }; + await axios.post( "/api/it-help/post-ticket", + payload, { - name, - email, - subject, - description, - priority, - status: "open", + withCredentials: true, } ); setSuccess( - "Ticket created successfully." + "Support ticket created successfully. Your request has been submitted and is now being tracked." + ); + + setInfoMessage( + "Your tickets are linked to your email address. Use the same email every time to view your ticket history." ); setSubject(""); + setDescription(""); - setPriority("normal"); - fetchTickets(email); - } catch (err) { - console.error(err); + setPriority( + "normal" + ); - setError( - "Unable to create ticket." + await fetchTickets( + email + ); + } catch (err: any) { + console.error( + "Create Ticket Error:", + err ); + + if ( + err?.response?.status === + 400 + ) { + setError( + err.response.data + ?.message || + "Some required ticket information is missing." + ); + } else if ( + err?.response?.status === + 401 + ) { + setError( + "Your session expired. Please sign in again." + ); + } else if ( + err?.response?.status === + 500 + ) { + setError( + "The server encountered an error while creating your ticket. Please try again." + ); + } else { + setError( + "Unable to create ticket right now. Please try again." + ); + } } finally { setLoading(false); } }; - // ----------------------------------- - // LOAD TICKETS AFTER EMAIL - // ----------------------------------- - - useEffect(() => { - if (email.trim()) { - fetchTickets(email); - } - }, [email]); - - // ----------------------------------- + // ===================================================== // FILTER + SORT - // ----------------------------------- + // ===================================================== const filteredTickets = useMemo(() => { - let filtered = tickets.filter( - (ticket) => - ticket.subject - ?.toLowerCase() - .includes( - search.toLowerCase() - ) || - ticket.description - ?.toLowerCase() - .includes( - search.toLowerCase() - ) - ); + let filtered = [ + ...tickets, + ]; + + filtered = + filtered.filter( + (ticket) => + ticket.subject + ?.toLowerCase() + .includes( + search.toLowerCase() + ) || + ticket.description + ?.toLowerCase() + .includes( + search.toLowerCase() + ) + ); - if (sortBy === "newest") { + if ( + sortBy === "newest" + ) { filtered.sort( (a, b) => new Date( @@ -180,7 +400,9 @@ const CreateTicket = () => { ); } - if (sortBy === "oldest") { + if ( + sortBy === "oldest" + ) { filtered.sort( (a, b) => new Date( @@ -192,16 +414,40 @@ const CreateTicket = () => { ); } + if ( + sortBy === "priority" + ) { + const order: any = { + urgent: 4, + high: 3, + normal: 2, + low: 1, + }; + + filtered.sort( + (a, b) => + (order[ + b.priority || "" + ] || 0) - + (order[ + a.priority || "" + ] || 0) + ); + } + return filtered; - }, [tickets, search, sortBy]); + }, [ + tickets, + search, + sortBy, + ]); - // ----------------------------------- + // ===================================================== // RENDER - // ----------------------------------- + // ===================================================== return (
-
@@ -209,11 +455,9 @@ const CreateTicket = () => {
- {/* HERO */}
-

Support Command Center

@@ -224,17 +468,14 @@ const CreateTicket = () => { and manage your issues in real time.

-
{/* GRID */}
- {/* LEFT */}
-
{

-
+
+ Important Ticket Information +
- {/* NAME + EMAIL GRID */} +
    +
  • + Your email + address is used + to load your + tickets. +
  • + +
  • + Always use the + same email to + access your + ticket history. +
  • + +
  • + Ticket subjects + should clearly + explain the + issue. +
  • + +
  • + Detailed + descriptions + help support + resolve issues + faster. +
  • +
+
-
+ {/* FORM */} -
+ + {/* NAME + EMAIL */} -