Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions frontend/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@ export default function App() {
"ed9109c16f30a470cf0ea2251816789b4ffa510c990118323ce94a2364b9bf05bdb8777959cbac86f5cabc4852e0da71",
"4f2bcdf16c38842e1a45defd944d24ea58bb5bcb76491843223022acfe9eb6f1ff79b2cb9a6b2a9219daf9c7bf40fa37",
"b8ee4b511ef2c9c6ab3e5c0840c5df2218fbb4d9df88254ece7af9462677e55aa5a03838f3ae432d86ca1cb6f992eee7",
"33ffe5cae0f72cfe904bde8019ad98efa0ce5db2800f37c5d4149461023d1f70ea77e4f58ae1327ff46ed6a34045d6e2"
"33ffe5cae0f72cfe904bde8019ad98efa0ce5db2800f37c5d4149461023d1f70ea77e4f58ae1327ff46ed6a34045d6e2",
"a1398fa2946b6ed4b96a1a992ee668aef3661329690f87d44cad5b646ce33e3b16a55674b1d6d54d115a5520801b97d6"
],
pcr0DevValues: [
"799600ba64a29e360b1651f4ced6c9ca5323094a45294551327b996062c3f21e6fef651e7e3d97ec8d25be87b9935b4f",
"2fd9d4f716fd28336d96bc1a20b18a727c2d18f292577ba99323acfc8fb08959428a123b7acff478994c4f961247a0c7",
"4292db2a90ce5ea6f6e2766e0238a328c81dc060a1f3175bced2e94a10e0490d3ff9125d774dafdff969ac661778e757",
"f58409ae1bc8600c887fef5cc4055149c88c94b41c2b3e268826af7b43a1cdbacffdb2c96bf5972120c6460ab83fe89e"
"f58409ae1bc8600c887fef5cc4055149c88c94b41c2b3e268826af7b43a1cdbacffdb2c96bf5972120c6460ab83fe89e",
"6fcdb8086806a96c421c08eaf67cebf164aa898798b6f91b072c884773bc6ed64fe8f5af644fe35411195167b0e4a5f1"
]
}}
>
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/components/AccountMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LogOut, Trash, User, CreditCard, ArrowUpCircle } from "lucide-react";
import { LogOut, Trash, User, CreditCard, ArrowUpCircle, Mail } from "lucide-react";

import { Button } from "@/components/ui/button";
import {
Expand Down Expand Up @@ -144,6 +144,12 @@ export function AccountMenu() {
<span>{isPortalLoading ? "Loading..." : "Manage Subscription"}</span>
</DropdownMenuItem>
)}
<DropdownMenuItem asChild>
<a href="mailto:support@opensecret.cloud">
<Mail className="mr-2 h-4 w-4" />
<span>Contact Us</span>
</a>
</DropdownMenuItem>
<AlertDialogTrigger asChild>
<DropdownMenuItem>
<Trash className="mr-2 h-4 w-4" />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/BillingStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function BillingStatus() {
if (billingStatus.chats_remaining === null || billingStatus.chats_remaining <= 0) {
return "You've run out of chats, upgrade to keep chatting!";
}
return "Free Plan";
return `Free Plan — ${billingStatus.chats_remaining} Chat${billingStatus.chats_remaining === 1 ? "" : "s"} Left This Week`;
}
if (!billingStatus.can_chat) {
if (isPro) {
Expand Down
13 changes: 8 additions & 5 deletions frontend/src/components/Marketing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ export function Marketing() {
return (
<div className="flex flex-col items-center gap-12 text-foreground pt-24 text-white">
<div className="flex flex-col items-center gap-8">
<Link
to="/waitlist"
<a
href="http://blog.opensecret.cloud/maple-private-ai-for-work-and-personal"
target="_blank"
rel="noopener noreferrer"
className="bg-white/10 backdrop-blur-sm px-4 py-1.5 rounded-full border border-white/20 text-sm font-light hover:bg-white/20 transition-colors"
>
🎉 Now in private beta • Join the waitlist
</Link>
🎉 Now Live • Read the Announcement
</a>
<MarketingHeader
title="Private AI Chat"
className="pt-0"
Expand Down Expand Up @@ -82,7 +84,8 @@ export function Marketing() {
<img src="/cloud-gradient.svg" alt="mask test" className="w-32 h-32 self-center p-4" />
<h3 className="text-2xl font-medium">AI Cloud</h3>
<p className="text-lg font-light text-white/70">
Your chats are sent encrypted to a GPU and are impossible to intercept.
Your chats are encrypted and sent to a GPU, providing a highly secure transmission
that's resistant to interception.
</p>
</div>
</div>
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/components/TopNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ export function TopNav() {
</div>

<div className="flex items-center gap-4">
{/* Waitlist Link (Desktop) */}
<div className="hidden sm:block">
<NavLink to="/waitlist">Join Waitlist</NavLink>
</div>

{/* Login/Chat Button */}
{os.auth.user ? (
<Button variant="secondary" onClick={() => navigate({ to: "/" })}>
Expand Down Expand Up @@ -97,9 +92,6 @@ export function TopNav() {
<NavLink to="/about" onClick={() => setMobileMenuOpen(false)}>
About
</NavLink>
<NavLink to="/waitlist" onClick={() => setMobileMenuOpen(false)}>
Join Waitlist
</NavLink>
</div>
</div>
)}
Expand Down
18 changes: 0 additions & 18 deletions frontend/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// Import Routes

import { Route as rootRoute } from './routes/__root'
import { Route as WaitlistImport } from './routes/waitlist'
import { Route as SignupImport } from './routes/signup'
import { Route as ProofImport } from './routes/proof'
import { Route as PricingImport } from './routes/pricing'
Expand All @@ -27,11 +26,6 @@ import { Route as AuthChatChatIdImport } from './routes/_auth.chat.$chatId'

// Create/Update Routes

const WaitlistRoute = WaitlistImport.update({
path: '/waitlist',
getParentRoute: () => rootRoute,
} as any)

const SignupRoute = SignupImport.update({
path: '/signup',
getParentRoute: () => rootRoute,
Expand Down Expand Up @@ -152,13 +146,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof SignupImport
parentRoute: typeof rootRoute
}
'/waitlist': {
id: '/waitlist'
path: '/waitlist'
fullPath: '/waitlist'
preLoaderRoute: typeof WaitlistImport
parentRoute: typeof rootRoute
}
'/password-reset/confirm': {
id: '/password-reset/confirm'
path: '/confirm'
Expand Down Expand Up @@ -203,7 +190,6 @@ export const routeTree = rootRoute.addChildren({
PricingRoute,
ProofRoute,
SignupRoute,
WaitlistRoute,
VerifyCodeRoute,
AuthProviderCallbackRoute,
})
Expand All @@ -224,7 +210,6 @@ export const routeTree = rootRoute.addChildren({
"/pricing",
"/proof",
"/signup",
"/waitlist",
"/verify/$code",
"/auth/$provider/callback"
]
Expand Down Expand Up @@ -259,9 +244,6 @@ export const routeTree = rootRoute.addChildren({
"/signup": {
"filePath": "signup.tsx"
},
"/waitlist": {
"filePath": "waitlist.tsx"
},
"/password-reset/confirm": {
"filePath": "password-reset.confirm.tsx",
"parent": "/password-reset"
Expand Down
6 changes: 2 additions & 4 deletions frontend/src/routes/auth.$provider.callback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,16 @@ function OAuthCallback() {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
const state = urlParams.get("state");
const inviteCode = window.localStorage.getItem(`${provider}_invite_code`) || "";

if (code && state) {
try {
if (provider === "github") {
await handleGitHubCallback(code, state, inviteCode);
await handleGitHubCallback(code, state, "");
} else if (provider === "google") {
await handleGoogleCallback(code, state, inviteCode);
await handleGoogleCallback(code, state, "");
} else {
throw new Error("Unsupported provider");
}
window.localStorage.removeItem(`${provider}_invite_code`); // Clean up
// If successful, redirect to home page after a short delay
setTimeout(() => navigate({ to: "/" }), 2000);
} catch (error) {
Expand Down
103 changes: 8 additions & 95 deletions frontend/src/routes/signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ function SignupPage() {
const formData = new FormData(e.currentTarget);
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const inviteCode = formData.get("inviteCode") as string;

try {
await os.signUp(email, password, inviteCode, "ANON");
await os.signUp(email, password, "", "ANON");
setTimeout(() => {
navigate({ to: next || "/" });
window.scrollTo(0, 0);
Expand All @@ -66,41 +65,21 @@ function SignupPage() {

const handleGitHubSignup = async () => {
try {
const inviteCode = (document.getElementById("inviteCode") as HTMLInputElement)?.value;
if (!inviteCode) {
setError("Invite code is required");
return;
}
const { auth_url } = await os.initiateGitHubAuth(inviteCode);
window.localStorage.setItem("github_invite_code", inviteCode);
const { auth_url } = await os.initiateGitHubAuth("");
window.location.href = auth_url;
} catch (error) {
console.error("Failed to initiate GitHub signup:", error);
if (error instanceof Error && error.message.includes("Invalid invite code")) {
setError("Invalid invite code. Please check and try again.");
} else {
setError("Failed to initiate GitHub signup. Please try again.");
}
setError("Failed to initiate GitHub signup. Please try again.");
}
};

const handleGoogleSignup = async () => {
try {
const inviteCode = (document.getElementById("inviteCode") as HTMLInputElement)?.value;
if (!inviteCode) {
setError("Invite code is required");
return;
}
const { auth_url } = await os.initiateGoogleAuth(inviteCode);
window.localStorage.setItem("google_invite_code", inviteCode);
const { auth_url } = await os.initiateGoogleAuth("");
window.location.href = auth_url;
} catch (error) {
console.error("Failed to initiate Google signup:", error);
if (error instanceof Error && error.message.includes("Invalid invite code")) {
setError("Invalid invite code. Please check and try again.");
} else {
setError("Failed to initiate Google signup. Please try again.");
}
setError("Failed to initiate Google signup. Please try again.");
}
};

Expand All @@ -111,11 +90,11 @@ function SignupPage() {
<Mail className="mr-2 h-4 w-4" />
Sign up with Email
</Button>
<Button onClick={() => setSignUpMethod("github")} className="w-full">
<Button onClick={handleGitHubSignup} className="w-full">
<Github className="mr-2 h-4 w-4" />
Sign up with GitHub
</Button>
<Button onClick={() => setSignUpMethod("google")} className="w-full">
<Button onClick={handleGoogleSignup} className="w-full">
<Google className="mr-2 h-4 w-4" />
Sign up with Google
</Button>
Expand All @@ -129,71 +108,9 @@ function SignupPage() {
);
}

if (signUpMethod === "github") {
return (
<form
onSubmit={(e) => {
e.preventDefault();
handleGitHubSignup();
}}
>
<AuthMain title="Sign Up with GitHub" description="Invite code required for beta access.">
{error && <AlertDestructive title="Error" description={error} />}
<div className="grid gap-2">
<Label htmlFor="inviteCode">Invite Code</Label>
<Input id="inviteCode" name="inviteCode" type="text" required />
</div>
<Button type="submit" className="w-full">
<Github className="mr-2 h-4 w-4" />
Continue with GitHub
</Button>
<Button
type="button"
variant="outline"
onClick={() => setSignUpMethod(null)}
className="w-full"
>
Back
</Button>
</AuthMain>
</form>
);
}

if (signUpMethod === "google") {
return (
<form
onSubmit={(e) => {
e.preventDefault();
handleGoogleSignup();
}}
>
<AuthMain title="Sign Up with Google" description="Invite code required for beta access.">
{error && <AlertDestructive title="Error" description={error} />}
<div className="grid gap-2">
<Label htmlFor="inviteCode">Invite Code</Label>
<Input id="inviteCode" name="inviteCode" type="text" required />
</div>
<Button type="submit" className="w-full">
<Google className="mr-2 h-4 w-4" />
Continue with Google
</Button>
<Button
type="button"
variant="outline"
onClick={() => setSignUpMethod(null)}
className="w-full"
>
Back
</Button>
</AuthMain>
</form>
);
}

return (
<form onSubmit={handleSubmit}>
<AuthMain title="Sign Up with Email" description="Invite code required for beta access.">
<AuthMain title="Sign Up with Email">
{error && <AlertDestructive title="Error" description={error} />}
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
Expand All @@ -217,10 +134,6 @@ function SignupPage() {
autoComplete="new-password"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="inviteCode">Invite Code</Label>
<Input id="inviteCode" name="inviteCode" type="text" required />
</div>
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? (
<>
Expand Down
Loading