@getjack/jack 0.1.28 → 0.1.30
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.
- package/package.json +1 -1
- package/src/commands/cd.ts +163 -0
- package/src/commands/clone.ts +112 -68
- package/src/commands/domain.ts +506 -0
- package/src/commands/domains.ts +215 -0
- package/src/commands/down.ts +18 -12
- package/src/commands/hack.ts +185 -8
- package/src/commands/init.ts +52 -1
- package/src/commands/link.ts +25 -43
- package/src/commands/logs.ts +2 -2
- package/src/commands/mcp.ts +74 -3
- package/src/commands/new.ts +48 -54
- package/src/commands/projects.ts +53 -10
- package/src/commands/secrets.ts +5 -1
- package/src/commands/services.ts +16 -4
- package/src/commands/shell-init.ts +43 -0
- package/src/commands/ship.ts +2 -11
- package/src/commands/skills.ts +335 -0
- package/src/commands/update.ts +31 -0
- package/src/commands/upgrade.ts +14 -0
- package/src/index.ts +116 -24
- package/src/lib/agent-integration.ts +1 -2
- package/src/lib/agents.ts +2 -2
- package/src/lib/auth/login-flow.ts +1 -1
- package/src/lib/clone-core.ts +252 -0
- package/src/lib/config.ts +22 -0
- package/src/lib/control-plane.ts +31 -5
- package/src/lib/fuzzy.ts +93 -0
- package/src/lib/managed-deploy.ts +4 -1
- package/src/lib/managed-down.ts +20 -5
- package/src/lib/output.ts +90 -9
- package/src/lib/picker.ts +406 -0
- package/src/lib/project-detection.ts +5 -2
- package/src/lib/project-list.ts +66 -5
- package/src/lib/project-operations.ts +68 -6
- package/src/lib/prompts.ts +1 -1
- package/src/lib/services/db-execute.ts +8 -1
- package/src/lib/services/db-list.ts +4 -1
- package/src/lib/services/domain-operations.ts +379 -0
- package/src/lib/services/storage-config.ts +1 -5
- package/src/lib/services/storage-delete.ts +1 -1
- package/src/lib/services/storage-info.ts +2 -4
- package/src/lib/services/vectorize-config.ts +1 -5
- package/src/lib/services/vectorize-create.ts +3 -1
- package/src/lib/shell-integration.ts +202 -0
- package/src/lib/telemetry-config.ts +50 -4
- package/src/lib/telemetry.ts +71 -2
- package/src/lib/version-check.ts +1 -3
- package/src/lib/wrangler-config.test.ts +2 -2
- package/src/lib/wrangler-config.ts +1 -1
- package/src/lib/zip-packager.ts +1 -3
- package/src/mcp/tools/index.ts +261 -7
- package/src/templates/index.ts +10 -1
- package/templates/ai-chat/.jack.json +1 -5
- package/templates/ai-chat/public/chat.js +130 -130
- package/templates/ai-chat/src/index.ts +9 -13
- package/templates/ai-chat/src/jack-ai.ts +6 -2
- package/templates/saas/.jack.json +6 -1
- package/templates/saas/src/auth.ts +8 -4
- package/templates/saas/src/client/App.tsx +22 -7
- package/templates/saas/src/client/components/ProtectedRoute.tsx +9 -2
- package/templates/saas/src/client/components/ThemeToggle.tsx +1 -6
- package/templates/saas/src/client/components/ui/accordion.tsx +1 -1
- package/templates/saas/src/client/components/ui/alert-dialog.tsx +2 -2
- package/templates/saas/src/client/components/ui/alert.tsx +2 -2
- package/templates/saas/src/client/components/ui/avatar.tsx +1 -1
- package/templates/saas/src/client/components/ui/badge.tsx +2 -2
- package/templates/saas/src/client/components/ui/breadcrumb.tsx +1 -1
- package/templates/saas/src/client/components/ui/button-group.tsx +2 -2
- package/templates/saas/src/client/components/ui/button.tsx +2 -2
- package/templates/saas/src/client/components/ui/card.tsx +1 -1
- package/templates/saas/src/client/components/ui/carousel.tsx +2 -2
- package/templates/saas/src/client/components/ui/checkbox.tsx +1 -1
- package/templates/saas/src/client/components/ui/command.tsx +2 -2
- package/templates/saas/src/client/components/ui/context-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/dialog.tsx +1 -1
- package/templates/saas/src/client/components/ui/drawer.tsx +1 -1
- package/templates/saas/src/client/components/ui/dropdown-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/empty.tsx +1 -1
- package/templates/saas/src/client/components/ui/field.tsx +2 -2
- package/templates/saas/src/client/components/ui/form.tsx +5 -5
- package/templates/saas/src/client/components/ui/hover-card.tsx +1 -1
- package/templates/saas/src/client/components/ui/input-group.tsx +3 -3
- package/templates/saas/src/client/components/ui/input-otp.tsx +1 -1
- package/templates/saas/src/client/components/ui/input.tsx +1 -1
- package/templates/saas/src/client/components/ui/item.tsx +3 -3
- package/templates/saas/src/client/components/ui/label.tsx +1 -1
- package/templates/saas/src/client/components/ui/menubar.tsx +1 -1
- package/templates/saas/src/client/components/ui/navigation-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/pagination.tsx +2 -2
- package/templates/saas/src/client/components/ui/popover.tsx +1 -1
- package/templates/saas/src/client/components/ui/progress.tsx +1 -1
- package/templates/saas/src/client/components/ui/radio-group.tsx +1 -1
- package/templates/saas/src/client/components/ui/resizable.tsx +1 -1
- package/templates/saas/src/client/components/ui/scroll-area.tsx +1 -1
- package/templates/saas/src/client/components/ui/select.tsx +1 -1
- package/templates/saas/src/client/components/ui/separator.tsx +1 -1
- package/templates/saas/src/client/components/ui/sheet.tsx +1 -1
- package/templates/saas/src/client/components/ui/sidebar.tsx +4 -4
- package/templates/saas/src/client/components/ui/slider.tsx +1 -1
- package/templates/saas/src/client/components/ui/switch.tsx +1 -1
- package/templates/saas/src/client/components/ui/table.tsx +1 -1
- package/templates/saas/src/client/components/ui/tabs.tsx +1 -1
- package/templates/saas/src/client/components/ui/textarea.tsx +1 -1
- package/templates/saas/src/client/components/ui/toggle-group.tsx +3 -3
- package/templates/saas/src/client/components/ui/toggle.tsx +2 -2
- package/templates/saas/src/client/components/ui/tooltip.tsx +1 -1
- package/templates/saas/src/client/hooks/useSubscription.ts +5 -4
- package/templates/saas/src/client/lib/auth-client.ts +1 -1
- package/templates/saas/src/client/lib/plans.ts +1 -6
- package/templates/saas/src/client/lib/utils.ts +1 -1
- package/templates/saas/src/client/main.tsx +1 -1
- package/templates/saas/src/client/pages/DashboardPage.tsx +41 -9
- package/templates/saas/src/client/pages/ForgotPasswordPage.tsx +11 -2
- package/templates/saas/src/client/pages/HomePage.tsx +11 -2
- package/templates/saas/src/client/pages/LoginPage.tsx +11 -2
- package/templates/saas/src/client/pages/PricingPage.tsx +20 -10
- package/templates/saas/src/client/pages/ResetPasswordPage.tsx +14 -11
- package/templates/saas/src/client/pages/SignupPage.tsx +11 -2
- package/templates/saas/src/index.ts +28 -19
- package/templates/saas/vite.config.ts +1 -1
- package/templates/semantic-search/.jack.json +1 -5
- package/templates/semantic-search/src/index.ts +8 -4
- package/templates/semantic-search/src/jack-ai.ts +6 -2
- package/templates/semantic-search/src/jack-vectorize.ts +5 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
1
2
|
import { useMemo } from "react";
|
|
2
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
3
|
|
|
4
|
-
import { cn } from "@/lib/utils";
|
|
5
4
|
import { Label } from "@/components/ui/label";
|
|
6
5
|
import { Separator } from "@/components/ui/separator";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
7
|
|
|
8
8
|
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
|
9
9
|
return (
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import * as React from "react";
|
|
4
3
|
import type * as LabelPrimitive from "@radix-ui/react-label";
|
|
5
4
|
import { Slot } from "@radix-ui/react-slot";
|
|
5
|
+
import * as React from "react";
|
|
6
6
|
import {
|
|
7
7
|
Controller,
|
|
8
|
-
FormProvider,
|
|
9
|
-
useFormContext,
|
|
10
|
-
useFormState,
|
|
11
8
|
type ControllerProps,
|
|
12
9
|
type FieldPath,
|
|
13
10
|
type FieldValues,
|
|
11
|
+
FormProvider,
|
|
12
|
+
useFormContext,
|
|
13
|
+
useFormState,
|
|
14
14
|
} from "react-hook-form";
|
|
15
15
|
|
|
16
|
-
import { cn } from "@/lib/utils";
|
|
17
16
|
import { Label } from "@/components/ui/label";
|
|
17
|
+
import { cn } from "@/lib/utils";
|
|
18
18
|
|
|
19
19
|
const Form = FormProvider;
|
|
20
20
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
4
|
+
import type * as React from "react";
|
|
5
5
|
|
|
6
|
-
import { cn } from "@/lib/utils";
|
|
7
6
|
import { Button } from "@/components/ui/button";
|
|
8
7
|
import { Input } from "@/components/ui/input";
|
|
9
8
|
import { Textarea } from "@/components/ui/textarea";
|
|
9
|
+
import { cn } from "@/lib/utils";
|
|
10
10
|
|
|
11
11
|
function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
12
12
|
return (
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
-
import {
|
|
2
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
3
|
+
import type * as React from "react";
|
|
4
4
|
|
|
5
|
-
import { cn } from "@/lib/utils";
|
|
6
5
|
import { Separator } from "@/components/ui/separator";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
7
|
|
|
8
8
|
function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
9
9
|
return (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
|
|
3
2
|
import { cva } from "class-variance-authority";
|
|
4
3
|
import { ChevronDownIcon } from "lucide-react";
|
|
4
|
+
import type * as React from "react";
|
|
5
5
|
|
|
6
6
|
import { cn } from "@/lib/utils";
|
|
7
7
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
|
2
|
+
import type * as React from "react";
|
|
3
3
|
|
|
4
|
+
import { type Button, buttonVariants } from "@/components/ui/button";
|
|
4
5
|
import { cn } from "@/lib/utils";
|
|
5
|
-
import { buttonVariants, type Button } from "@/components/ui/button";
|
|
6
6
|
|
|
7
7
|
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
|
8
8
|
return (
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import * as React from "react";
|
|
4
3
|
import { Slot } from "@radix-ui/react-slot";
|
|
5
|
-
import {
|
|
4
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
6
5
|
import { PanelLeftIcon } from "lucide-react";
|
|
6
|
+
import * as React from "react";
|
|
7
7
|
|
|
8
|
-
import { useIsMobile } from "@/hooks/use-mobile";
|
|
9
|
-
import { cn } from "@/lib/utils";
|
|
10
8
|
import { Button } from "@/components/ui/button";
|
|
11
9
|
import { Input } from "@/components/ui/input";
|
|
12
10
|
import { Separator } from "@/components/ui/separator";
|
|
@@ -19,6 +17,8 @@ import {
|
|
|
19
17
|
} from "@/components/ui/sheet";
|
|
20
18
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
21
19
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
|
20
|
+
import { useIsMobile } from "@/hooks/use-mobile";
|
|
21
|
+
import { cn } from "@/lib/utils";
|
|
22
22
|
|
|
23
23
|
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
|
24
24
|
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
|
3
|
-
import {
|
|
2
|
+
import type { VariantProps } from "class-variance-authority";
|
|
3
|
+
import * as React from "react";
|
|
4
4
|
|
|
5
|
-
import { cn } from "@/lib/utils";
|
|
6
5
|
import { toggleVariants } from "@/components/ui/toggle";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
7
|
|
|
8
8
|
const ToggleGroupContext = React.createContext<
|
|
9
9
|
VariantProps<typeof toggleVariants> & {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
import * as TogglePrimitive from "@radix-ui/react-toggle";
|
|
3
|
-
import {
|
|
2
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
3
|
+
import type * as React from "react";
|
|
4
4
|
|
|
5
5
|
import { cn } from "@/lib/utils";
|
|
6
6
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
2
|
import { authClient } from "../lib/auth-client";
|
|
3
3
|
|
|
4
4
|
type Subscription = {
|
|
@@ -8,7 +8,7 @@ type Subscription = {
|
|
|
8
8
|
stripeCustomerId?: string;
|
|
9
9
|
stripeSubscriptionId?: string;
|
|
10
10
|
cancelAtPeriodEnd?: boolean;
|
|
11
|
-
cancelAt?: Date | string | null;
|
|
11
|
+
cancelAt?: Date | string | null; // Better Auth uses this
|
|
12
12
|
periodEnd?: Date | string | null;
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -60,11 +60,12 @@ export function useSubscription() {
|
|
|
60
60
|
const isCancelling =
|
|
61
61
|
stripeStatus?.cancelAtPeriodEnd ||
|
|
62
62
|
activeSubscription?.cancelAtPeriodEnd ||
|
|
63
|
-
!!activeSubscription?.cancelAt ||
|
|
63
|
+
!!activeSubscription?.cancelAt || // Better Auth sets cancelAt date when cancelling
|
|
64
64
|
false;
|
|
65
65
|
|
|
66
66
|
// Get period end from either source
|
|
67
|
-
const periodEnd =
|
|
67
|
+
const periodEnd =
|
|
68
|
+
stripeStatus?.periodEnd ||
|
|
68
69
|
(activeSubscription?.periodEnd ? String(activeSubscription.periodEnd) : null);
|
|
69
70
|
|
|
70
71
|
return {
|
|
@@ -20,12 +20,7 @@ export const plans: PlanConfig[] = [
|
|
|
20
20
|
price: "$0",
|
|
21
21
|
priceMonthly: 0,
|
|
22
22
|
description: "Perfect for getting started",
|
|
23
|
-
features: [
|
|
24
|
-
"Up to 100 users",
|
|
25
|
-
"Basic analytics",
|
|
26
|
-
"Community support",
|
|
27
|
-
"1 project",
|
|
28
|
-
],
|
|
23
|
+
features: ["Up to 100 users", "Basic analytics", "Community support", "1 project"],
|
|
29
24
|
},
|
|
30
25
|
{
|
|
31
26
|
id: "pro",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { ThemeProvider } from "next-themes";
|
|
1
2
|
import { StrictMode } from "react";
|
|
2
3
|
import { createRoot } from "react-dom/client";
|
|
3
|
-
import { ThemeProvider } from "next-themes";
|
|
4
4
|
import App from "./App";
|
|
5
5
|
import { Toaster } from "./components/ui/sonner";
|
|
6
6
|
import "./index.css";
|
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
+
import { ThemeToggle } from "../components/ThemeToggle";
|
|
3
|
+
import { Button } from "../components/ui/button";
|
|
4
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../components/ui/card";
|
|
2
5
|
import { useAuth } from "../hooks/useAuth";
|
|
3
6
|
import { useSubscription } from "../hooks/useSubscription";
|
|
4
|
-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../components/ui/card";
|
|
5
|
-
import { Button } from "../components/ui/button";
|
|
6
|
-
import { ThemeToggle } from "../components/ThemeToggle";
|
|
7
7
|
import { getPlanName } from "../lib/plans";
|
|
8
8
|
|
|
9
9
|
interface DashboardPageProps {
|
|
10
|
-
navigate: (
|
|
10
|
+
navigate: (
|
|
11
|
+
route:
|
|
12
|
+
| "/"
|
|
13
|
+
| "/login"
|
|
14
|
+
| "/signup"
|
|
15
|
+
| "/pricing"
|
|
16
|
+
| "/dashboard"
|
|
17
|
+
| "/forgot-password"
|
|
18
|
+
| "/reset-password",
|
|
19
|
+
) => void;
|
|
11
20
|
}
|
|
12
21
|
|
|
13
22
|
export default function DashboardPage({ navigate }: DashboardPageProps) {
|
|
14
23
|
const { user, signOut } = useAuth();
|
|
15
|
-
const {
|
|
24
|
+
const {
|
|
25
|
+
plan,
|
|
26
|
+
isSubscribed,
|
|
27
|
+
isCancelling,
|
|
28
|
+
periodEnd,
|
|
29
|
+
isLoading: isSubscriptionLoading,
|
|
30
|
+
} = useSubscription();
|
|
16
31
|
const [showUpgradeSuccess, setShowUpgradeSuccess] = useState(false);
|
|
17
32
|
|
|
18
33
|
// Check for upgrade success
|
|
@@ -103,19 +118,33 @@ export default function DashboardPage({ navigate }: DashboardPageProps) {
|
|
|
103
118
|
className="absolute top-4 right-4 text-white/80 hover:text-white"
|
|
104
119
|
>
|
|
105
120
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
106
|
-
<path
|
|
121
|
+
<path
|
|
122
|
+
strokeLinecap="round"
|
|
123
|
+
strokeLinejoin="round"
|
|
124
|
+
strokeWidth={2}
|
|
125
|
+
d="M6 18L18 6M6 6l12 12"
|
|
126
|
+
/>
|
|
107
127
|
</svg>
|
|
108
128
|
</button>
|
|
109
129
|
<div className="flex items-start gap-4">
|
|
110
130
|
<div className="flex-shrink-0 w-12 h-12 bg-white/20 rounded-full flex items-center justify-center">
|
|
111
131
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
112
|
-
<path
|
|
132
|
+
<path
|
|
133
|
+
strokeLinecap="round"
|
|
134
|
+
strokeLinejoin="round"
|
|
135
|
+
strokeWidth={2}
|
|
136
|
+
d="M5 13l4 4L19 7"
|
|
137
|
+
/>
|
|
113
138
|
</svg>
|
|
114
139
|
</div>
|
|
115
140
|
<div className="flex-1">
|
|
116
141
|
<h2 className="text-xl font-bold mb-1">You're all set!</h2>
|
|
117
142
|
<p className="text-white/90 mb-4">
|
|
118
|
-
Your upgrade to
|
|
143
|
+
Your upgrade to{" "}
|
|
144
|
+
<span className="font-semibold">
|
|
145
|
+
{plan === "enterprise" ? "Enterprise" : "Pro"}
|
|
146
|
+
</span>{" "}
|
|
147
|
+
is complete. Here's what you just unlocked:
|
|
119
148
|
</p>
|
|
120
149
|
<div className="grid gap-2 sm:grid-cols-3 mb-4">
|
|
121
150
|
<div className="bg-white/10 rounded-lg p-3">
|
|
@@ -184,7 +213,10 @@ export default function DashboardPage({ navigate }: DashboardPageProps) {
|
|
|
184
213
|
</p>
|
|
185
214
|
<p className="text-sm text-yellow-700 dark:text-yellow-300">
|
|
186
215
|
You'll have access to {getPlanName(currentPlan)} features until{" "}
|
|
187
|
-
{periodEnd
|
|
216
|
+
{periodEnd
|
|
217
|
+
? new Date(periodEnd).toLocaleDateString()
|
|
218
|
+
: "the end of your billing period"}
|
|
219
|
+
.
|
|
188
220
|
</p>
|
|
189
221
|
</div>
|
|
190
222
|
<Button variant="outline" onClick={() => navigate("/pricing")}>
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { authClient } from "../lib/auth-client";
|
|
3
2
|
import { toast } from "sonner";
|
|
4
3
|
import { ThemeToggle } from "../components/ThemeToggle";
|
|
5
4
|
import { Button } from "../components/ui/button";
|
|
5
|
+
import { authClient } from "../lib/auth-client";
|
|
6
6
|
|
|
7
7
|
interface ForgotPasswordPageProps {
|
|
8
|
-
navigate: (
|
|
8
|
+
navigate: (
|
|
9
|
+
route:
|
|
10
|
+
| "/"
|
|
11
|
+
| "/login"
|
|
12
|
+
| "/signup"
|
|
13
|
+
| "/pricing"
|
|
14
|
+
| "/dashboard"
|
|
15
|
+
| "/forgot-password"
|
|
16
|
+
| "/reset-password",
|
|
17
|
+
) => void;
|
|
9
18
|
}
|
|
10
19
|
|
|
11
20
|
export default function ForgotPasswordPage({ navigate }: ForgotPasswordPageProps) {
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
import { authClient } from "../lib/auth-client";
|
|
3
2
|
import { ThemeToggle } from "../components/ThemeToggle";
|
|
3
|
+
import { authClient } from "../lib/auth-client";
|
|
4
4
|
|
|
5
5
|
interface HomePageProps {
|
|
6
|
-
navigate: (
|
|
6
|
+
navigate: (
|
|
7
|
+
route:
|
|
8
|
+
| "/"
|
|
9
|
+
| "/login"
|
|
10
|
+
| "/signup"
|
|
11
|
+
| "/pricing"
|
|
12
|
+
| "/dashboard"
|
|
13
|
+
| "/forgot-password"
|
|
14
|
+
| "/reset-password",
|
|
15
|
+
) => void;
|
|
7
16
|
}
|
|
8
17
|
|
|
9
18
|
export default function HomePage({ navigate }: HomePageProps) {
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { authClient } from "../lib/auth-client";
|
|
3
2
|
import { ThemeToggle } from "../components/ThemeToggle";
|
|
3
|
+
import { authClient } from "../lib/auth-client";
|
|
4
4
|
|
|
5
5
|
interface LoginPageProps {
|
|
6
|
-
navigate: (
|
|
6
|
+
navigate: (
|
|
7
|
+
route:
|
|
8
|
+
| "/"
|
|
9
|
+
| "/login"
|
|
10
|
+
| "/signup"
|
|
11
|
+
| "/pricing"
|
|
12
|
+
| "/dashboard"
|
|
13
|
+
| "/forgot-password"
|
|
14
|
+
| "/reset-password",
|
|
15
|
+
) => void;
|
|
7
16
|
}
|
|
8
17
|
|
|
9
18
|
export default function LoginPage({ navigate }: LoginPageProps) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
import { authClient } from "../lib/auth-client";
|
|
3
2
|
import { toast } from "sonner";
|
|
3
|
+
import { ThemeToggle } from "../components/ThemeToggle";
|
|
4
|
+
import { Button } from "../components/ui/button";
|
|
4
5
|
import {
|
|
5
6
|
Card,
|
|
6
7
|
CardContent,
|
|
@@ -9,12 +10,20 @@ import {
|
|
|
9
10
|
CardHeader,
|
|
10
11
|
CardTitle,
|
|
11
12
|
} from "../components/ui/card";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { plans, getPlanName, isPaidPlan, type PlanId, type PlanConfig } from "../lib/plans";
|
|
13
|
+
import { authClient } from "../lib/auth-client";
|
|
14
|
+
import { type PlanConfig, type PlanId, getPlanName, isPaidPlan, plans } from "../lib/plans";
|
|
15
15
|
|
|
16
16
|
interface PricingPageProps {
|
|
17
|
-
navigate: (
|
|
17
|
+
navigate: (
|
|
18
|
+
route:
|
|
19
|
+
| "/"
|
|
20
|
+
| "/login"
|
|
21
|
+
| "/signup"
|
|
22
|
+
| "/pricing"
|
|
23
|
+
| "/dashboard"
|
|
24
|
+
| "/forgot-password"
|
|
25
|
+
| "/reset-password",
|
|
26
|
+
) => void;
|
|
18
27
|
}
|
|
19
28
|
|
|
20
29
|
export default function PricingPage({ navigate }: PricingPageProps) {
|
|
@@ -45,7 +54,7 @@ export default function PricingPage({ navigate }: PricingPageProps) {
|
|
|
45
54
|
try {
|
|
46
55
|
const subscription = await authClient.subscription.list();
|
|
47
56
|
const activeSub = subscription?.data?.find(
|
|
48
|
-
(s: { status: string }) => s.status === "active" || s.status === "trialing"
|
|
57
|
+
(s: { status: string }) => s.status === "active" || s.status === "trialing",
|
|
49
58
|
);
|
|
50
59
|
if (activeSub?.plan) {
|
|
51
60
|
setCurrentPlan(activeSub.plan as PlanId);
|
|
@@ -283,7 +292,10 @@ export default function PricingPage({ navigate }: PricingPageProps) {
|
|
|
283
292
|
<p className="text-sm text-yellow-800 dark:text-yellow-200">
|
|
284
293
|
<strong>Your subscription is set to cancel.</strong> You'll have access to{" "}
|
|
285
294
|
{getPlanName(currentPlan || "free")} features until{" "}
|
|
286
|
-
{periodEnd
|
|
295
|
+
{periodEnd
|
|
296
|
+
? new Date(periodEnd).toLocaleDateString()
|
|
297
|
+
: "the end of your billing period"}
|
|
298
|
+
.
|
|
287
299
|
</p>
|
|
288
300
|
<Button variant="outline" size="sm" asChild className="shrink-0">
|
|
289
301
|
<a href="/api/billing-portal">Manage in Stripe</a>
|
|
@@ -320,9 +332,7 @@ export default function PricingPage({ navigate }: PricingPageProps) {
|
|
|
320
332
|
<CardTitle className="text-2xl">{plan.name}</CardTitle>
|
|
321
333
|
<div className="mt-2">
|
|
322
334
|
<span className="text-4xl font-bold">{plan.price}</span>
|
|
323
|
-
{plan.id !== "free" &&
|
|
324
|
-
<span className="text-muted-foreground">/month</span>
|
|
325
|
-
)}
|
|
335
|
+
{plan.id !== "free" && <span className="text-muted-foreground">/month</span>}
|
|
326
336
|
</div>
|
|
327
337
|
<CardDescription className="mt-2">{plan.description}</CardDescription>
|
|
328
338
|
</CardHeader>
|