Skip to content

Commit 68a5e9e

Browse files
updated pricing card & nav
1 parent b70dacd commit 68a5e9e

File tree

7 files changed

+199
-24
lines changed

7 files changed

+199
-24
lines changed

app/api/chat/codeInterpreter.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import 'server-only';
2+
3+
import { Sandbox } from '@e2b/code-interpreter';
4+
5+
const E2B_API_KEY = process.env.E2B_API_KEY;
6+
if (!E2B_API_KEY) {
7+
throw new Error('E2B_API_KEY environment variable not found');
8+
}
9+
10+
const sandboxTimeout = 10 * 60 * 1000;
11+
12+
export async function evaluateCode(
13+
sessionID: string,
14+
code: string,
15+
) {
16+
const sandbox = await getSandbox(sessionID);
17+
18+
// Execute the code in a Jupyter Notebook in the sandbox.
19+
// https://e2b.dev/docs/code-interpreter/execution
20+
const execution = await sandbox.runCode(code, {
21+
// We can also use callbacks to handle streaming stdout, stderr, and results from the sandbox.
22+
// This is useful if you want to stream the results to client directly.
23+
// onStdout,
24+
// onStderr,
25+
// onResult,
26+
});
27+
28+
return {
29+
results: execution.results,
30+
stdout: execution.logs.stdout,
31+
stderr: execution.logs.stderr,
32+
error: execution.error,
33+
};
34+
}
35+
36+
37+
async function getSandbox(sessionID: string) {
38+
const sandboxes = await Sandbox.list();
39+
40+
const sandboxID = sandboxes.find(sandbox => sandbox.metadata?.sessionID === sessionID)?.sandboxId;
41+
42+
if (sandboxID) {
43+
const sandbox = await Sandbox.connect(sandboxID, {
44+
apiKey: E2B_API_KEY,
45+
})
46+
await sandbox.setTimeout(sandboxTimeout);
47+
return sandbox;
48+
} else {
49+
const sandbox = await Sandbox.create({
50+
apiKey: E2B_API_KEY,
51+
metadata: {
52+
sessionID,
53+
},
54+
timeoutMs: sandboxTimeout
55+
});
56+
return sandbox;
57+
}
58+
}
59+
60+
export function nonEmpty<T>(value: T | null | undefined): value is T {
61+
return value !== null && value !== undefined;
62+
}

app/page.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,11 @@ export default function Home() {
342342
/>
343343
)}
344344

345-
<Sidebar onStateChange={setSidebarOpen} userName={userTeam?.name} userPlan={userTeam?.tier} />
345+
<Sidebar
346+
onStateChange={setSidebarOpen}
347+
userName={userTeam?.name}
348+
userPlan={userTeam?.tier}
349+
/>
346350

347351

348352
{/* Main content with left margin to account for collapsed sidebar */}
@@ -420,4 +424,4 @@ export default function Home() {
420424
</div>
421425
</main>
422426
)
423-
}
427+
}

components/navbar.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// File: components/navbar.tsx
21
import Logo from './logo'
32
import { Button } from '@/components/ui/button'
43
import {
@@ -116,7 +115,7 @@ export function NavBar({
116115
<DropdownMenuSeparator />
117116
<DropdownMenuItem
118117
onClick={() => {
119-
window.open('https://codinit.dev', '_blank')
118+
window.open('https://codinit.dev/codinit-beta', '_blank')
120119
}}
121120
>
122121
<Image

components/pricing.tsx

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"use client"
2+
3+
import { PricingCard } from "@/components/ui/pricing-card"
4+
import {
5+
Dialog,
6+
DialogContent,
7+
DialogHeader,
8+
DialogTitle,
9+
DialogDescription,
10+
} from "@/components/ui/dialog"
11+
12+
interface PricingModalProps {
13+
isOpen: boolean
14+
onClose: () => void
15+
}
16+
17+
export function PricingModal({ isOpen, onClose }: PricingModalProps) {
18+
return (
19+
<Dialog open={isOpen} onOpenChange={onClose}>
20+
<DialogContent className="max-w-7xl">
21+
<DialogHeader className="text-left md:text-center">
22+
<DialogTitle className="mb-3 text-3xl font-semibold md:mb-4 lg:mb-6 lg:text-4xl">
23+
Plans made for every developer
24+
</DialogTitle>
25+
<DialogDescription className="text-muted-foreground lg:text-lg mb-6 md:mb-8 lg:mb-12">
26+
Start building with our powerful tools. Upgrade anytime as your needs grow.
27+
</DialogDescription>
28+
</DialogHeader>
29+
30+
<div className="rounded-xl flex flex-col justify-between border p-1">
31+
<div className="flex flex-col gap-4 md:flex-row">
32+
<PricingCard
33+
title="Free / Open Source"
34+
price="$0 / forever"
35+
description="Perfect for individual developers and open source projects."
36+
buttonText="Current Plan"
37+
buttonVariant="outline"
38+
features={[
39+
"Unlimited code generation",
40+
"All AI models included",
41+
"Community support",
42+
"Self-hosted deployment",
43+
"GitHub integration",
44+
"Open source license",
45+
]}
46+
/>
47+
48+
<PricingCard
49+
title="Pro Developer"
50+
price="$9.99 / month"
51+
description="Enhanced features for professional developers and teams."
52+
buttonText="Start Pro Trial"
53+
buttonVariant="default"
54+
features={[
55+
"Advanced AI models (GPT-4, Claude)",
56+
"Priority code generation",
57+
"Private cloud hosting",
58+
"Advanced debugging tools",
59+
"Custom component libraries",
60+
"Priority support",
61+
"Team collaboration",
62+
"Usage analytics",
63+
]}
64+
/>
65+
66+
<PricingCard
67+
title="Enterprise"
68+
price="Custom / month"
69+
description="Custom solutions for large development teams and organizations."
70+
buttonText="Contact Sales"
71+
buttonVariant="default"
72+
highlight
73+
badge="Most Popular"
74+
features={[
75+
"Custom AI model fine-tuning",
76+
"On-premises deployment",
77+
"SSO & enterprise security",
78+
"Dedicated support manager",
79+
"Custom integrations",
80+
"SLA guarantees",
81+
"White-label options",
82+
"Custom training & onboarding",
83+
]}
84+
/>
85+
</div>
86+
</div>
87+
</DialogContent>
88+
</Dialog>
89+
)
90+
}

components/sidebar.tsx

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,12 @@ import {
99
Search,
1010
Settings,
1111
HelpCircle,
12-
User,
1312
LogOut,
14-
Plus,
15-
Calendar,
16-
Archive,
17-
Star,
18-
ChevronDown,
1913
MoreHorizontal,
2014
CreditCardIcon
2115
} from 'lucide-react';
2216
import Logo from './logo';
17+
import { PricingModal } from './pricing';
2318

2419
export interface SidebarProps {
2520
children?: ReactNode;
@@ -157,10 +152,9 @@ const DefaultSidebarContent: React.FC<{
157152
session: Session | null;
158153
}> = ({ userName, userPlan, session }) => {
159154
const [searchQuery, setSearchQuery] = useState('');
155+
const [isPricingModalOpen, setIsPricingModalOpen] = useState(false);
160156

161-
const recentChats = [
162-
''
163-
];
157+
const recentChats: string[] = [];
164158

165159
return (
166160
<div className="flex flex-col h-full bg-background text-foreground">
@@ -220,11 +214,6 @@ const DefaultSidebarContent: React.FC<{
220214
</div>
221215
</div>
222216

223-
{/* Last 30 Days */}
224-
<div className="mb-4">
225-
<div className="flex items-center gap-2 mb-2">
226-
<h4 className="text-xs text-muted-foreground">Last 30 days</h4>
227-
</div>
228217
<div className="space-y-1">
229218
{recentChats.slice(1, 6).map((chat, index) => (
230219
<div
@@ -257,15 +246,15 @@ const DefaultSidebarContent: React.FC<{
257246
</div>
258247
</div>
259248
</div>
260-
</div>
249+
261250

262251
{/* Footer */}
263252
<div className="border-t">
264253
{/* Get free tokens, Go Pro, Settings and Help */}
265254
<div className="p-4 space-y-1">
266255
<button className="flex items-center gap-2 text-sm text-green-400 hover:text-green-300 transition-colors w-full">
267256
<div className="w-2 h-2 bg-green-400 rounded-full"></div>
268-
Get free tokens
257+
<span className="text-sm">Get free tokens</span>
269258
</button>
270259
<button className="flex items-center gap-3 w-full p-2 rounded-lg hover:bg-accent transition-colors">
271260
<CreditCardIcon className="w-4 h-4 text-muted-foreground" />
@@ -287,7 +276,7 @@ const DefaultSidebarContent: React.FC<{
287276
<div className="flex items-center gap-3">
288277
<div className="w-8 h-8 bg-gradient-to-br from-blue-500 to-purple-600 rounded-full flex items-center justify-center flex-shrink-0">
289278
<span className="text-white font-medium text-sm">
290-
{session?.user.user_metadata?.name?.[0] || 'G'}
279+
{session?.user.user_metadata?.name?.[0] || ''}
291280
</span>
292281
</div>
293282
<div className="flex-1 min-w-0">
@@ -303,8 +292,13 @@ const DefaultSidebarContent: React.FC<{
303292
</button>
304293
</div>
305294
</div>
306-
</div>
295+
<PricingModal
296+
isOpen={isPricingModalOpen}
297+
onClose={() => setIsPricingModalOpen(false)}
298+
/>
299+
</div>
307300
);
308301
};
309302

303+
310304
export default Sidebar;

components/ui/pricing-card.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ interface PricingCardProps {
1010
highlight?: boolean;
1111
highlightLabel?: string;
1212
buttonVariant?: "default" | "outline";
13+
buttonText?: string;
14+
badge?: string;
1315
}
1416

1517
export function PricingCard({
@@ -19,6 +21,8 @@ export function PricingCard({
1921
features,
2022
highlight = false,
2123
buttonVariant = "outline",
24+
buttonText = "Get Started",
25+
badge,
2226
}: PricingCardProps) {
2327
return (
2428
<div
@@ -29,13 +33,20 @@ export function PricingCard({
2933
<div className={highlight ? "grid gap-6 sm:grid-cols-2" : ""}>
3034
<div className="space-y-4">
3135
<div>
32-
<h2 className="font-medium">{title}</h2>
36+
<div className="flex justify-between">
37+
<h2 className="font-medium">{title}</h2>
38+
{badge && (
39+
<div className="text-sm font-bold bg-primary text-primary-foreground rounded-full px-3 py-1">
40+
{badge}
41+
</div>
42+
)}
43+
</div>
3344
<span className="my-3 block text-2xl font-semibold">{price}</span>
3445
<p className="text-muted-foreground text-sm">{description}</p>
3546
</div>
3647

3748
<Button asChild className="w-full" variant={buttonVariant}>
38-
<Link href="">Get Started</Link>
49+
<Link href="">{buttonText}</Link>
3950
</Button>
4051
</div>
4152
</div>

components/ui/spinner.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function Spinner() {
2+
return (
3+
<svg
4+
className="animate-spin h-4 w-4 text-white-800"
5+
xmlns="http://www.w3.org/2000/svg"
6+
fill="none"
7+
viewBox="0 0 24 24"
8+
>
9+
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
10+
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
11+
</svg>
12+
);
13+
}
14+
15+
export default Spinner;

0 commit comments

Comments
 (0)