This commit is contained in:
Frank
2025-10-10 21:21:55 -04:00
parent b946fd21b1
commit c7dfbbeed0
4 changed files with 51 additions and 33 deletions

View File

@@ -11,6 +11,7 @@ import { Account } from "./account"
import { AccountTable } from "./schema/account.sql" import { AccountTable } from "./schema/account.sql"
import { Key } from "./key" import { Key } from "./key"
import { KeyTable } from "./schema/key.sql" import { KeyTable } from "./schema/key.sql"
import { WorkspaceTable } from "./schema/workspace.sql"
export namespace User { export namespace User {
const assertNotSelf = (id: string) => { const assertNotSelf = (id: string) => {
@@ -115,6 +116,21 @@ export namespace User {
// send email, ignore errors // send email, ignore errors
try { try {
const emailInfo = await Database.use((tx) =>
tx
.select({
email: AccountTable.email,
workspaceName: WorkspaceTable.name,
})
.from(UserTable)
.innerJoin(AccountTable, eq(UserTable.accountID, AccountTable.id))
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, workspaceID))
.where(
and(eq(UserTable.workspaceID, workspaceID), eq(UserTable.id, Actor.assert("user").properties.userID)),
)
.then((rows) => rows[0]),
)
const { InviteEmail } = await import("@opencode-ai/console-mail/InviteEmail.jsx") const { InviteEmail } = await import("@opencode-ai/console-mail/InviteEmail.jsx")
await AWS.sendEmail({ await AWS.sendEmail({
to: email, to: email,
@@ -122,8 +138,10 @@ export namespace User {
body: render( body: render(
// @ts-ignore // @ts-ignore
InviteEmail({ InviteEmail({
inviter: emailInfo.email,
assetsUrl: `https://opencode.ai/email`, assetsUrl: `https://opencode.ai/email`,
workspace: workspaceID, workspaceID: workspaceID,
workspaceName: emailInfo.workspaceName,
}), }),
), ),
}) })

View File

@@ -31,6 +31,10 @@ export function A({ children, ...props }: AProps) {
return React.createElement("a", props, children) return React.createElement("a", props, children)
} }
export function B({ children, ...props }: AProps) {
return React.createElement("b", props, children)
}
export function Span({ children, ...props }: SpanProps) { export function Span({ children, ...props }: SpanProps) {
return React.createElement("span", props, children) return React.createElement("span", props, children)
} }

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import React from "react" import React from "react"
import { Img, Row, Html, Link, Body, Head, Button, Column, Preview, Section, Container } from "@jsx-email/all" import { Img, Row, Html, Link, Body, Head, Button, Column, Preview, Section, Container } from "@jsx-email/all"
import { Hr, Text, Fonts, SplitString, Title, A, Span } from "../components" import { Hr, Text, Fonts, SplitString, Title, A, Span, B } from "../components"
import { import {
unit, unit,
body, body,
@@ -23,17 +23,24 @@ const CONSOLE_URL = "https://opencode.ai/"
const DOC_URL = "https://opencode.ai/docs/zen" const DOC_URL = "https://opencode.ai/docs/zen"
interface InviteEmailProps { interface InviteEmailProps {
workspace: string inviter: string
workspaceID: string
workspaceName: string
assetsUrl: string assetsUrl: string
} }
export const InviteEmail = ({ workspace, assetsUrl = LOCAL_ASSETS_URL }: InviteEmailProps) => { export const InviteEmail = ({
const subject = `Join the ${workspace} workspace` inviter = "test@anoma.ly",
const messagePlain = `You've been invited to join the ${workspace} workspace in the OpenCode Zen Console.` workspaceID = "wrk_01K6XFY7V53T8XN0A7X8G9BTN3",
const url = `${CONSOLE_URL}workspace/${workspace}` workspaceName = "anomaly",
assetsUrl = LOCAL_ASSETS_URL,
}: InviteEmailProps) => {
const subject = `You were invited to the OpenCode Console`
const messagePlain = `${inviter} invited you to join the ${workspaceName} workspace (${workspaceID}).`
const url = `${CONSOLE_URL}workspace/${workspaceID}`
return ( return (
<Html lang="en"> <Html lang="en">
<Head> <Head>
<Title>{`OpenCode Zen ${messagePlain}`}</Title> <Title>{`OpenCode — ${messagePlain}`}</Title>
</Head> </Head>
<Fonts assetsUrl={assetsUrl} /> <Fonts assetsUrl={assetsUrl} />
<Preview>{messagePlain}</Preview> <Preview>{messagePlain}</Preview>
@@ -42,15 +49,10 @@ export const InviteEmail = ({ workspace, assetsUrl = LOCAL_ASSETS_URL }: InviteE
<Section style={frame}> <Section style={frame}>
<Row> <Row>
<Column> <Column>
<A href={CONSOLE_URL}> <A href={`${CONSOLE_URL}zen`}>
<Img height="32" alt="OpenCode Zen Logo" src={`${assetsUrl}/zen-logo.png`} /> <Img height="32" alt="OpenCode Logo" src={`${assetsUrl}/logo.png`} />
</A> </A>
</Column> </Column>
<Column align="right">
<Button style={buttonPrimary} href={url}>
<Span style={code}>Join Workspace</Span>
</Button>
</Column>
</Row> </Row>
<Row style={headingHr}> <Row style={headingHr}>
@@ -59,32 +61,26 @@ export const InviteEmail = ({ workspace, assetsUrl = LOCAL_ASSETS_URL }: InviteE
</Column> </Column>
</Row> </Row>
<Section>
<Text style={{ ...compactText, ...breadcrumb }}>
<Span>OpenCode Zen</Span>
<Span style={{ ...code, ...breadcrumbColonSeparator }}>:</Span>
<Span>{workspace}</Span>
</Text>
<Text style={{ ...heading, ...compactText }}>
<Link href={url}>
<SplitString text={subject} split={40} />
</Link>
</Text>
</Section>
<Section style={{ padding: `${unit}px 0 0 0` }}> <Section style={{ padding: `${unit}px 0 0 0` }}>
<Text style={{ ...compactText }}> <Text style={{ ...compactText }}>
You've been invited to join the{" "} <B>{inviter}</B> invited you to join the{" "}
<Link style={medium} href={url}> <Link style={medium} href={url}>
{workspace} <B>{workspaceName}</B>
</Link>{" "} </Link>{" "}
workspace in the{" "} workspace ({workspaceID}) in the{" "}
<Link style={medium} href={CONSOLE_URL}> <Link style={medium} href={`${CONSOLE_URL}zen`}>
OpenCode Zen Console OpenCode Console
</Link> </Link>
. .
</Text> </Text>
</Section> </Section>
<Section style={{ padding: `${unit}px 0 0 0` }}>
<Button style={buttonPrimary} href={url}>
<Span style={code}>Join Workspace</Span>
</Button>
</Section>
<Row style={headingHr}> <Row style={headingHr}>
<Column> <Column>
<Hr /> <Hr />
@@ -93,7 +89,7 @@ export const InviteEmail = ({ workspace, assetsUrl = LOCAL_ASSETS_URL }: InviteE
<Row> <Row>
<Column> <Column>
<Link href={CONSOLE_URL} style={footerLink}> <Link href={`${CONSOLE_URL}zen`} style={footerLink}>
Console Console
</Link> </Link>
</Column> </Column>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB