feat: multi-media attachments, linkify URLs, shared MessageMediaGrid

- Add media_items array support to ticket messages (types, API clients)
- Create shared MessageMediaGrid component with photo grid, fullscreen
  viewer, keyboard nav, video/document rendering
- Replace per-page AdminMessageMedia/MessageMedia with MessageMediaGrid
- Add linkifyText util (DOMPurify-sanitized) for auto-linking URLs
- Support multi-file upload (up to 10) in AdminTickets and Support pages
- Remove unused ticketsApi import from AdminUserDetail
This commit is contained in:
Fringg
2026-04-29 08:45:15 +03:00
parent 9b1e26d4ec
commit 6d3010b621
8 changed files with 666 additions and 553 deletions

28
src/utils/linkify.ts Normal file
View File

@@ -0,0 +1,28 @@
import DOMPurify from 'dompurify';
/**
* Match http(s) URLs but exclude common trailing punctuation that is unlikely
* to be part of the URL itself (e.g. the period at the end of a sentence,
* or a closing bracket / quote that wraps the URL).
*/
const URL_REGEX = /(https?:\/\/[^\s<]+[^\s<.,;:!?\])}"'])/g;
/**
* Linkify plain text by wrapping http(s) URLs in <a> tags.
* Returns an HTML string sanitized via DOMPurify with a strict allowlist
* (only <a> + <br>), safe to render in the UI.
*
* Trailing punctuation (.,;:!?)]}"') is excluded from the URL match so a
* sentence like `Visit https://example.com.` does not capture the period.
*/
export function linkifyText(text: string | null | undefined): string {
if (!text) return '';
const replaced = text.replace(
URL_REGEX,
'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>',
);
return DOMPurify.sanitize(replaced, {
ALLOWED_TAGS: ['a', 'br'],
ALLOWED_ATTR: ['href', 'target', 'rel'],
});
}