Skip to content

Instantly share code, notes, and snippets.

@alexruimy
Last active August 10, 2022 21:50
Show Gist options
  • Save alexruimy/1a14ac9d0a74ef1816196ffe2c349e15 to your computer and use it in GitHub Desktop.
Save alexruimy/1a14ac9d0a74ef1816196ffe2c349e15 to your computer and use it in GitHub Desktop.
Email model notes
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<Response> {
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 = <Participant>{
type: getChoiceFromArray(["specta", "external"]),
userId: faker.datatype.uuid(),
email: faker.internet.email(),
name: faker.name.fullName(),
};
participants.push(p);
}
let ps = <Participants>{ 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 = <EmailThread>{
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("------");
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment