feat: no login experience and prem tokens
Some checks are pending
Build and Push Docker Images / tag_release (push) Waiting to run
Build and Push Docker Images / build (./surfsense_backend, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_backend, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_web, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-24.04-arm, linux/arm64, arm64) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_web, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-latest, linux/amd64, amd64) (push) Blocked by required conditions
Build and Push Docker Images / create_manifest (backend, surfsense-backend) (push) Blocked by required conditions
Build and Push Docker Images / create_manifest (web, surfsense-web) (push) Blocked by required conditions

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-04-15 17:02:00 -07:00
parent 87452bb315
commit ff4e0f9b62
68 changed files with 5914 additions and 121 deletions

View file

@ -0,0 +1,49 @@
"use client";
import { motion } from "motion/react";
import { useState } from "react";
import { BuyPagesContent } from "@/components/settings/buy-pages-content";
import { BuyTokensContent } from "@/components/settings/buy-tokens-content";
import { cn } from "@/lib/utils";
const TABS = [
{ id: "pages", label: "Pages" },
{ id: "tokens", label: "Premium Tokens" },
] as const;
type TabId = (typeof TABS)[number]["id"];
export default function BuyMorePage() {
const [activeTab, setActiveTab] = useState<TabId>("pages");
return (
<div className="flex min-h-[calc(100vh-64px)] select-none items-center justify-center px-4 py-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className="w-full max-w-md space-y-6"
>
<div className="flex items-center justify-center rounded-lg border bg-muted/30 p-1">
{TABS.map((tab) => (
<button
key={tab.id}
type="button"
onClick={() => setActiveTab(tab.id)}
className={cn(
"flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors",
activeTab === tab.id
? "bg-background text-foreground shadow-sm"
: "text-muted-foreground hover:text-foreground"
)}
>
{tab.label}
</button>
))}
</div>
{activeTab === "pages" ? <BuyPagesContent /> : <BuyTokensContent />}
</motion.div>
</div>
);
}

View file

@ -1,19 +1,16 @@
"use client";
import { motion } from "motion/react";
import { BuyPagesContent } from "@/components/settings/buy-pages-content";
import { useParams, useRouter } from "next/navigation";
import { useEffect } from "react";
export default function BuyPagesPage() {
return (
<div className="flex min-h-[calc(100vh-64px)] select-none items-center justify-center px-4 py-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className="w-full max-w-md space-y-6"
>
<BuyPagesContent />
</motion.div>
</div>
);
const router = useRouter();
const params = useParams();
const searchSpaceId = params?.search_space_id ?? "";
useEffect(() => {
router.replace(`/dashboard/${searchSpaceId}/buy-more`);
}, [router, searchSpaceId]);
return null;
}

View file

@ -0,0 +1,16 @@
"use client";
import { useParams, useRouter } from "next/navigation";
import { useEffect } from "react";
export default function BuyTokensPage() {
const router = useRouter();
const params = useParams();
const searchSpaceId = params?.search_space_id ?? "";
useEffect(() => {
router.replace(`/dashboard/${searchSpaceId}/buy-more`);
}, [router, searchSpaceId]);
return null;
}

View file

@ -23,16 +23,14 @@ export default function PurchaseCancelPage() {
<CardHeader className="text-center">
<CircleSlash2 className="mx-auto h-10 w-10 text-muted-foreground" />
<CardTitle className="text-2xl">Checkout canceled</CardTitle>
<CardDescription>
No charge was made and your current pages are unchanged.
</CardDescription>
<CardDescription>No charge was made and your account is unchanged.</CardDescription>
</CardHeader>
<CardContent className="text-center text-sm text-muted-foreground">
You can return to the pricing options and try again whenever you&apos;re ready.
</CardContent>
<CardFooter className="flex flex-col gap-2 sm:flex-row">
<Button asChild className="w-full">
<Link href={`/dashboard/${searchSpaceId}/more-pages`}>Back to Buy Pages</Link>
<Link href={`/dashboard/${searchSpaceId}/buy-more`}>Back to Pricing</Link>
</Button>
<Button asChild variant="outline" className="w-full">
<Link href={`/dashboard/${searchSpaceId}/new-chat`}>Back to Dashboard</Link>

View file

@ -23,6 +23,7 @@ export default function PurchaseSuccessPage() {
useEffect(() => {
void queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
void queryClient.invalidateQueries({ queryKey: ["token-status"] });
}, [queryClient]);
return (
@ -31,13 +32,11 @@ export default function PurchaseSuccessPage() {
<CardHeader className="text-center">
<CheckCircle2 className="mx-auto h-10 w-10 text-emerald-500" />
<CardTitle className="text-2xl">Purchase complete</CardTitle>
<CardDescription>
Your additional pages are being applied to your account now.
</CardDescription>
<CardDescription>Your purchase is being applied to your account now.</CardDescription>
</CardHeader>
<CardContent className="space-y-3 text-center">
<p className="text-sm text-muted-foreground">
Your sidebar usage meter should refresh automatically in a moment.
Your usage meters should refresh automatically in a moment.
</p>
</CardContent>
<CardFooter className="flex flex-col gap-2">
@ -45,7 +44,7 @@ export default function PurchaseSuccessPage() {
<Link href={`/dashboard/${searchSpaceId}/new-chat`}>Back to Dashboard</Link>
</Button>
<Button asChild variant="outline" className="w-full">
<Link href={`/dashboard/${searchSpaceId}/more-pages`}>Buy More Pages</Link>
<Link href={`/dashboard/${searchSpaceId}/buy-more`}>Buy More</Link>
</Button>
</CardFooter>
</Card>