"use client"; /** * /sadhna-streak/preview — DEV-ONLY sandbox for the sādhana creeper. * * Lets you fast-track the vine: scrub the streak length, set today's * in-progress rounds/posts, and dial the health (growth) score to watch the * vine climb the pole, sprout folds + blossoms, and wither — all without * seeding real logs. Returns nothing in production builds. * * The synthesized payload matches what the BFF's Dashboard builds, so what * you see here mirrors live. */ import { useState } from "react"; import { SadhnaVine } from "@/components/sadhna/sadhna-vine"; import type { VineDay } from "@/lib/sadhna"; import { cn } from "@/lib/utils"; export default function SadhnaPreviewPage() { if (process.env.NODE_ENV === "production") { return (

Not available.

); } return ; } /** Build a vine_days payload exactly the way the BFF would. */ function buildDays( completed: number, target: number, todayRounds: number, todayPosts: number, todayComplete: boolean, ): VineDay[] { const out: VineDay[] = []; const now = new Date(); const todayMs = Date.UTC( now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), ); const endOffset = todayComplete ? 0 : 1; // days-ago of the last finished fold for (let i = completed - 1; i >= 0; i--) { const daysAgo = endOffset + i; const date = new Date(todayMs - daysAgo * 86400000) .toISOString() .slice(0, 10); out.push({ date, rounds: target + (i % 3), posts: 1 + (i % 2), completed: true, in_progress: false, }); } if (!todayComplete) { out.push({ date: new Date(todayMs).toISOString().slice(0, 10), rounds: todayRounds, posts: todayPosts, completed: false, in_progress: true, }); } return out; } function Preview() { const [completed, setCompleted] = useState(3); const [target] = useState(16); const [todayComplete, setTodayComplete] = useState(false); const [todayRounds, setTodayRounds] = useState(8); const [todayPosts, setTodayPosts] = useState(0); const [growth, setGrowth] = useState(60); const days = buildDays(completed, target, todayRounds, todayPosts, todayComplete); const streak = completed; // current streak = finished folds const alive = growth > 0; return (
Dev

Vine preview

{/* Controls */}
setGrowth(Math.min(100, completed * 4))}> sync health → streak setGrowth(0)}>kill
{/* Live vine — same panel chrome as the real page */}
); } function Slider({ label, value, min, max, onChange, disabled, }: { label: string; value: number; min: number; max: number; onChange: (v: number) => void; disabled?: boolean; }) { return (
{label} {value}
onChange(Number(e.target.value))} className="w-full accent-primary" />
); } function Chip({ children, onClick, }: { children: React.ReactNode; onClick: () => void; }) { return ( ); }