shipd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +1366 -0
  5. package/docs-template/README.md +255 -0
  6. package/docs-template/[slug]/[subslug]/page.tsx +1242 -0
  7. package/docs-template/[slug]/page.tsx +422 -0
  8. package/docs-template/api/page.tsx +47 -0
  9. package/docs-template/components/docs/docs-category-page.tsx +162 -0
  10. package/docs-template/components/docs/docs-code-card.tsx +135 -0
  11. package/docs-template/components/docs/docs-header.tsx +69 -0
  12. package/docs-template/components/docs/docs-nav.ts +95 -0
  13. package/docs-template/components/docs/docs-sidebar.tsx +112 -0
  14. package/docs-template/components/docs/docs-toc.tsx +38 -0
  15. package/docs-template/components/ui/badge.tsx +47 -0
  16. package/docs-template/components/ui/button.tsx +60 -0
  17. package/docs-template/components/ui/card.tsx +93 -0
  18. package/docs-template/components/ui/sheet.tsx +140 -0
  19. package/docs-template/documentation/page.tsx +80 -0
  20. package/docs-template/layout.tsx +27 -0
  21. package/docs-template/lib/utils.ts +7 -0
  22. package/docs-template/page.tsx +360 -0
  23. package/package.json +66 -0
  24. package/template/.env.example +45 -0
  25. package/template/README.md +239 -0
  26. package/template/app/api/auth/[...all]/route.ts +4 -0
  27. package/template/app/api/chat/route.ts +16 -0
  28. package/template/app/api/subscription/route.ts +25 -0
  29. package/template/app/api/upload-image/route.ts +64 -0
  30. package/template/app/blog/[slug]/page.tsx +314 -0
  31. package/template/app/blog/page.tsx +107 -0
  32. package/template/app/dashboard/_components/chart-interactive.tsx +289 -0
  33. package/template/app/dashboard/_components/chatbot.tsx +39 -0
  34. package/template/app/dashboard/_components/mode-toggle.tsx +46 -0
  35. package/template/app/dashboard/_components/navbar.tsx +84 -0
  36. package/template/app/dashboard/_components/section-cards.tsx +102 -0
  37. package/template/app/dashboard/_components/sidebar.tsx +90 -0
  38. package/template/app/dashboard/_components/subscribe-button.tsx +49 -0
  39. package/template/app/dashboard/billing/page.tsx +277 -0
  40. package/template/app/dashboard/chat/page.tsx +73 -0
  41. package/template/app/dashboard/cli/page.tsx +260 -0
  42. package/template/app/dashboard/layout.tsx +24 -0
  43. package/template/app/dashboard/page.tsx +216 -0
  44. package/template/app/dashboard/payment/_components/manage-subscription.tsx +22 -0
  45. package/template/app/dashboard/payment/page.tsx +126 -0
  46. package/template/app/dashboard/settings/page.tsx +613 -0
  47. package/template/app/dashboard/upload/page.tsx +324 -0
  48. package/template/app/error.tsx +78 -0
  49. package/template/app/favicon.ico +0 -0
  50. package/template/app/globals.css +126 -0
  51. package/template/app/layout.tsx +135 -0
  52. package/template/app/not-found.tsx +45 -0
  53. package/template/app/page.tsx +28 -0
  54. package/template/app/pricing/_component/pricing-table.tsx +276 -0
  55. package/template/app/pricing/page.tsx +23 -0
  56. package/template/app/privacy-policy/page.tsx +280 -0
  57. package/template/app/robots.txt +12 -0
  58. package/template/app/sign-in/page.tsx +228 -0
  59. package/template/app/sign-up/page.tsx +243 -0
  60. package/template/app/sitemap.ts +62 -0
  61. package/template/app/success/page.tsx +123 -0
  62. package/template/app/terms-of-service/page.tsx +212 -0
  63. package/template/auth-schema.ts +47 -0
  64. package/template/components/homepage/cli-workflow-section.tsx +138 -0
  65. package/template/components/homepage/features-section.tsx +150 -0
  66. package/template/components/homepage/footer.tsx +53 -0
  67. package/template/components/homepage/hero-section.tsx +112 -0
  68. package/template/components/homepage/integrations.tsx +124 -0
  69. package/template/components/homepage/navigation.tsx +116 -0
  70. package/template/components/homepage/news-section.tsx +82 -0
  71. package/template/components/homepage/testimonials-section.tsx +34 -0
  72. package/template/components/logos/BetterAuth.tsx +21 -0
  73. package/template/components/logos/NeonPostgres.tsx +41 -0
  74. package/template/components/logos/Nextjs.tsx +72 -0
  75. package/template/components/logos/Polar.tsx +7 -0
  76. package/template/components/logos/TailwindCSS.tsx +27 -0
  77. package/template/components/logos/index.ts +6 -0
  78. package/template/components/logos/shadcnui.tsx +8 -0
  79. package/template/components/provider.tsx +8 -0
  80. package/template/components/ui/avatar.tsx +53 -0
  81. package/template/components/ui/badge.tsx +46 -0
  82. package/template/components/ui/button.tsx +59 -0
  83. package/template/components/ui/card.tsx +92 -0
  84. package/template/components/ui/chart.tsx +353 -0
  85. package/template/components/ui/checkbox.tsx +32 -0
  86. package/template/components/ui/dialog.tsx +135 -0
  87. package/template/components/ui/dropdown-menu.tsx +257 -0
  88. package/template/components/ui/form.tsx +167 -0
  89. package/template/components/ui/input.tsx +21 -0
  90. package/template/components/ui/label.tsx +24 -0
  91. package/template/components/ui/progress.tsx +31 -0
  92. package/template/components/ui/resizable.tsx +56 -0
  93. package/template/components/ui/select.tsx +185 -0
  94. package/template/components/ui/separator.tsx +28 -0
  95. package/template/components/ui/sheet.tsx +139 -0
  96. package/template/components/ui/skeleton.tsx +13 -0
  97. package/template/components/ui/sonner.tsx +25 -0
  98. package/template/components/ui/switch.tsx +31 -0
  99. package/template/components/ui/tabs.tsx +66 -0
  100. package/template/components/ui/textarea.tsx +18 -0
  101. package/template/components/ui/toggle-group.tsx +73 -0
  102. package/template/components/ui/toggle.tsx +47 -0
  103. package/template/components/ui/tooltip.tsx +61 -0
  104. package/template/components/user-profile.tsx +139 -0
  105. package/template/components.json +21 -0
  106. package/template/db/drizzle.ts +14 -0
  107. package/template/db/migrations/0000_worried_rawhide_kid.sql +77 -0
  108. package/template/db/migrations/meta/0000_snapshot.json +494 -0
  109. package/template/db/migrations/meta/_journal.json +13 -0
  110. package/template/db/schema.ts +85 -0
  111. package/template/drizzle.config.ts +13 -0
  112. package/template/emails/components/layout.tsx +181 -0
  113. package/template/emails/password-reset.tsx +67 -0
  114. package/template/emails/payment-failed.tsx +167 -0
  115. package/template/emails/subscription-confirmation.tsx +129 -0
  116. package/template/emails/welcome.tsx +100 -0
  117. package/template/eslint.config.mjs +16 -0
  118. package/template/hooks/use-mobile.ts +21 -0
  119. package/template/lib/auth-client.ts +8 -0
  120. package/template/lib/auth.ts +276 -0
  121. package/template/lib/email.ts +118 -0
  122. package/template/lib/polar-products.ts +49 -0
  123. package/template/lib/subscription.ts +148 -0
  124. package/template/lib/upload-image.ts +28 -0
  125. package/template/lib/utils.ts +6 -0
  126. package/template/middleware.ts +30 -0
  127. package/template/next-env.d.ts +5 -0
  128. package/template/next.config.ts +27 -0
  129. package/template/package.json +99 -0
  130. package/template/postcss.config.mjs +5 -0
  131. package/template/public/add.png +0 -0
  132. package/template/public/favicon.svg +4 -0
  133. package/template/public/file.svg +1 -0
  134. package/template/public/globe.svg +1 -0
  135. package/template/public/iphone.png +0 -0
  136. package/template/public/logo.png +0 -0
  137. package/template/public/next.svg +1 -0
  138. package/template/public/polar-sh.svg +1 -0
  139. package/template/public/shadcn-ui.svg +1 -0
  140. package/template/public/site.webmanifest +21 -0
  141. package/template/public/vercel.svg +1 -0
  142. package/template/public/window.svg +1 -0
  143. package/template/tailwind.config.ts +89 -0
  144. package/template/template.config.json +138 -0
  145. package/template/tsconfig.json +27 -0
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import { authClient } from "@/lib/auth-client";
5
+ import { Zap } from "lucide-react";
6
+ import { useState } from "react";
7
+ import { toast } from "sonner";
8
+
9
+ interface SubscribeButtonProps {
10
+ productId?: string;
11
+ slug?: string;
12
+ }
13
+
14
+ export function SubscribeButton({
15
+ productId = process.env.NEXT_PUBLIC_STARTER_TIER!,
16
+ slug = process.env.NEXT_PUBLIC_STARTER_SLUG!
17
+ }: SubscribeButtonProps = {}) {
18
+ const [isLoading, setIsLoading] = useState(false);
19
+
20
+ const handleSubscribe = async () => {
21
+ setIsLoading(true);
22
+ try {
23
+ console.log("Starting checkout with:", { productId, slug });
24
+
25
+ await authClient.checkout({
26
+ products: [productId],
27
+ slug: slug,
28
+ });
29
+
30
+ // If we reach here, checkout was initiated
31
+ console.log("Checkout initiated successfully");
32
+ } catch (error) {
33
+ console.error("Checkout error:", error);
34
+ toast.error("Failed to start checkout. Please try again.");
35
+ setIsLoading(false);
36
+ }
37
+ };
38
+
39
+ return (
40
+ <Button
41
+ onClick={handleSubscribe}
42
+ disabled={isLoading}
43
+ className="bg-[#ff5722] hover:bg-[#d84315] text-white w-full"
44
+ >
45
+ <Zap className="w-4 h-4 mr-2" />
46
+ {isLoading ? "Loading..." : "Subscribe Now"}
47
+ </Button>
48
+ );
49
+ }
@@ -0,0 +1,277 @@
1
+ import { auth } from "@/lib/auth";
2
+ import { headers } from "next/headers";
3
+ import { redirect } from "next/navigation";
4
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Badge } from "@/components/ui/badge";
7
+ import { CreditCard, Calendar, AlertCircle, CheckCircle2, ExternalLink } from "lucide-react";
8
+ import { getSubscriptionDetails } from "@/lib/subscription";
9
+ import Link from "next/link";
10
+
11
+ export default async function BillingPage() {
12
+ const session = await auth.api.getSession({
13
+ headers: await headers(),
14
+ });
15
+
16
+ if (!session?.session?.userId) {
17
+ redirect("/sign-in");
18
+ }
19
+
20
+ const subscription = await getSubscriptionDetails();
21
+ const sub = subscription.subscription;
22
+
23
+ return (
24
+ <section className="flex flex-col items-start justify-start p-6 w-full max-w-5xl mx-auto">
25
+ {/* Header */}
26
+ <div className="w-full mb-8">
27
+ <h1 className="text-3xl font-bold tracking-tight text-white">Billing & Subscription</h1>
28
+ <p className="text-gray-400 mt-2">
29
+ Manage your subscription, payment methods, and billing history
30
+ </p>
31
+ </div>
32
+
33
+ {/* No Subscription State */}
34
+ {!subscription.hasActiveSubscription ? (
35
+ <div className="w-full">
36
+ <Card className="bg-[#1a1a1a] border-[#2a2a2a]">
37
+ <CardContent className="p-12 text-center">
38
+ <div className="max-w-md mx-auto">
39
+ <div className="w-16 h-16 bg-[#ff5722]/10 rounded-full flex items-center justify-center mx-auto mb-4">
40
+ <CreditCard className="w-8 h-8 text-[#ff5722]" />
41
+ </div>
42
+ <h3 className="text-2xl font-semibold text-white mb-2">
43
+ No Active Subscription
44
+ </h3>
45
+ <p className="text-gray-400 mb-6">
46
+ Subscribe to SaaS Scaffold to access the CLI and start building your SaaS application.
47
+ </p>
48
+ <div className="flex flex-col sm:flex-row gap-3 justify-center">
49
+ <Link href="/pricing">
50
+ <Button className="bg-[#ff5722] hover:bg-[#d84315] text-white w-full sm:w-auto">
51
+ View Pricing Plans
52
+ </Button>
53
+ </Link>
54
+ <Link href="/docs">
55
+ <Button variant="outline" className="border-[#2a2a2a] hover:bg-[#0a0a0a] w-full sm:w-auto">
56
+ Learn More
57
+ </Button>
58
+ </Link>
59
+ </div>
60
+ </div>
61
+ </CardContent>
62
+ </Card>
63
+ </div>
64
+ ) : (
65
+ <div className="w-full space-y-6">
66
+ {/* Current Plan Card */}
67
+ <Card className="bg-gradient-to-br from-[#1a1a1a] to-[#0a0a0a] border-[#2a2a2a]">
68
+ <CardHeader>
69
+ <div className="flex items-center justify-between">
70
+ <div>
71
+ <CardTitle className="text-white">Current Plan</CardTitle>
72
+ <CardDescription>Your active subscription details</CardDescription>
73
+ </div>
74
+ <Badge className="bg-green-500/20 text-green-400 border-green-500/30">
75
+ <CheckCircle2 className="w-3 h-3 mr-1" />
76
+ Active
77
+ </Badge>
78
+ </div>
79
+ </CardHeader>
80
+ <CardContent>
81
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
82
+ <div>
83
+ <p className="text-sm text-gray-400 mb-1">Plan</p>
84
+ <p className="text-2xl font-bold text-white">
85
+ {sub?.productId || 'Premium'}
86
+ </p>
87
+ </div>
88
+ <div>
89
+ <p className="text-sm text-gray-400 mb-1">Price</p>
90
+ <p className="text-2xl font-bold text-white">
91
+ ${(sub?.amount || 0) / 100}
92
+ <span className="text-base font-normal text-gray-400">
93
+ /{sub?.recurringInterval || 'month'}
94
+ </span>
95
+ </p>
96
+ </div>
97
+ <div>
98
+ <p className="text-sm text-gray-400 mb-1">Status</p>
99
+ <p className="text-2xl font-bold text-white capitalize">
100
+ {sub?.status || 'Active'}
101
+ </p>
102
+ </div>
103
+ </div>
104
+
105
+ {sub?.cancelAtPeriodEnd && (
106
+ <div className="mt-6 p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg flex items-start gap-3">
107
+ <AlertCircle className="w-5 h-5 text-yellow-400 flex-shrink-0 mt-0.5" />
108
+ <div>
109
+ <p className="text-sm font-semibold text-yellow-400 mb-1">
110
+ Subscription Ending
111
+ </p>
112
+ <p className="text-sm text-gray-400">
113
+ Your subscription will end on{' '}
114
+ <span className="text-white font-medium">
115
+ {sub.currentPeriodEnd && new Date(sub.currentPeriodEnd).toLocaleDateString('en-US', {
116
+ month: 'long',
117
+ day: 'numeric',
118
+ year: 'numeric'
119
+ })}
120
+ </span>
121
+ . You can reactivate it anytime before then.
122
+ </p>
123
+ </div>
124
+ </div>
125
+ )}
126
+ </CardContent>
127
+ </Card>
128
+
129
+ {/* Billing Details Card */}
130
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a]">
131
+ <CardHeader>
132
+ <CardTitle className="text-white flex items-center">
133
+ <Calendar className="w-5 h-5 mr-2 text-[#ff5722]" />
134
+ Billing Cycle
135
+ </CardTitle>
136
+ <CardDescription>Your current billing period and renewal date</CardDescription>
137
+ </CardHeader>
138
+ <CardContent>
139
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
140
+ <div>
141
+ <p className="text-sm text-gray-400 mb-2">Current Period</p>
142
+ <div className="flex items-center gap-2">
143
+ <p className="text-white">
144
+ {sub?.currentPeriodStart && new Date(sub.currentPeriodStart).toLocaleDateString('en-US', {
145
+ month: 'short',
146
+ day: 'numeric',
147
+ year: 'numeric'
148
+ })}
149
+ </p>
150
+ <span className="text-gray-500">→</span>
151
+ <p className="text-white">
152
+ {sub?.currentPeriodEnd && new Date(sub.currentPeriodEnd).toLocaleDateString('en-US', {
153
+ month: 'short',
154
+ day: 'numeric',
155
+ year: 'numeric'
156
+ })}
157
+ </p>
158
+ </div>
159
+ </div>
160
+ <div>
161
+ <p className="text-sm text-gray-400 mb-2">Next Billing Date</p>
162
+ <p className="text-white font-semibold">
163
+ {sub?.currentPeriodEnd && !sub?.cancelAtPeriodEnd &&
164
+ new Date(sub.currentPeriodEnd).toLocaleDateString('en-US', {
165
+ month: 'long',
166
+ day: 'numeric',
167
+ year: 'numeric'
168
+ })
169
+ }
170
+ {sub?.cancelAtPeriodEnd && (
171
+ <span className="text-yellow-400">Subscription Ending</span>
172
+ )}
173
+ </p>
174
+ </div>
175
+ </div>
176
+ </CardContent>
177
+ </Card>
178
+
179
+ {/* Manage Subscription Card */}
180
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a]">
181
+ <CardHeader>
182
+ <CardTitle className="text-white">Manage Subscription</CardTitle>
183
+ <CardDescription>Update your plan, payment method, or cancel your subscription</CardDescription>
184
+ </CardHeader>
185
+ <CardContent className="space-y-4">
186
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
187
+ {/* Polar Customer Portal */}
188
+ <form action="/api/subscription/portal" method="POST" className="w-full">
189
+ <Button
190
+ type="submit"
191
+ variant="outline"
192
+ className="w-full border-[#2a2a2a] hover:bg-[#1a1a1a] justify-between"
193
+ >
194
+ <span className="flex items-center">
195
+ <CreditCard className="w-4 h-4 mr-2" />
196
+ Manage Payment
197
+ </span>
198
+ <ExternalLink className="w-4 h-4" />
199
+ </Button>
200
+ </form>
201
+
202
+ {/* Change Plan */}
203
+ <Link href="/pricing" className="w-full">
204
+ <Button
205
+ variant="outline"
206
+ className="w-full border-[#2a2a2a] hover:bg-[#1a1a1a] justify-between"
207
+ >
208
+ <span>Change Plan</span>
209
+ <ExternalLink className="w-4 h-4" />
210
+ </Button>
211
+ </Link>
212
+ </div>
213
+
214
+ <div className="pt-4 border-t border-[#2a2a2a]">
215
+ <p className="text-sm text-gray-400 mb-3">
216
+ Need to cancel? You can cancel your subscription anytime. You&apos;ll retain access until the end of your billing period.
217
+ </p>
218
+ {!sub?.cancelAtPeriodEnd ? (
219
+ <form action="/api/subscription/cancel" method="POST">
220
+ <Button
221
+ type="submit"
222
+ variant="outline"
223
+ className="border-red-500/30 text-red-400 hover:bg-red-500/10"
224
+ >
225
+ Cancel Subscription
226
+ </Button>
227
+ </form>
228
+ ) : (
229
+ <form action="/api/subscription/reactivate" method="POST">
230
+ <Button
231
+ type="submit"
232
+ className="bg-[#ff5722] hover:bg-[#d84315]"
233
+ >
234
+ Reactivate Subscription
235
+ </Button>
236
+ </form>
237
+ )}
238
+ </div>
239
+ </CardContent>
240
+ </Card>
241
+
242
+ {/* Billing Information */}
243
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a]">
244
+ <CardHeader>
245
+ <CardTitle className="text-white">Billing Information</CardTitle>
246
+ <CardDescription>Your billing details and invoice history</CardDescription>
247
+ </CardHeader>
248
+ <CardContent className="space-y-4">
249
+ <div>
250
+ <p className="text-sm text-gray-400 mb-2">Payment Method</p>
251
+ <div className="flex items-center gap-2">
252
+ <CreditCard className="w-4 h-4 text-gray-400" />
253
+ <p className="text-white">Managed via Polar.sh</p>
254
+ </div>
255
+ </div>
256
+ <div>
257
+ <p className="text-sm text-gray-400 mb-2">Invoices</p>
258
+ <p className="text-white text-sm">
259
+ Access your invoice history through the{' '}
260
+ <form action="/api/subscription/portal" method="POST" className="inline">
261
+ <Button
262
+ type="submit"
263
+ variant="link"
264
+ className="text-[#ff5722] hover:text-[#d84315] p-0 h-auto"
265
+ >
266
+ customer portal
267
+ </Button>
268
+ </form>
269
+ </p>
270
+ </div>
271
+ </CardContent>
272
+ </Card>
273
+ </div>
274
+ )}
275
+ </section>
276
+ );
277
+ }
@@ -0,0 +1,73 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import { Input } from "@/components/ui/input";
5
+ import { cn } from "@/lib/utils";
6
+ import { useChat } from "@ai-sdk/react";
7
+ import Markdown from "react-markdown";
8
+
9
+ export default function Chat() {
10
+ const { messages, input, handleInputChange, handleSubmit } = useChat({
11
+ maxSteps: 10,
12
+ });
13
+
14
+ return (
15
+ <div className="flex flex-col w-full py-24 justify-center items-center">
16
+ <div className="w-full max-w-xl space-y-4 mb-20">
17
+ {messages.map((message, i) => (
18
+ <div
19
+ key={message.id}
20
+ className={cn(
21
+ "flex",
22
+ message.role === "user" ? "justify-end" : "justify-start",
23
+ )}
24
+ >
25
+ <div
26
+ className={cn(
27
+ "max-w-[65%] px-3 py-1.5 text-sm shadow-sm",
28
+ message.role === "user"
29
+ ? "bg-[#0B93F6] text-white rounded-2xl rounded-br-sm"
30
+ : "bg-[#E9E9EB] text-black rounded-2xl rounded-bl-sm",
31
+ )}
32
+ >
33
+ {message.parts.map((part) => {
34
+ switch (part.type) {
35
+ case "text":
36
+ return (
37
+ <div
38
+ key={`${message.id}-${i}`}
39
+ className="prose-sm prose-p:my-0.5 prose-li:my-0.5 prose-ul:my-1 prose-ol:my-1"
40
+ >
41
+ <Markdown>{part.text}</Markdown>
42
+ </div>
43
+ );
44
+ default:
45
+ return null;
46
+ }
47
+ })}
48
+ </div>
49
+ </div>
50
+ ))}
51
+ </div>
52
+
53
+ <form
54
+ className="flex gap-2 justify-center w-full items-center fixed bottom-0"
55
+ onSubmit={handleSubmit}
56
+ >
57
+ <div className="flex flex-col gap-2 justify-center items-start mb-8 max-w-xl w-full border p-2 rounded-lg bg-white ">
58
+ <Input
59
+ className="w-full border-0 shadow-none !ring-transparent "
60
+ value={input}
61
+ placeholder="Say something..."
62
+ onChange={handleInputChange}
63
+ />
64
+ <div className="flex justify-end gap-3 items-center w-full">
65
+ <Button size="sm" className="text-xs">
66
+ Send
67
+ </Button>
68
+ </div>
69
+ </div>
70
+ </form>
71
+ </div>
72
+ );
73
+ }
@@ -0,0 +1,260 @@
1
+ import { auth } from "@/lib/auth";
2
+ import { headers } from "next/headers";
3
+ import { redirect } from "next/navigation";
4
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Badge } from "@/components/ui/badge";
7
+ import { Terminal, Copy, CheckCircle2, Download, BookOpen, Github } from "lucide-react";
8
+ import { getSubscriptionDetails } from "@/lib/subscription";
9
+ import Link from "next/link";
10
+
11
+ export default async function CLIPage() {
12
+ const session = await auth.api.getSession({
13
+ headers: await headers(),
14
+ });
15
+
16
+ if (!session?.session?.userId) {
17
+ redirect("/sign-in");
18
+ }
19
+
20
+ const subscription = await getSubscriptionDetails();
21
+ const user = session.user;
22
+
23
+ return (
24
+ <section className="flex flex-col items-start justify-start p-6 w-full max-w-7xl mx-auto">
25
+ {/* Header */}
26
+ <div className="w-full mb-8">
27
+ <h1 className="text-3xl font-bold tracking-tight text-white">CLI Access</h1>
28
+ <p className="text-gray-400 mt-2">
29
+ Everything you need to get started with the SaaS Scaffold CLI
30
+ </p>
31
+ </div>
32
+
33
+ {/* Subscription Check */}
34
+ {!subscription.hasActiveSubscription && (
35
+ <div className="w-full mb-6">
36
+ <Card className="bg-red-500/10 border-red-500/30">
37
+ <CardContent className="p-6">
38
+ <div className="flex items-center gap-4">
39
+ <div className="flex-1">
40
+ <h3 className="text-lg font-semibold text-red-400 mb-1">
41
+ Active Subscription Required
42
+ </h3>
43
+ <p className="text-gray-400 text-sm">
44
+ You need an active subscription to use the SaaS Scaffold CLI.
45
+ </p>
46
+ </div>
47
+ <Link href="/pricing">
48
+ <Button className="bg-[#ff5722] hover:bg-[#d84315]">
49
+ View Pricing
50
+ </Button>
51
+ </Link>
52
+ </div>
53
+ </CardContent>
54
+ </Card>
55
+ </div>
56
+ )}
57
+
58
+ {/* Installation */}
59
+ <div className="w-full mb-6">
60
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a]">
61
+ <CardHeader>
62
+ <CardTitle className="text-white flex items-center">
63
+ <Download className="w-5 h-5 mr-2 text-[#ff5722]" />
64
+ Installation
65
+ </CardTitle>
66
+ <CardDescription>Install the SaaS Scaffold CLI globally via npm</CardDescription>
67
+ </CardHeader>
68
+ <CardContent className="space-y-4">
69
+ <div>
70
+ <p className="text-sm text-gray-400 mb-2">npm (recommended)</p>
71
+ <div className="bg-black/50 p-4 rounded-lg border border-[#2a2a2a] flex items-center justify-between">
72
+ <code className="text-[#ff5722] font-mono text-sm">
73
+ npx saas-scaffold init my-project
74
+ </code>
75
+ <Button
76
+ variant="ghost"
77
+ size="sm"
78
+ className="text-gray-400 hover:text-white"
79
+ onClick={() => navigator.clipboard.writeText('npx saas-scaffold init my-project')}
80
+ >
81
+ <Copy className="w-4 h-4" />
82
+ </Button>
83
+ </div>
84
+ </div>
85
+ <div className="text-sm text-gray-400">
86
+ <p>No installation required! Use <code className="text-[#ff5722] bg-black/50 px-2 py-1 rounded">npx</code> to run the latest version directly.</p>
87
+ </div>
88
+ </CardContent>
89
+ </Card>
90
+ </div>
91
+
92
+ {/* Authentication */}
93
+ <div className="w-full mb-6">
94
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a]">
95
+ <CardHeader>
96
+ <CardTitle className="text-white flex items-center">
97
+ <Terminal className="w-5 h-5 mr-2 text-[#ff5722]" />
98
+ Authentication
99
+ </CardTitle>
100
+ <CardDescription>Authenticate your CLI to access premium features</CardDescription>
101
+ </CardHeader>
102
+ <CardContent className="space-y-6">
103
+ {/* Step 1 */}
104
+ <div>
105
+ <div className="flex items-center gap-2 mb-2">
106
+ <div className="w-6 h-6 rounded-full bg-[#ff5722] flex items-center justify-center text-white text-sm font-semibold">
107
+ 1
108
+ </div>
109
+ <h4 className="text-white font-semibold">Run the login command</h4>
110
+ </div>
111
+ <div className="ml-8 space-y-2">
112
+ <p className="text-sm text-gray-400">Execute the following command in your terminal:</p>
113
+ <div className="bg-black/50 p-4 rounded-lg border border-[#2a2a2a] flex items-center justify-between">
114
+ <code className="text-[#ff5722] font-mono text-sm">
115
+ npx saas-scaffold login
116
+ </code>
117
+ <Button
118
+ variant="ghost"
119
+ size="sm"
120
+ className="text-gray-400 hover:text-white"
121
+ onClick={() => navigator.clipboard.writeText('npx saas-scaffold login')}
122
+ >
123
+ <Copy className="w-4 h-4" />
124
+ </Button>
125
+ </div>
126
+ </div>
127
+ </div>
128
+
129
+ {/* Step 2 */}
130
+ <div>
131
+ <div className="flex items-center gap-2 mb-2">
132
+ <div className="w-6 h-6 rounded-full bg-[#ff5722] flex items-center justify-center text-white text-sm font-semibold">
133
+ 2
134
+ </div>
135
+ <h4 className="text-white font-semibold">Complete browser authentication</h4>
136
+ </div>
137
+ <div className="ml-8 space-y-2">
138
+ <p className="text-sm text-gray-400">
139
+ Your browser will open automatically. Sign in with your account (you&apos;re already signed in as <span className="text-white">{user?.email}</span>).
140
+ </p>
141
+ </div>
142
+ </div>
143
+
144
+ {/* Step 3 */}
145
+ <div>
146
+ <div className="flex items-center gap-2 mb-2">
147
+ <div className="w-6 h-6 rounded-full bg-[#ff5722] flex items-center justify-center text-white text-sm font-semibold">
148
+ 3
149
+ </div>
150
+ <h4 className="text-white font-semibold">Start building</h4>
151
+ </div>
152
+ <div className="ml-8 space-y-2">
153
+ <p className="text-sm text-gray-400">You&apos;re now authenticated! Create your first project:</p>
154
+ <div className="bg-black/50 p-4 rounded-lg border border-[#2a2a2a] flex items-center justify-between">
155
+ <code className="text-[#ff5722] font-mono text-sm">
156
+ npx saas-scaffold init my-saas-app
157
+ </code>
158
+ <Button
159
+ variant="ghost"
160
+ size="sm"
161
+ className="text-gray-400 hover:text-white"
162
+ onClick={() => navigator.clipboard.writeText('npx saas-scaffold init my-saas-app')}
163
+ >
164
+ <Copy className="w-4 h-4" />
165
+ </Button>
166
+ </div>
167
+ </div>
168
+ </div>
169
+
170
+ {subscription.hasActiveSubscription && (
171
+ <div className="pt-4 border-t border-[#2a2a2a]">
172
+ <div className="flex items-center gap-2 text-green-400">
173
+ <CheckCircle2 className="w-5 h-5" />
174
+ <p className="text-sm font-medium">Active subscription detected - CLI access enabled</p>
175
+ </div>
176
+ </div>
177
+ )}
178
+ </CardContent>
179
+ </Card>
180
+ </div>
181
+
182
+ {/* Available Commands */}
183
+ <div className="w-full mb-6">
184
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a]">
185
+ <CardHeader>
186
+ <CardTitle className="text-white">Available Commands</CardTitle>
187
+ <CardDescription>All commands available in the SaaS Scaffold CLI</CardDescription>
188
+ </CardHeader>
189
+ <CardContent className="space-y-4">
190
+ <div className="grid gap-4">
191
+ {/* Init Command */}
192
+ <div className="p-4 bg-black/30 rounded-lg border border-[#2a2a2a]">
193
+ <div className="flex items-start justify-between mb-2">
194
+ <code className="text-[#ff5722] font-mono">saas-scaffold init [project-name]</code>
195
+ <Badge variant="outline" className="border-green-500/30 text-green-400">
196
+ Primary
197
+ </Badge>
198
+ </div>
199
+ <p className="text-sm text-gray-400">
200
+ Generate a new SaaS project with authentication, billing, and premium features pre-configured.
201
+ </p>
202
+ <div className="mt-2 text-xs text-gray-500">
203
+ Options: <code>--mock</code> (skip authentication for testing)
204
+ </div>
205
+ </div>
206
+
207
+ {/* Login Command */}
208
+ <div className="p-4 bg-black/30 rounded-lg border border-[#2a2a2a]">
209
+ <code className="text-[#ff5722] font-mono mb-2 block">saas-scaffold login</code>
210
+ <p className="text-sm text-gray-400">
211
+ Authenticate your CLI with your SaaS Scaffold account. Opens browser for OAuth flow.
212
+ </p>
213
+ </div>
214
+
215
+ {/* Logout Command */}
216
+ <div className="p-4 bg-black/30 rounded-lg border border-[#2a2a2a]">
217
+ <code className="text-[#ff5722] font-mono mb-2 block">saas-scaffold logout</code>
218
+ <p className="text-sm text-gray-400">
219
+ Remove authentication token and log out of the CLI.
220
+ </p>
221
+ </div>
222
+ </div>
223
+ </CardContent>
224
+ </Card>
225
+ </div>
226
+
227
+ {/* Resources */}
228
+ <div className="w-full">
229
+ <h2 className="text-xl font-semibold text-white mb-4">Resources</h2>
230
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
231
+ {/* Documentation */}
232
+ <Link href="/docs">
233
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a] hover:border-[#ff5722]/50 transition-colors cursor-pointer h-full">
234
+ <CardHeader>
235
+ <BookOpen className="w-8 h-8 text-[#ff5722] mb-2" />
236
+ <CardTitle className="text-white">Documentation</CardTitle>
237
+ <CardDescription>
238
+ Complete guides, API reference, and tutorials
239
+ </CardDescription>
240
+ </CardHeader>
241
+ </Card>
242
+ </Link>
243
+
244
+ {/* GitHub */}
245
+ <a href="https://github.com/saas-scaffold/cli" target="_blank" rel="noopener noreferrer">
246
+ <Card className="bg-[#0a0a0a] border-[#2a2a2a] hover:border-[#ff5722]/50 transition-colors cursor-pointer h-full">
247
+ <CardHeader>
248
+ <Github className="w-8 h-8 text-[#ff5722] mb-2" />
249
+ <CardTitle className="text-white">GitHub Repository</CardTitle>
250
+ <CardDescription>
251
+ Source code, issues, and contributions
252
+ </CardDescription>
253
+ </CardHeader>
254
+ </Card>
255
+ </a>
256
+ </div>
257
+ </div>
258
+ </section>
259
+ );
260
+ }