You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

633 lines
25 KiB

7 months ago
"use client";
import { useState, useEffect } from "react";
import Image from "next/image";
import UploadArea from "@/components/UploadArea";
7 months ago
import { useAuth } from "@/lib/auth-context";
import {
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuLink,
} from "@/components/ui/navigation-menu";
7 months ago
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ChevronDownIcon } from "lucide-react";
export default function Home() {
7 months ago
const { isAuthenticated, user, logout } = useAuth();
const [showSuccess, setShowSuccess] = useState(false);
const [userSubscription, setUserSubscription] = useState<any>(null);
7 months ago
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
// Check for success message in URL
useEffect(() => {
if (typeof window !== "undefined") {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get("success") === "true") {
setShowSuccess(true);
// Remove the query parameter from URL
window.history.replaceState({}, "", window.location.pathname);
// Hide after 5 seconds
setTimeout(() => setShowSuccess(false), 5000);
}
}
}, []);
// Fetch user subscription when authenticated
useEffect(() => {
const fetchUserSubscription = async () => {
if (!isAuthenticated || !user?.id) return;
try {
const response = await fetch("/api/subscriptions/me", {
headers: {
"user-id": user.id,
},
});
if (response.ok) {
const data = await response.json();
setUserSubscription(data.subscription);
}
} catch (error) {
console.error("Error fetching subscription:", error);
}
};
fetchUserSubscription();
}, [isAuthenticated, user]);
7 months ago
// Get user initials for the circle icon
const getUserInitials = () => {
if (!user) return "U";
const firstName = user.FirstName || "";
const lastName = user.LastName || "";
return (firstName.charAt(0) + lastName.charAt(0)).toUpperCase() || "U";
};
// Handle subscription button click
const handleSubscribe = async (tier: string) => {
if (!isAuthenticated) {
// Redirect to login
window.location.href = "/login?redirect=/";
return;
}
// Check if user already has an active subscription
if (userSubscription && userSubscription.status === "ACTIVE") {
alert(
"You already have an active subscription. Please manage it from the My Subscriptions page."
);
return;
}
// Show loading state
setLoading(true);
try {
const response = await fetch("/api/create-checkout-session", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
tier,
userId: user?.id,
}),
});
// Check if response is JSON before parsing
const contentType = response.headers.get("content-type");
if (!contentType || !contentType.includes("application/json")) {
throw new Error(
"Invalid response from server. Please check your Stripe configuration."
);
}
const data = await response.json();
if (!response.ok) {
const errorMessage = data.error || "Failed to create checkout session";
console.error("Payment API error:", errorMessage);
alert(errorMessage);
setLoading(false);
return;
}
// Redirect to Stripe Checkout
if (data.url) {
window.location.href = data.url;
} else {
alert("No checkout URL received");
setLoading(false);
}
} catch (error) {
console.error("Payment error:", error);
alert("Failed to start payment process. Please try again.");
setLoading(false);
}
};
const [loading, setLoading] = useState(false);
return (
<div className="min-h-screen" style={{ backgroundColor: "#FFFFFF" }}>
{/* Success Message Banner */}
{showSuccess && (
<div className="fixed top-16 left-1/2 transform -translate-x-1/2 z-50 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg flex items-center space-x-2">
<span></span>
<span>Subscription successful! Welcome to Reya Render.</span>
</div>
)}
{/* Sticky Navigation */}
<nav className="sticky top-0 z-50 bg-white/95 backdrop-blur-sm border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo */}
<div className="flex-shrink-0">
<Image src="/reya2.svg" alt="Reya Logo" width={120} height={40} />
</div>
{/* Navigation Menu */}
<NavigationMenu className="hidden md:flex">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink
href="/contact"
className="px-4 py-2 text-gray-700 hover:text-gray-900"
>
Contact
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
7 months ago
href="#pricing"
onClick={(e) => {
e.preventDefault();
const pricingSection = document.getElementById("pricing");
if (pricingSection) {
pricingSection.scrollIntoView({ behavior: "smooth" });
}
}}
className="px-4 py-2 text-gray-700 hover:text-gray-900 cursor-pointer"
>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
7 months ago
{/* Show Upload File only when authenticated */}
{isAuthenticated && (
<NavigationMenuItem>
<NavigationMenuLink
href="/upload"
className="px-4 py-2 text-gray-700 hover:text-gray-900"
>
Upload File
</NavigationMenuLink>
</NavigationMenuItem>
)}
</NavigationMenuList>
</NavigationMenu>
7 months ago
{/* Auth Section */}
<div className="flex items-center space-x-4">
7 months ago
{isAuthenticated ? (
// Show user circle with dropdown when logged in
<div className="flex items-center space-x-4">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="flex items-center space-x-1 bg-white hover:bg-gray-50 text-gray-700 font-semibold text-sm rounded-full px-3 py-2 transition-colors cursor-pointer border border-gray-200 hover:border-gray-300">
<div className="w-8 h-8 bg-orange-500 rounded-full flex items-center justify-center text-white">
{getUserInitials()}
</div>
<ChevronDownIcon className="w-4 h-4 transition-transform duration-200 data-[state=open]:rotate-180" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
7 months ago
<DropdownMenuItem asChild>
<a href="/contact" className="cursor-pointer">
Contact
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a
href="#pricing"
onClick={(e) => {
e.preventDefault();
const pricingSection =
document.getElementById("pricing");
if (pricingSection) {
pricingSection.scrollIntoView({
behavior: "smooth",
});
}
}}
className="cursor-pointer"
>
Pricing
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href="/upload" className="cursor-pointer">
Upload File
</a>
</DropdownMenuItem>
<div className="border-t border-gray-200 my-1" />
7 months ago
<DropdownMenuItem asChild>
<a href="/subscriptions" className="cursor-pointer">
My Subscriptions
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href="/renders" className="cursor-pointer">
My Renders
</a>
</DropdownMenuItem>
<DropdownMenuItem
onClick={logout}
className="cursor-pointer"
>
Logout
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
) : (
// Show login/signup buttons when not authenticated
<>
7 months ago
{/* Hamburger Button - Mobile (visible when logged out) */}
<button
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="md:hidden p-2 rounded-md text-gray-700 hover:bg-gray-100"
aria-label="Toggle menu"
7 months ago
>
7 months ago
<svg
className="w-6 h-6"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
>
{mobileMenuOpen ? (
<path d="M6 18L18 6M6 6l12 12" />
) : (
<path d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
{/* Desktop Login/Signup Buttons */}
<div className="hidden md:flex items-center space-x-4">
<a
href="/login"
className="text-gray-700 hover:text-gray-900 px-4 py-2 border border-gray-300 hover:border-gray-400 rounded-md cursor-pointer transition-colors"
>
Log In
</a>
<a
href="/signup"
className="bg-orange-500 hover:bg-orange-600 text-white px-6 py-2 rounded-md font-medium cursor-pointer transition-colors"
>
Sign Up
</a>
</div>
7 months ago
</>
)}
</div>
</div>
</div>
</nav>
7 months ago
{/* Mobile Menu Panel - Only show when logged out */}
{!isAuthenticated && (
<div
className={`fixed top-16 right-0 h-[calc(100vh-4rem)] w-64 bg-white border-l border-gray-200 shadow-xl z-50 transform transition-transform duration-300 ease-in-out md:hidden ${
mobileMenuOpen ? "translate-x-0" : "translate-x-full"
}`}
>
<div className="flex flex-col p-4 space-y-4">
{/* Navigation Links */}
<a
href="/contact"
onClick={() => setMobileMenuOpen(false)}
className="px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md transition-colors"
>
Contact
</a>
<button
onClick={(e) => {
e.preventDefault();
setMobileMenuOpen(false);
const pricingSection = document.getElementById("pricing");
if (pricingSection) {
pricingSection.scrollIntoView({ behavior: "smooth" });
}
}}
className="px-4 py-2 text-left text-gray-700 hover:bg-gray-100 rounded-md transition-colors"
>
Pricing
</button>
{/* Divider */}
<div className="border-t border-gray-200 my-2" />
{/* Auth Section - Mobile */}
<a
href="/login"
onClick={() => setMobileMenuOpen(false)}
className="px-4 py-2 text-center text-gray-700 border border-gray-300 hover:bg-gray-100 rounded-md transition-colors"
>
Log In
</a>
<a
href="/signup"
onClick={() => setMobileMenuOpen(false)}
className="px-4 py-2 text-center bg-orange-500 hover:bg-orange-600 text-white rounded-md transition-colors"
>
Sign Up
</a>
</div>
</div>
)}
{/* Main Content */}
<div className="flex items-center justify-center min-h-screen">
<div
7 months ago
className="w-[90%] md:w-[90%] h-auto md:h-[600px] rounded-2xl flex flex-col md:flex-row justify-between items-start relative"
style={{
backgroundColor: "#FF580F",
margin: "20px",
marginTop: "5px",
}}
>
7 months ago
<div className="px-4 md:ml-8 mt-8 md:mt-16 w-full md:w-auto pb-8 md:pb-0">
<h1
7 months ago
className="text-white text-3xl md:text-6xl font-bold mb-4"
style={{ fontFamily: "Inter, sans-serif" }}
>
Welcome to reYa Render
</h1>
<p
7 months ago
className="text-white text-sm md:text-2xl max-w-full md:max-w-[600px] mb-6 md:mb-0 leading-relaxed pr-2 md:pr-0"
style={{ fontFamily: "Inter, sans-serif" }}
>
Whether you're working on animations, visualizations, or still
images, our render farm is optimized to deliver high-quality
results efficiently. Simply upload your files, and our system will
take care of the rendering process, saving you time and computing
power so you can focus on the creative side of your work.
</p>
7 months ago
<div className="flex flex-col md:flex-row gap-3 md:gap-4 mt-4 md:mt-6 w-full md:w-auto">
7 months ago
<a
href="/contact"
7 months ago
className="bg-white text-orange-500 px-4 py-2 md:px-6 md:py-3 rounded-md font-medium hover:bg-gray-100 cursor-pointer transition-colors text-center md:text-left text-sm md:text-base w-full md:w-auto"
7 months ago
>
Contact Us
7 months ago
</a>
<a
href="/signup"
7 months ago
className="bg-transparent border-2 border-white text-white px-4 py-2 md:px-6 md:py-3 rounded-md font-medium hover:bg-white hover:text-orange-500 cursor-pointer transition-colors text-center md:text-left text-sm md:text-base w-full md:w-auto"
7 months ago
>
Get Started
7 months ago
</a>
</div>
7 months ago
{/* Image below text on mobile */}
<div className="mt-6 md:hidden flex justify-center">
<img
src="/creativity.png"
alt="3D Model"
className="w-full max-w-[250px] h-auto"
style={{ display: "block" }}
/>
</div>
</div>
7 months ago
{/* Image on desktop */}
<div className="absolute bottom-4 right-4 hidden md:block">
<img
src="/creativity.png"
alt="3D Model"
width={500}
height={500}
style={{ display: "block" }}
/>
</div>
</div>
</div>
{/* Subscription Status Indicator */}
{isAuthenticated &&
userSubscription &&
userSubscription.status === "ACTIVE" && (
<div className="flex justify-center mt-8">
<div className="bg-green-50 border-2 border-green-500 rounded-lg p-6 max-w-2xl">
<div className="flex items-center justify-between">
<div>
<p className="text-green-800 font-semibold text-lg mb-1">
You have an active {userSubscription.tier} subscription
</p>
<p className="text-green-700 text-sm">
Member since{" "}
{new Date(userSubscription.created_at).toLocaleDateString()}
</p>
</div>
<a
href="/subscriptions"
className="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-md text-sm font-medium ml-4"
>
Manage Subscription
</a>
</div>
</div>
</div>
)}
{/* Pricing Section */}
7 months ago
<div id="pricing" className="flex justify-center mt-16 mb-16">
<div className="w-[90%]">
<h2 className="text-4xl font-bold text-center mb-12 text-gray-800">
Available Plans
</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{/* Basic Plan */}
<div className="bg-white border-2 border-gray-200 rounded-xl p-8 text-center transition-all hover:transform hover:-translate-y-2 hover:shadow-xl hover:border-orange-500 cursor-pointer">
<div className="text-2xl font-bold text-orange-500 mb-2">
Basic
</div>
<div className="text-4xl font-bold text-orange-500 mb-8">
9.99{" "}
<span className="text-lg font-normal text-gray-500">
/month
</span>
</div>
<button
onClick={() => handleSubscribe("basic")}
disabled={
loading ||
(userSubscription && userSubscription.status === "ACTIVE")
}
className="w-full bg-orange-500 text-white py-3 px-6 rounded-lg font-medium mb-6 hover:bg-orange-600 transition-colors hover:cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading
? "Processing..."
: userSubscription && userSubscription.status === "ACTIVE"
? "Current Plan"
: "Choose Basic"}
</button>
<ul className="text-left space-y-3">
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
250 GB storage
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Custom subdomain
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Unlimited downloads
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Password protected links
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Basic analytics
</li>
</ul>
</div>
{/* Standard Plan */}
<div className="bg-white border-2 border-gray-200 rounded-xl p-8 text-center transition-all hover:transform hover:-translate-y-2 hover:shadow-xl hover:border-orange-500 cursor-pointer">
<div className="text-2xl font-bold text-orange-500 mb-2">
Standard
</div>
<div className="text-4xl font-bold text-orange-500 mb-8">
19.99{" "}
<span className="text-lg font-normal text-gray-500">
/month
</span>
</div>
<button
onClick={() => handleSubscribe("standard")}
disabled={
loading ||
(userSubscription && userSubscription.status === "ACTIVE")
}
className="w-full bg-orange-500 text-white py-3 px-6 rounded-lg font-medium mb-6 hover:bg-orange-600 transition-colors hover:cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading
? "Processing..."
: userSubscription && userSubscription.status === "ACTIVE"
? "Current Plan"
: "Choose Standard"}
</button>
<ul className="text-left space-y-3">
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
500 GB storage
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Custom subdomain
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Unlimited downloads
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Password protected links
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Basic analytics
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Custom branding & logo
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Priority support
</li>
</ul>
</div>
{/* Premium Plan */}
<div className="bg-white border-2 border-gray-200 rounded-xl p-8 text-center transition-all hover:transform hover:-translate-y-2 hover:shadow-xl hover:border-orange-500 cursor-pointer">
<div className="text-2xl font-bold text-orange-500 mb-2">
Premium
</div>
<div className="text-4xl font-bold text-orange-500 mb-8">
39.99{" "}
<span className="text-lg font-normal text-gray-500">
/month
</span>
</div>
<button
onClick={() => handleSubscribe("premium")}
disabled={
loading ||
(userSubscription && userSubscription.status === "ACTIVE")
}
className="w-full bg-orange-500 text-white py-3 px-6 rounded-lg font-medium mb-6 hover:bg-orange-600 transition-colors hover:cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading
? "Processing..."
: userSubscription && userSubscription.status === "ACTIVE"
? "Current Plan"
: "Choose Premium"}
</button>
<ul className="text-left space-y-3">
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>1 TB
storage
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Custom subdomain
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Unlimited downloads
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Password protected links
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Basic analytics
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Custom branding & logo
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Priority support
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Multiple user accounts
</li>
<li className="flex items-center">
<span className="text-green-500 font-bold mr-3"></span>
Team management
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
);
}