fix(activities): show form photos in the note instead of the raw file link
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -50,7 +50,78 @@ export function parseLeadFormNotes(raw: string | null | undefined): LeadNoteView
|
||||
}
|
||||
|
||||
export function leadNoteFileIsImage(file: LeadNoteFile): boolean {
|
||||
return file.mime.startsWith('image/') || (file.dataUrl ?? '').startsWith('data:image/');
|
||||
return (
|
||||
file.mime.startsWith('image/') ||
|
||||
(file.dataUrl ?? '').startsWith('data:image/') ||
|
||||
/\.(png|jpe?g|gif|webp)$/i.test(file.name)
|
||||
);
|
||||
}
|
||||
|
||||
export type NoteChip =
|
||||
| { kind: 'text'; text: string }
|
||||
| { kind: 'image'; src: string; name: string }
|
||||
| { kind: 'link'; href: string; label: string };
|
||||
|
||||
const FILE_BLOB = /\{[^{}]*"dataUrl"\s*:\s*"data:[^"]+"[^{}]*\}/gi;
|
||||
const DATA_IMAGE = /data:image\/[a-z0-9.+-]+;base64,[a-z0-9+/=]+/gi;
|
||||
const HTTP_URL = /https?:\/\/[^\s<>"']+/gi;
|
||||
|
||||
/** متن یادداشت را به نوشته، لینک کوتاه و تصویر جدا میکند. */
|
||||
export function noteChips(raw: string | null | undefined): NoteChip[] {
|
||||
const text = raw ?? '';
|
||||
if (!text.trim()) return [];
|
||||
const chips: NoteChip[] = [];
|
||||
const token = new RegExp(
|
||||
`${FILE_BLOB.source}|${DATA_IMAGE.source}|${HTTP_URL.source}`,
|
||||
'gi',
|
||||
);
|
||||
let cursor = 0;
|
||||
for (const match of text.matchAll(token)) {
|
||||
const index = match.index ?? 0;
|
||||
pushText(chips, text.slice(cursor, index));
|
||||
chips.push(chipForToken(match[0]));
|
||||
cursor = index + match[0].length;
|
||||
}
|
||||
pushText(chips, text.slice(cursor));
|
||||
return chips;
|
||||
}
|
||||
|
||||
function pushText(chips: NoteChip[], value: string) {
|
||||
if (!value) return;
|
||||
const prev = chips[chips.length - 1];
|
||||
if (prev?.kind === 'text') prev.text += value;
|
||||
else chips.push({ kind: 'text', text: value });
|
||||
}
|
||||
|
||||
function chipForToken(token: string): NoteChip {
|
||||
if (token.startsWith('{')) {
|
||||
const file = readFileValue(token);
|
||||
if (file?.dataUrl && leadNoteFileIsImage(file)) {
|
||||
return { kind: 'image', src: file.dataUrl, name: file.name };
|
||||
}
|
||||
if (file?.dataUrl) return { kind: 'link', href: file.dataUrl, label: file.name };
|
||||
return { kind: 'text', text: file?.name || 'فایل پیوست' };
|
||||
}
|
||||
if (token.startsWith('data:image/')) {
|
||||
return { kind: 'image', src: token, name: 'تصویر پیوست' };
|
||||
}
|
||||
if (isImageUrl(token)) return { kind: 'image', src: token, name: shortUrl(token) };
|
||||
return { kind: 'link', href: token, label: shortUrl(token) };
|
||||
}
|
||||
|
||||
function isImageUrl(href: string): boolean {
|
||||
return /\.(png|jpe?g|gif|webp)(\?.*)?$/i.test(href);
|
||||
}
|
||||
|
||||
function shortUrl(href: string): string {
|
||||
try {
|
||||
const url = new URL(href);
|
||||
const file = decodeURIComponent(url.pathname.split('/').filter(Boolean).pop() ?? '');
|
||||
const label = file || url.hostname;
|
||||
return label.length > 42 ? `${label.slice(0, 24)}…${label.slice(-10)}` : label;
|
||||
} catch {
|
||||
return href.length > 42 ? `${href.slice(0, 28)}…` : href;
|
||||
}
|
||||
}
|
||||
|
||||
/** فیلد تاریخ تولد روی خود لید هست؛ جواب فرم نباید دوباره ردیف بسازد. */
|
||||
@@ -111,7 +182,8 @@ function readFileValue(value: string): LeadNoteFile | null {
|
||||
return asFile(JSON.parse(value));
|
||||
} catch {
|
||||
const name = value.match(/"name"\s*:\s*"([^"]+)"/)?.[1]?.trim();
|
||||
if (name) return { name, mime: '', dataUrl: null };
|
||||
const mime = value.match(/"mime"\s*:\s*"([^"]+)"/)?.[1]?.trim() ?? '';
|
||||
if (name) return { name, mime, dataUrl: null };
|
||||
if (value.includes('data:')) return { name: 'فایل پیوست', mime: '', dataUrl: null };
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user