72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import { jalaliToDate } from '@/lib/jalali';
|
||||
|
|
|
|||
|
|
export type ActivityThreadEntry = {
|
|||
|
|
at: Date | null;
|
|||
|
|
dateLabel: string;
|
|||
|
|
timeLabel: string;
|
|||
|
|
author: string;
|
|||
|
|
body: string;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const STAMP = /^\[(.+?) ساعت (\S+?)(?: — (.+))?\]$/;
|
|||
|
|
|
|||
|
|
/** یادداشت فعالیت را به نظرهای جدا با مهر تاریخ/ساعت/نویسنده تبدیل میکند. */
|
|||
|
|
export function parseActivityThread(raw: string | null | undefined): ActivityThreadEntry[] | null {
|
|||
|
|
const text = (raw ?? '').replace(/\r\n/g, '\n').trim();
|
|||
|
|
if (!text) return null;
|
|||
|
|
|
|||
|
|
const entries: ActivityThreadEntry[] = [];
|
|||
|
|
const preamble: string[] = [];
|
|||
|
|
let current: ActivityThreadEntry | null = null;
|
|||
|
|
let sawStamp = false;
|
|||
|
|
|
|||
|
|
for (const line of text.split('\n')) {
|
|||
|
|
const match = line.trim().match(STAMP);
|
|||
|
|
if (match) {
|
|||
|
|
sawStamp = true;
|
|||
|
|
if (current) entries.push(trimEntry(current));
|
|||
|
|
current = {
|
|||
|
|
at: stampToDate(match[1] ?? '', match[2] ?? ''),
|
|||
|
|
dateLabel: (match[1] ?? '').trim(),
|
|||
|
|
timeLabel: (match[2] ?? '').trim(),
|
|||
|
|
author: (match[3] ?? '').trim(),
|
|||
|
|
body: '',
|
|||
|
|
};
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (current) current.body += `${current.body ? '\n' : ''}${line}`;
|
|||
|
|
else preamble.push(line);
|
|||
|
|
}
|
|||
|
|
if (current) entries.push(trimEntry(current));
|
|||
|
|
if (!sawStamp) return null;
|
|||
|
|
|
|||
|
|
const head = preamble.join('\n').trim();
|
|||
|
|
if (head) {
|
|||
|
|
entries.unshift({ at: null, dateLabel: '', timeLabel: '', author: '', body: head });
|
|||
|
|
}
|
|||
|
|
return entries;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function trimEntry(entry: ActivityThreadEntry): ActivityThreadEntry {
|
|||
|
|
return { ...entry, body: entry.body.trim() };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function latinDigits(value: string): string {
|
|||
|
|
const fa = '۰۱۲۳۴۵۶۷۸۹';
|
|||
|
|
const ar = '٠١٢٣٤٥٦٧٨٩';
|
|||
|
|
return value.replace(/[۰-۹٠-٩]/g, (ch) => {
|
|||
|
|
const faIndex = fa.indexOf(ch);
|
|||
|
|
return String(faIndex >= 0 ? faIndex : ar.indexOf(ch));
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function stampToDate(dateLabel: string, timeLabel: string): Date | null {
|
|||
|
|
const date = latinDigits(dateLabel).match(/(\d{4})\/(\d{1,2})\/(\d{1,2})/);
|
|||
|
|
if (!date) return null;
|
|||
|
|
const at = jalaliToDate(Number(date[1]), Number(date[2]), Number(date[3]));
|
|||
|
|
if (Number.isNaN(at.getTime())) return null;
|
|||
|
|
const time = latinDigits(timeLabel).match(/(\d{1,2}):(\d{2})/);
|
|||
|
|
if (time) at.setHours(Number(time[1]), Number(time[2]), 0, 0);
|
|||
|
|
return at;
|
|||
|
|
}
|