import { faker } from "@faker-js/faker"; // maps to firestore root collection: EmailThread class EmailThread { id: string; eeid: string; // emailengine thread id subject: ThreadSubject; participants: Participants; } class ThreadSubject { default: string; [userId: string]: string; } interface Participants { to: Participant[]; cc?: Participant[]; bcc?: Participant[]; } // map to a Specta user or external contact (eventually, will be part of a Contact model) class Participant { type: "specta" | "external"; userId?: string; email?: string; name?: string; } enum ThreadMessageType { message = "message", suggestion = "suggestion", loopIn = "loopIn", forward = "forward", partialReply = "partialReply", } // subclasses of ThreadItem map to firestore root collection: EmailThreadMessages abstract class ThreadItem { id: string; from: Participant; type: ThreadMessageType; eeid?: string; // emailengine message id participants: Participants; attachments?: []; content?: string; banner?: ThreadItemBanner; hasMessage: Boolean; messageIsCollapsed: Boolean; } class ThreadItemBanner { content: string; isInline: Boolean; printBanner?(): string; constructor(content: string, isInline = false) { this.content = content; this.isInline = isInline; } } class ThreadMessage extends ThreadItem { type = ThreadMessageType.message; content = faker.lorem.sentence(Math.floor(Math.random() * 5) + 1); hasMessage = true; messageIsCollapsed = false; getContent(): Promise { return fetch(`https://mail.joinspecta.com/api/v1/emails/${this.eeid}`); } } class ThreadSuggestion extends ThreadItem { type = ThreadMessageType.suggestion; hasMessage = false; suggestionTo: Participant; constructor() { super(); const bannerContent = `${this.suggestionTo.name} was suggested to reply by ${this.from.name}`; this.banner = new ThreadItemBanner(bannerContent); } } class ThreadLoopIn extends ThreadItem { type = ThreadMessageType.loopIn; hasMessage = true; messageIsCollapsed = true; loopedIn: Participants[]; formattedParticipants = ""; // todo constructor() { super(); const bannerContent = `${this.formattedParticipants} has been added to the email chain.`; this.banner = new ThreadItemBanner(bannerContent); } } class ThreadForward extends ThreadItem { type = ThreadMessageType.forward; bannerOnly = false; hasMessage = true; messageIsCollapsed = true; formattedParticipants = ""; // todo constructor() { super(); const bannerContent = `Forwarded to ${this.formattedParticipants}`; this.banner = new ThreadItemBanner(bannerContent); } } class ThreadPartialReply extends ThreadItem { type = ThreadMessageType.partialReply; bannerOnly = false; hasBanner = true; hasMessage = true; bannerIsInline = true; messageIsCollapsed = false; formattedParticipants = ""; // todo constructor() { super(); const bannerContent = `Reply to ${this.formattedParticipants}`; this.banner = new ThreadItemBanner(bannerContent, true); } } /// BELOW HERE I JUST PLAYED WITH GENERATING AN EMAIL THREAD, PROBABLY NOTHING TO SEE HERE const getChoiceFromArray = (array: any[]) => array[Math.floor(Math.random() * array.length)]; // fetch email content from emailengine const urlprefix = "https://mail.joinspecta.com/"; const getEmailContent = async (eeid: string) => { const response = await fetch(`${urlprefix}api/v1/threads/${eeid}`); const data = await response.json(); return data; }; function getThreadItem(): ThreadItem { const random = Math.random(); let threadItem; if (random < 0.4) { threadItem = new ThreadMessage(); } else { const randomType = Math.floor(Math.random() * 4); switch (randomType) { case 0: threadItem = new ThreadSuggestion(); case 1: threadItem = new ThreadLoopIn(); case 2: threadItem = new ThreadForward(); case 3: threadItem = new ThreadPartialReply(); } } threadItem.id = faker.datatype.uuid(); return threadItem; } let participants = Array(); for (let i = 0; i < 4; i++) { let p = { type: getChoiceFromArray(["specta", "external"]), userId: faker.datatype.uuid(), email: faker.internet.email(), name: faker.name.fullName(), }; participants.push(p); } let ps = { to: participants }; // create an array of 20 messages. // instantiate each message with getThreadMessage() // if message is a message let messages = Array(); for (let i = 0; i < 10; i++) { let currentUser = getChoiceFromArray(participants); let recipient = getChoiceFromArray( participants.filter((p) => p !== currentUser) ); let m = getThreadItem(); m.from = currentUser; m.participants = ps; messages.push(m); } // messages.push(m); // console.log(messages); // todo: add normalizer for thread id let thread = { id: "1", eeid: "1", subject: { default: "Hello" }, participants: ps, }; let messageCount = 0; messages.forEach((m) => { if (m.type === ThreadMessageType.message) { messageCount++; console.log("MESSAGE " + messageCount); console.log( "TO: " + m.participants.to.map((p: Participant) => p.email).join(", ") ); console.log("FROM: " + m.from.email); console.log(m.content); } else { console.log(m.banner.toUpperCase()); if (!m.bannerOnly) { console.log( m.from.name, m.participants.to.map((p: Participant) => p.name).join(", ") ); } } console.log("------"); });