From 87dc305496b5ab37b581ced0c78e7a7b3919765f Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 03:37:47 +0000 Subject: [PATCH] Phase 2: helpful votes, shareable FAQ links, Contact IT form Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01GJy6X45by9tzgQjaHHGMvW --- it-support/PRD.md | 2 +- it-support/src/App.tsx | 5 +- it-support/src/ContactForm.tsx | 74 +++++++++++++++++++ it-support/src/Faq.tsx | 126 ++++++++++++++++++++++++-------- it-support/src/storage.ts | 17 +++++ it-support/tsconfig.tsbuildinfo | 2 +- 6 files changed, 192 insertions(+), 34 deletions(-) create mode 100644 it-support/src/ContactForm.tsx create mode 100644 it-support/src/storage.ts diff --git a/it-support/PRD.md b/it-support/PRD.md index 1b08757..baeb008 100644 --- a/it-support/PRD.md +++ b/it-support/PRD.md @@ -11,7 +11,7 @@ Restaurant analogy: the FAQ database is the **kitchen's recipe book**. The websi ## Phased roadmap - **Phase 1 – Food stand (TODAY):** hero + search + categories + 87 FAQs from the database, baked in as a JSON file. No server. -- **Phase 2 – Small restaurant:** "Was this helpful?" votes, "Contact IT" ticket form, shareable links per question. +- **Phase 2 – Small restaurant (DONE, browser-only storage):** "Was this helpful?" votes, "Contact IT" ticket form, shareable links per question. - **Phase 3 – Full restaurant:** small back-of-house server + real database, staff login, admin page to edit FAQs, ticket tracking. ## Test ladder diff --git a/it-support/src/App.tsx b/it-support/src/App.tsx index fd9cb7d..eca06ee 100644 --- a/it-support/src/App.tsx +++ b/it-support/src/App.tsx @@ -2,6 +2,7 @@ import { useMemo, useRef, useState } from 'react' import { ArrowRight, Globe, Instagram, Twitter } from 'lucide-react' import VideoBackground from './VideoBackground' import FaqList from './Faq' +import ContactForm from './ContactForm' import type { Faq } from './types' import faqData from './data/faqs.json' @@ -40,7 +41,7 @@ export default function App() { {[ ['Topics', '#answers'], ['Search', '#top'], - ['About', '#about'], + ['Contact', '#contact'], ].map(([label, href]) => ( {label} @@ -141,6 +142,8 @@ export default function App() { + +
General guidance only. For account-specific problems, contact your organisation's IT service desk.
diff --git a/it-support/src/ContactForm.tsx b/it-support/src/ContactForm.tsx new file mode 100644 index 0000000..36275e7 --- /dev/null +++ b/it-support/src/ContactForm.tsx @@ -0,0 +1,74 @@ +import { useState } from 'react' +import { Send } from 'lucide-react' +import { load, save } from './storage' + +interface Ticket { id: string; name: string; email: string; topic: string; message: string; created: string } + +const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ +const inputCls = 'w-full bg-transparent outline-none text-white placeholder:text-white/40 text-base' + +export default function ContactForm({ topics }: { topics: string[] }) { + const [form, setForm] = useState({ name: '', email: '', topic: topics[0] ?? '', message: '' }) + const [errors, setErrors] = useState>({}) + const [ticketId, setTicketId] = useState(null) + + const set = (k: keyof typeof form) => (e: React.ChangeEvent) => + setForm({ ...form, [k]: e.target.value }) + + const submit = (e: React.FormEvent) => { + e.preventDefault() + const errs: Record = {} + if (!form.name.trim()) errs.name = 'Please enter your name.' + if (!EMAIL_RE.test(form.email.trim())) errs.email = 'Please enter a valid email.' + if (form.message.trim().length < 10) errs.message = 'Please describe the problem (at least 10 characters).' + setErrors(errs) + if (Object.keys(errs).length) return + const id = `IT-${Date.now().toString(36).toUpperCase()}` + const ticket: Ticket = { id, ...form, created: new Date().toISOString() } + save('tickets', [...load('tickets', []), ticket]) + setTicketId(id) + setForm({ name: '', email: '', topic: topics[0] ?? '', message: '' }) + } + + const field = 'liquid-glass rounded-3xl px-6 py-4' + const err = (k: string) => errors[k] &&

{errors[k]}

+ + return ( +
+

Contact IT

+

Can't find your answer? Tell us what's wrong.

+ {ticketId ? ( +
+

Request saved. Your ticket number is {ticketId}.

+

+ Heads up: this demo version only saves the request in this browser. It is not yet sent to an IT team. Real sending arrives in the next phase. +

+ +
+ ) : ( +
+
+
+ {err('name')} +
+
+
+ {err('email')} +
+
+ +
+
+