UI enhancement
This commit is contained in:
parent
23239c5cb6
commit
53922952c6
13 changed files with 1076 additions and 260 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import { senderDisplayName } from "./senderAvatar";
|
||||
|
||||
const CATEGORY_ORDER = ["Primary", "Updates", "Promotions", "Social", "Finance"];
|
||||
|
||||
export function emailSearchText(email) {
|
||||
|
|
@ -88,6 +90,95 @@ export function attachmentCount(email) {
|
|||
return Number(email.attachment_count || 0);
|
||||
}
|
||||
|
||||
function emailTimestamp(email) {
|
||||
const value = email.received_at || email.sent_at || email.created_at || email.updated_at;
|
||||
if (!value) return null;
|
||||
const date = new Date(value);
|
||||
return Number.isNaN(date.getTime()) ? null : date;
|
||||
}
|
||||
|
||||
function formatRelativeAge(date) {
|
||||
if (!date) return "";
|
||||
const hours = Math.floor((Date.now() - date.getTime()) / 3600000);
|
||||
if (hours < 1) return "<1h";
|
||||
if (hours < 24) return `${hours}h`;
|
||||
return `${Math.floor(hours / 24)}d`;
|
||||
}
|
||||
|
||||
function extractMeetingTime(text) {
|
||||
const match = text.match(/\b(\d{1,2}:\d{2})\s*(am|pm)?/i)
|
||||
|| text.match(/\b(\d{1,2})\s*(am|pm)\b/i);
|
||||
if (!match) return null;
|
||||
return match[0].replace(/\s+/g, "").toUpperCase();
|
||||
}
|
||||
|
||||
function extractDeadline(text) {
|
||||
if (/tomorrow/i.test(text)) return "Tomorrow";
|
||||
const weekday = text.match(/\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\b/i);
|
||||
if (weekday) {
|
||||
return weekday[1].charAt(0).toUpperCase() + weekday[1].slice(1);
|
||||
}
|
||||
if (/today/i.test(text)) return "Today";
|
||||
return null;
|
||||
}
|
||||
|
||||
export function inboxContext(emails) {
|
||||
const stats = inboxIntelligence(emails);
|
||||
|
||||
const needsReply = emails
|
||||
.filter((email) =>
|
||||
/please|reply|respond|confirm|review|attached|need your|waiting|action required/.test(
|
||||
emailSearchText(email),
|
||||
),
|
||||
)
|
||||
.sort((left, right) => {
|
||||
const leftDate = emailTimestamp(left)?.getTime() || 0;
|
||||
const rightDate = emailTimestamp(right)?.getTime() || 0;
|
||||
return rightDate - leftDate;
|
||||
})
|
||||
.slice(0, 4)
|
||||
.map((email) => ({
|
||||
id: email.id,
|
||||
name: senderDisplayName(email),
|
||||
age: formatRelativeAge(emailTimestamp(email)),
|
||||
}));
|
||||
|
||||
const today = [];
|
||||
emails.forEach((email) => {
|
||||
const text = emailSearchText(email);
|
||||
if (!/meet|meeting|call|interview|sync|calendar/.test(text)) return;
|
||||
const time = extractMeetingTime(text);
|
||||
if (!time) return;
|
||||
const label = (email.subject || "Meeting").trim().slice(0, 42);
|
||||
if (!today.some((item) => item.time === time && item.label === label)) {
|
||||
today.push({ time, label });
|
||||
}
|
||||
});
|
||||
|
||||
const deadlines = [];
|
||||
emails.forEach((email) => {
|
||||
const text = emailSearchText(email);
|
||||
if (!/invoice|proposal|payment|due|deadline|bill/.test(text)) return;
|
||||
const due = extractDeadline(text);
|
||||
if (!due) return;
|
||||
const label = (email.subject || "Deadline")
|
||||
.split(/[-–:|]/)
|
||||
.map((part) => part.trim())
|
||||
.find(Boolean)
|
||||
?.slice(0, 28) || "Deadline";
|
||||
if (!deadlines.some((item) => item.label === label && item.due === due)) {
|
||||
deadlines.push({ label, due });
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
stats,
|
||||
needsReply,
|
||||
today: today.slice(0, 4),
|
||||
deadlines: deadlines.slice(0, 4),
|
||||
};
|
||||
}
|
||||
|
||||
export function labelCounts(emails) {
|
||||
const counts = {
|
||||
Important: 0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue