presenton/servers/nextjs/components/OnBoarding/FinalStep.tsx
sudipnext c7860127f2 feat: add support for optional embedded Ollama and enhance database migration handling
- Updated docker-compose.yml to allow disabling embedded Ollama via environment variable.
- Refactored Dockerfile and Dockerfile.dev for improved dependency management and installation process.
- Enhanced FastAPI migration scripts to handle orphaned Alembic revisions and added new database migration logic.
- Improved error handling in background tasks and Codex authentication endpoints.
- Added support for font file uploads with better validation and extraction of font names.
- Introduced new image search functionality with support for Pexels and Pixabay APIs.
2026-04-15 15:39:35 +05:45

132 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { ArrowRight, PartyPopper } from "lucide-react";
import { usePathname, useRouter } from "next/navigation";
import React, { useCallback, useEffect, useState } from "react";
import { trackEvent, MixpanelEvent, setTelemetryEnabled } from "@/utils/mixpanel";
import { Switch } from "../ui/switch";
const CONFETTI_COLORS = ["#ff00c5", "#f3ff00", "#9500d0", "#00d2f2", "#00ea9b", "#ff7f36"];
function fireRealisticConfetti() {
void import("canvas-confetti").then((mod) => {
const confetti = mod.default;
confetti({
particleCount: 300,
spread: 360,
origin: { x: 0.5, y: 0.5 },
colors: CONFETTI_COLORS,
startVelocity: 60,
scalar: 1.8,
gravity: 0.6,
ticks: 300,
decay: 0.93,
zIndex: 9999,
});
});
}
const FinalStep = () => {
const router = useRouter();
const pathname = usePathname();
const [trackingEnabled, setTrackingEnabled] = useState<boolean | null>(null);
useEffect(() => {
fireRealisticConfetti();
}, []);
useEffect(() => {
async function fetchStatus() {
try {
const res = await fetch("/api/telemetry-status");
const data = await res.json();
setTrackingEnabled(Boolean(data.telemetryEnabled));
} catch {
setTrackingEnabled(true);
}
}
void fetchStatus();
}, []);
const handleTrackingToggle = useCallback(
async (enabled: boolean) => {
const prev = trackingEnabled;
setTrackingEnabled(enabled);
setTelemetryEnabled(enabled);
try {
await fetch("/api/user-config", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
DISABLE_ANONYMOUS_TRACKING: enabled ? "" : "true",
}),
});
} catch {
setTrackingEnabled(prev);
setTelemetryEnabled(prev ?? true);
}
},
[trackingEnabled]
);
const handleGoToDashboard = () => {
trackEvent(MixpanelEvent.Navigation, { from: pathname, to: "/dashboard" });
router.push("/dashboard");
};
const handleGoToUpload = () => {
trackEvent(MixpanelEvent.Navigation, { from: pathname, to: "/upload" });
router.push("/upload");
};
return (
<div className="fixed top-0 left-0 w-full h-full flex flex-col items-center justify-center">
<div className="flex flex-col items-center justify-center">
<img
src="/final_onboarding.png"
alt="presenton"
className="w-[118px] h-[98px] object-contain"
/>
<h1 className="text-black text-[30px] font-normal font-unbounded py-2.5">Welcome on board!</h1>
<p className="text-[#000000CC] text-xl font-normal font-syne">
Youre all set. Lets create your first presentation.
</p>
{trackingEnabled !== null && (
<div className="flex items-center gap-3 mt-8 px-5 py-3.5 rounded-[10px] border border-[#EDEEEF] bg-white">
<div>
<p className="text-sm font-medium text-[#191919] font-syne">Usage analytics</p>
<p className="text-[11px] text-[#9CA3AF] font-syne leading-tight mt-0.5">
Help improve Presenton by sharing anonymous usage data.
</p>
</div>
<Switch
checked={trackingEnabled}
onCheckedChange={handleTrackingToggle}
className="data-[state=checked]:bg-[#7C51F8]"
/>
</div>
)}
<button
onClick={handleGoToUpload}
className="bg-[#7C51F8] px-[23px] mt-8 py-[15px] rounded-[70px] text-white text-lg font-syne font-semibold"
>
My First Presentation 🚀
</button>
<button
onClick={fireRealisticConfetti}
className="mt-3 flex items-center gap-1.5 text-sm text-[#7A5AF8] font-syne font-medium hover:underline"
>
<PartyPopper className="w-4 h-4" /> Celebrate again!
</button>
</div>
<button
onClick={handleGoToDashboard}
className="absolute uppercase bottom-20 text-[#7A5AF8] flex items-center gap-2 right-10 text-xs font-normal font-syne"
>
Go to your dashboard <ArrowRight className="w-4 h-4 text-[#7A5AF8]" />
</button>
</div>
);
};
export default FinalStep;