-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(email): storybook like email package
- Loading branch information
1 parent
442f3d2
commit e14d9c4
Showing
24 changed files
with
1,358 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
/node_modules | ||
node_modules | ||
*.swp | ||
*.swo | ||
*.orig | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// | ||
|
||
export class ChangeView extends HTMLElement { | ||
static tag = "x-change-view" as const; | ||
static define() { | ||
customElements.define(ChangeView.tag, this); | ||
} | ||
constructor() { | ||
super(); | ||
this.attachShadow({ mode: "open" }); | ||
} | ||
connectedCallback() { | ||
this.#render(); | ||
|
||
this.#inputs.forEach((element) => { | ||
element.addEventListener("click", () => { | ||
this.#view = element.value as "desktop" | "html"; | ||
}); | ||
}); | ||
} | ||
#render() { | ||
if (!this.shadowRoot) return; | ||
this.shadowRoot.innerHTML = ( | ||
<ChangeViewUI view={ChangeView.current} /> | ||
).toString(); | ||
} | ||
|
||
// | ||
|
||
static get current(): "desktop" | "html" { | ||
const view = new URLSearchParams(location.search).get("view"); | ||
return view === "html" ? view : "desktop"; | ||
} | ||
|
||
set #view(value: "desktop" | "html") { | ||
const url = new URL(location.href); | ||
url.searchParams.set("view", value); | ||
window.location.href = url.toString(); | ||
} | ||
|
||
// | ||
|
||
get #inputs() { | ||
if (!this.shadowRoot) throw new Error("ShadowRoot not found"); | ||
return this.shadowRoot.querySelectorAll("button"); | ||
} | ||
} | ||
|
||
ChangeView.define(); | ||
|
||
function ChangeViewUI({ view }: { view: string }) { | ||
return ( | ||
<nav> | ||
<button disabled={view === "desktop"} value="desktop"> | ||
Desktop | ||
</button> | ||
<button disabled={view === "html"} value="html"> | ||
HTML | ||
</button> | ||
</nav> | ||
); | ||
} |
142 changes: 142 additions & 0 deletions
142
packages/email/.storybook/SendEmailFormWebComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// | ||
|
||
type SendEmailOptions = { | ||
sender: { name: string; email: string }; | ||
to: { | ||
name: string; | ||
email: string; | ||
}[]; | ||
subject: string; | ||
htmlContent: string; | ||
}; | ||
|
||
// | ||
|
||
export class SendEmailFormWebComponent extends HTMLElement { | ||
static tag = "x-send-email-form" as const; | ||
static define() { | ||
customElements.define(SendEmailFormWebComponent.tag, this); | ||
} | ||
static BREVO_API_KEY = import.meta.env["VITE_BREVO_API_KEY"]; | ||
|
||
// | ||
|
||
constructor() { | ||
super(); | ||
this.attachShadow({ mode: "open" }); | ||
} | ||
|
||
connectedCallback() { | ||
if (!SendEmailFormWebComponent.BREVO_API_KEY) { | ||
console.warn( | ||
"No API key found for brevo, please set VITE_BREVO_API_KEY env variable if you want to test the email in a real email client environment", | ||
); | ||
return; | ||
} | ||
|
||
this.#render(); | ||
|
||
this.#form.addEventListener("submit", (e) => { | ||
e.preventDefault(); | ||
this.submit(this.innerHTML); | ||
}); | ||
} | ||
|
||
async submit(template: string) { | ||
const headers = new Headers(); | ||
headers.append("accept", "application/json"); | ||
headers.append("api-key", SendEmailFormWebComponent.BREVO_API_KEY); | ||
headers.append("content-type", "application/json"); | ||
|
||
await fetch("https://api.brevo.com/v3/smtp/email", { | ||
method: "POST", | ||
headers, | ||
body: JSON.stringify({ | ||
htmlContent: template, | ||
sender: { | ||
name: "MonComptePro", | ||
email: "[email protected]", | ||
}, | ||
subject: this.#object.value, | ||
to: [{ name: "Ike Proconnect", email: this.#to.value }], | ||
} as SendEmailOptions), | ||
redirect: "follow", | ||
}); | ||
} | ||
|
||
// | ||
|
||
#render() { | ||
if (!this.shadowRoot) return; | ||
this.shadowRoot.innerHTML = ( | ||
<details | ||
style={{ | ||
backgroundColor: "white", | ||
boxShadow: "0px 2px 6px 0px rgba(0, 0, 18, 0.16)", | ||
position: "fixed", | ||
bottom: "8px", | ||
right: "8px", | ||
}} | ||
> | ||
<summary style={{ background: "gainsboro", padding: "8px" }}> | ||
📨 | ||
</summary> | ||
|
||
<form | ||
style={{ | ||
display: "flex", | ||
flexDirection: "column", | ||
padding: "8px", | ||
}} | ||
> | ||
<label style={{ display: "flex", alignItems: "center" }}> | ||
<div style={{ marginRight: "8px" }}>To</div> | ||
<input | ||
name="to" | ||
value="[email protected]" | ||
style={{ flexGrow: 1 }} | ||
/> | ||
</label> | ||
<label style={{ display: "flex", alignItems: "center" }}> | ||
<div style={{ marginRight: "8px" }}>Subject</div> | ||
<input | ||
name="object" | ||
value="[Localhost] test email" | ||
style={{ flexGrow: 1 }} | ||
/> | ||
</label> | ||
<div | ||
style={{ | ||
display: "flex", | ||
alignItems: "end", | ||
justifyContent: "space-between", | ||
}} | ||
> | ||
<p style={{ marginBottom: "0" }}> | ||
Powered by <a href="https://brevo.com">Brevo</a> | ||
</p> | ||
<button>Send</button> | ||
</div> | ||
</form> | ||
</details> | ||
).toString(); | ||
} | ||
|
||
get #form() { | ||
const element = this.shadowRoot?.querySelector("form"); | ||
if (!element) throw new Error("No form found"); | ||
return element; | ||
} | ||
get #to() { | ||
const element = this.shadowRoot?.querySelector("input[name=to]"); | ||
if (!element) throw new Error("No input[name=to] found"); | ||
return element as HTMLInputElement; | ||
} | ||
get #object() { | ||
const element = this.shadowRoot?.querySelector("input[name=object]"); | ||
if (!element) throw new Error("No input[name=object] found"); | ||
return element as HTMLInputElement; | ||
} | ||
} | ||
|
||
SendEmailFormWebComponent.define(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<!doctype html> | ||
<html | ||
lang="en" | ||
style=" | ||
margin: 0; | ||
padding: 0; | ||
font-family: | ||
-apple-system, | ||
BlinkMacSystemFont, | ||
Segoe UI, | ||
Roboto, | ||
Oxygen-Sans, | ||
Ubuntu, | ||
Cantarell, | ||
Helvetica Neue, | ||
sans-serif; | ||
" | ||
> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Storybook like . Email Preview</title> | ||
</head> | ||
<body style="margin: 0; padding: 0"> | ||
<div id="root"></div> | ||
<script type="module" src="/.storybook/index.tsx"></script> | ||
</body> | ||
</html> |
Oops, something went wrong.