Implement email tab redesign, archive support, manual Q&A creation, URL linking, and question admin tools

- Add dedicated Emails tab with inbox/archive views and two-pane layout
- Implement archive/unarchive for contact submissions with persisted state
- Add manual question creation endpoint and admin form (non-contact origin)
- Implement URL auto-linking in Q&A answers with safe rendering
- Add question admin tools: search, filter (All/Pending/Approved/Answered/Unanswered), pagination
- Expand admin panel widths to reduce cramping
- Restore and enhance Asset Manager table layout
- Update email reply template with fixed from-address and HTML support
This commit is contained in:
nmemmert
2026-05-07 09:43:16 -04:00
parent bc3d906e64
commit 583a9b7b66
8 changed files with 1420 additions and 36 deletions
+23 -1
View File
@@ -19,6 +19,28 @@ function tokenizeForRelated(text: string) {
.filter(token => token.length > 3)
}
function renderTextWithLinks(text: string) {
const parts = text.split(/(https?:\/\/[^\s]+)/g)
return parts.map((part, index) => {
if (!/^https?:\/\//i.test(part)) {
return <span key={`text-${index}`}>{part}</span>
}
const safeHref = part.replace(/[),.;!?]+$/g, '')
const trailing = part.slice(safeHref.length)
return (
<span key={`link-${index}`}>
<a href={safeHref} target="_blank" rel="noopener noreferrer">
{safeHref}
</a>
{trailing}
</span>
)
})
}
export default function QASection() {
const [questions, setQuestions] = useState<PublicQuestion[]>([])
const [searchQuery, setSearchQuery] = useState('')
@@ -158,7 +180,7 @@ export default function QASection() {
</div>
<div className="qa-card-face qa-card-back">
<span className="qa-face-label">A</span>
<p className="qa-answer-text">{question.answer}</p>
<div className="qa-answer-text">{renderTextWithLinks(question.answer)}</div>
{getRelatedQuestions(question).length > 0 && (
<div className="qa-related-wrap">
<p className="qa-related-label">Related questions</p>