Initial commit: Complete Pennyzo Frontend with waitlist form implementation
- Added React TypeScript frontend with Vite build system - Implemented luxury-themed UI with custom Tailwind colors - Created comprehensive waitlist form with conditional logic: * Personal information (name, email) * Company details (name, type, GST registration) * Conditional CIN/PAN fields based on company type and GST status * Industry selection and goals questionnaire - Added form validation and error handling - Integrated waitlist form with hero section and live counter - Implemented responsive design with elegant animations - Added proper gitignore for frontend project
This commit is contained in:
52
src/App.tsx
Normal file
52
src/App.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useState } from 'react';
|
||||
import './index.css';
|
||||
import Header from './components/Header';
|
||||
import HeroSection from './components/HeroSection';
|
||||
import FeaturesSection from './components/FeaturesSection';
|
||||
import RoadmapSection from './components/RoadmapSection';
|
||||
import WhyPennyzoSection from './components/WhyPennyzoSection';
|
||||
import Footer from './components/Footer';
|
||||
import LiveCounter from './components/LiveCounter';
|
||||
import WaitlistForm from './components/WaitlistForm';
|
||||
|
||||
function App() {
|
||||
const [showWaitlistForm, setShowWaitlistForm] = useState(false);
|
||||
|
||||
const openWaitlistForm = () => setShowWaitlistForm(true);
|
||||
const closeWaitlistForm = () => setShowWaitlistForm(false);
|
||||
return (
|
||||
<div className="App min-h-screen bg-luxury-texture bg-cover bg-fixed bg-center font-elegant-sans relative">
|
||||
{/* Enhanced Background Overlay System */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-deep-forest/60 via-deep-forest/40 to-rich-brown/30"></div>
|
||||
|
||||
{/* Animated Background Elements */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<div className="absolute -top-1/2 -left-1/2 w-full h-full bg-luxury-gold/2 rounded-full blur-3xl animate-pulse"></div>
|
||||
<div className="absolute -bottom-1/2 -right-1/2 w-full h-full bg-cream/3 rounded-full blur-3xl animate-pulse delay-1000"></div>
|
||||
<div className="absolute top-1/4 left-1/3 w-96 h-96 bg-luxury-gold/1 rounded-full blur-2xl animate-pulse delay-2000"></div>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="relative z-10 min-h-screen">
|
||||
<Header />
|
||||
<LiveCounter onJoinWaitlist={openWaitlistForm} />
|
||||
<main>
|
||||
<HeroSection onJoinWaitlist={openWaitlistForm} />
|
||||
<FeaturesSection />
|
||||
<WhyPennyzoSection />
|
||||
<RoadmapSection />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
{/* Global Waitlist Form */}
|
||||
<WaitlistForm
|
||||
isVisible={showWaitlistForm}
|
||||
onClose={closeWaitlistForm}
|
||||
onBack={closeWaitlistForm}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
85
src/components/ExclusiveLaunchPopup.tsx
Normal file
85
src/components/ExclusiveLaunchPopup.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface ExclusiveLaunchPopupProps {
|
||||
remainingSpots: number;
|
||||
onJoinWaitlist: () => void;
|
||||
}
|
||||
|
||||
const ExclusiveLaunchPopup: React.FC<ExclusiveLaunchPopupProps> = ({ remainingSpots, onJoinWaitlist }) => {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Show popup after 2 seconds
|
||||
const timer = setTimeout(() => {
|
||||
setIsVisible(true);
|
||||
}, 2000);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-deep-forest/80 backdrop-blur-sm">
|
||||
<div className="relative max-w-md mx-4">
|
||||
{/* Close Button */}
|
||||
<button
|
||||
onClick={() => setIsVisible(false)}
|
||||
className="absolute -top-2 -right-2 w-8 h-8 bg-luxury-gold hover:bg-luxury-gold/90 text-deep-forest rounded-full flex items-center justify-center font-bold z-10 transition-all duration-200"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
||||
{/* Popup Content */}
|
||||
<div className="bg-gradient-to-r from-luxury-gold/20 to-luxury-gold/10 backdrop-blur-xl border border-luxury-gold/30 rounded-2xl p-8 shadow-2xl">
|
||||
<div className="text-center">
|
||||
<div className="flex items-center justify-center space-x-3 mb-6">
|
||||
<div className="w-2 h-2 bg-luxury-gold rounded-full animate-pulse"></div>
|
||||
<span className="text-luxury-gold font-luxury-serif text-sm font-semibold tracking-[0.2em] uppercase">
|
||||
Exclusive Launch
|
||||
</span>
|
||||
<div className="w-2 h-2 bg-luxury-gold rounded-full animate-pulse"></div>
|
||||
</div>
|
||||
|
||||
<h2 className="text-luxury-gold font-luxury-serif text-3xl font-bold mb-4">
|
||||
First 1,000 Elite Members
|
||||
</h2>
|
||||
<p className="text-cream/80 font-elegant-sans text-lg mb-6">
|
||||
Get complimentary access to our MVP platform
|
||||
</p>
|
||||
|
||||
<div className="bg-deep-forest/50 backdrop-blur-sm border border-luxury-gold/20 rounded-xl p-6 mb-6">
|
||||
<div className="flex items-center justify-center space-x-4 mb-4">
|
||||
<span className="text-cream/70 font-elegant-sans text-base">Remaining:</span>
|
||||
<div className="bg-luxury-gold text-deep-forest font-luxury-serif font-bold text-2xl px-6 py-2 rounded-lg shadow-lg">
|
||||
{remainingSpots}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="w-32 bg-deep-forest/30 rounded-full h-2 mb-2">
|
||||
<div
|
||||
className="bg-gradient-to-r from-luxury-gold to-cream h-2 rounded-full transition-all duration-1000"
|
||||
style={{ width: `${(remainingSpots / 1000) * 100}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<span className="text-cream/50 text-sm font-elegant-sans">of 1,000 spots</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsVisible(false);
|
||||
onJoinWaitlist();
|
||||
}}
|
||||
className="w-full bg-luxury-gold hover:bg-luxury-gold/90 text-deep-forest font-elegant-sans font-semibold text-lg py-4 px-6 rounded-xl transition-all duration-300 transform hover:scale-105 shadow-lg"
|
||||
>
|
||||
Join the Waitlist
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExclusiveLaunchPopup;
|
||||
132
src/components/FeaturesSection.tsx
Normal file
132
src/components/FeaturesSection.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
interface Feature {
|
||||
icon: React.ReactNode;
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const FeaturesSection: React.FC = () => {
|
||||
const features: Feature[] = [
|
||||
{
|
||||
icon: (
|
||||
<svg className="w-10 h-10 text-luxury-gold" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"/>
|
||||
</svg>
|
||||
),
|
||||
name: 'FinBook: Smart Accounting',
|
||||
description: 'Advanced financial management with automated bookkeeping, intelligent expense tracking, and comprehensive reporting to keep your finances organized.'
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<svg className="w-10 h-10 text-luxury-gold" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M16 4c0-1.11.89-2 2-2s2 .89 2 2-.89 2-2 2-2-.89-2-2zm4 18v-6h2.5l-2.54-7.63A2.99 2.99 0 0 0 17.15 7H16c-.8 0-1.54.37-2.03.97L12 10.5 10.03 7.97A2.5 2.5 0 0 0 8 7H6.85c-1.31 0-2.43.83-2.81 2.37L1.5 16H4v6h2v-6h2.5l1.5-4.5L12 14.5l2-3 1.5 4.5H18v6h2z"/>
|
||||
</svg>
|
||||
),
|
||||
name: 'HR Management Suite',
|
||||
description: 'Streamline your human resources with employee onboarding, performance tracking, payroll integration, and comprehensive workforce analytics.'
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<svg className="w-10 h-10 text-luxury-gold" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||||
</svg>
|
||||
),
|
||||
name: 'Customer Relationship Manager',
|
||||
description: 'Build stronger customer relationships with contact management, sales pipeline tracking, automated follow-ups, and detailed analytics.'
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<svg className="w-10 h-10 text-luxury-gold" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M9 11H7v6h2v-6zm4 0h-2v6h2v-6zm4 0h-2v6h2v-6zm2.5-9H19v2h-1.5v17H6.5V4H5V2h3.5V1h7v1H19v2h-.5V2z"/>
|
||||
</svg>
|
||||
),
|
||||
name: 'Inventory Control',
|
||||
description: 'Optimize your supply chain with real-time stock tracking, automated reordering, supplier management, and comprehensive inventory reports.'
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<svg className="w-10 h-10 text-luxury-gold" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>
|
||||
</svg>
|
||||
),
|
||||
name: 'Business Intelligence',
|
||||
description: 'Transform your data into actionable insights with customizable dashboards, automated reports, and predictive analytics for smarter decisions.'
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<svg className="w-10 h-10 text-luxury-gold" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 1L3 5v6c0 5.55 3.84 9.739 9 11 5.16-1.261 9-5.45 9-11V5l-9-4z"/>
|
||||
</svg>
|
||||
),
|
||||
name: 'Security & Compliance',
|
||||
description: 'Protect your business with enterprise-grade security, automatic backups, compliance monitoring, and comprehensive audit trails.'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="features" className="py-20 lg:py-32 relative">
|
||||
{/* Background overlay for section */}
|
||||
<div className="absolute inset-0 bg-deep-forest bg-opacity-20"></div>
|
||||
|
||||
<div className="container mx-auto px-6 relative z-10">
|
||||
{/* Section Title */}
|
||||
<div className="text-center mb-20">
|
||||
<div className="flex items-center justify-center mb-8">
|
||||
<div className="w-20 h-0.5 bg-luxury-gold mr-6"></div>
|
||||
<div className="w-3 h-3 bg-luxury-gold rounded-full"></div>
|
||||
<div className="w-20 h-0.5 bg-luxury-gold ml-6"></div>
|
||||
</div>
|
||||
<h2 className="text-4xl md:text-5xl lg:text-6xl font-luxury-serif font-bold text-luxury-gold mb-8 tracking-wide">
|
||||
A Complete Toolkit
|
||||
<span className="block text-cream mt-2">to Run Your Business</span>
|
||||
</h2>
|
||||
<p className="text-xl text-cream max-w-4xl mx-auto font-elegant-sans font-light leading-relaxed">
|
||||
Manage your finances, sales, HR, and operations from a single, easy-to-use platform
|
||||
designed for organizations that demand excellence.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Features Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 lg:gap-10">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="group bg-deep-forest bg-opacity-40 backdrop-blur-sm border border-luxury-gold border-opacity-20 rounded-2xl p-8 hover:bg-opacity-60 hover:border-opacity-40 transition-all duration-500 transform hover:-translate-y-2 hover:shadow-2xl hover:shadow-luxury-gold/10"
|
||||
>
|
||||
{/* Icon */}
|
||||
<div className="mb-8">
|
||||
<div className="w-20 h-20 bg-luxury-gold bg-opacity-10 rounded-2xl flex items-center justify-center group-hover:bg-opacity-20 transition-all duration-300 group-hover:scale-110">
|
||||
{feature.icon}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Feature Name */}
|
||||
<h3 className="text-2xl font-luxury-serif font-semibold text-luxury-gold mb-6 tracking-wide">
|
||||
{feature.name}
|
||||
</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-cream leading-relaxed font-elegant-sans opacity-90 group-hover:opacity-100 transition-opacity duration-300">
|
||||
{feature.description}
|
||||
</p>
|
||||
|
||||
{/* Decorative element */}
|
||||
<div className="mt-6 w-12 h-0.5 bg-luxury-gold opacity-30 group-hover:opacity-100 group-hover:w-20 transition-all duration-500"></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Bottom CTA */}
|
||||
<div className="text-center mt-20">
|
||||
<p className="text-cream mb-8 font-elegant-sans text-lg">
|
||||
Everything you need, all in one place.
|
||||
</p>
|
||||
<button className="bg-luxury-gold hover:bg-opacity-90 text-deep-forest px-12 py-4 rounded-xl font-elegant-sans font-semibold text-lg tracking-wide transition-all duration-300 transform hover:scale-105 hover:shadow-2xl focus:outline-none focus:ring-4 focus:ring-luxury-gold focus:ring-opacity-50">
|
||||
Explore All Features
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeaturesSection;
|
||||
163
src/components/Footer.tsx
Normal file
163
src/components/Footer.tsx
Normal file
@@ -0,0 +1,163 @@
|
||||
const Footer: React.FC = () => {
|
||||
return (
|
||||
<footer className="bg-deep-forest bg-opacity-80 border-t border-luxury-gold border-opacity-30 py-16 relative">
|
||||
{/* Background overlay */}
|
||||
<div className="absolute inset-0 bg-rich-brown bg-opacity-10"></div>
|
||||
|
||||
<div className="container mx-auto px-6 relative z-10">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12 lg:gap-16">
|
||||
{/* Company Info */}
|
||||
<div className="col-span-1 lg:col-span-2">
|
||||
<div className="mb-6">
|
||||
<img
|
||||
src="/assets/Dark-LineLogo-cropped.svg"
|
||||
alt="Pennyzo Logo"
|
||||
className="h-12 w-auto"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-cream mb-8 max-w-md font-elegant-sans leading-relaxed opacity-90">
|
||||
The pinnacle of business management excellence. Experience unparalleled sophistication
|
||||
in enterprise operations, where every detail reflects our commitment to perfection.
|
||||
</p>
|
||||
|
||||
{/* Social Media Links */}
|
||||
<div className="flex space-x-6">
|
||||
<a
|
||||
href="#"
|
||||
className="w-12 h-12 bg-luxury-gold bg-opacity-10 rounded-xl flex items-center justify-center text-luxury-gold hover:bg-opacity-20 hover:scale-110 transition-all duration-300 group"
|
||||
>
|
||||
<svg className="w-6 h-6 group-hover:scale-110 transition-transform duration-300" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="w-12 h-12 bg-luxury-gold bg-opacity-10 rounded-xl flex items-center justify-center text-luxury-gold hover:bg-opacity-20 hover:scale-110 transition-all duration-300 group"
|
||||
>
|
||||
<svg className="w-6 h-6 group-hover:scale-110 transition-transform duration-300" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="w-12 h-12 bg-luxury-gold bg-opacity-10 rounded-xl flex items-center justify-center text-luxury-gold hover:bg-opacity-20 hover:scale-110 transition-all duration-300 group"
|
||||
>
|
||||
<svg className="w-6 h-6 group-hover:scale-110 transition-transform duration-300" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.174-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.74.099.12.112.225.085.345-.09.375-.294 1.195-.334 1.362-.053.225-.172.271-.402.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.357-.629-2.750-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24.009 12.017 24.009c6.624 0 11.99-5.367 11.99-11.988C24.007 5.367 18.641.001.012.017z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Links */}
|
||||
<div>
|
||||
<h4 className="text-xl font-luxury-serif font-semibold text-luxury-gold mb-6 tracking-wide">
|
||||
Navigation
|
||||
</h4>
|
||||
<ul className="space-y-4">
|
||||
<li>
|
||||
<a
|
||||
href="#features"
|
||||
className="text-cream hover:text-luxury-gold transition-all duration-300 font-elegant-sans opacity-90 hover:opacity-100 relative group"
|
||||
>
|
||||
Premium Features
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-luxury-gold transition-all duration-300 group-hover:w-full"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#why-pennyzo"
|
||||
className="text-cream hover:text-luxury-gold transition-all duration-300 font-elegant-sans opacity-90 hover:opacity-100 relative group"
|
||||
>
|
||||
Why Choose Us
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-luxury-gold transition-all duration-300 group-hover:w-full"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#roadmap"
|
||||
className="text-cream hover:text-luxury-gold transition-all duration-300 font-elegant-sans opacity-90 hover:opacity-100 relative group"
|
||||
>
|
||||
Excellence Roadmap
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-luxury-gold transition-all duration-300 group-hover:w-full"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#pricing"
|
||||
className="text-cream hover:text-luxury-gold transition-all duration-300 font-elegant-sans opacity-90 hover:opacity-100 relative group"
|
||||
>
|
||||
Investment Plans
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-luxury-gold transition-all duration-300 group-hover:w-full"></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Contact */}
|
||||
<div>
|
||||
<h4 className="text-xl font-luxury-serif font-semibold text-luxury-gold mb-6 tracking-wide">
|
||||
Connect
|
||||
</h4>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<p className="text-cream font-elegant-sans opacity-75 mb-2">Executive Inquiries</p>
|
||||
<a
|
||||
href="mailto:excellence@pennyzo.com"
|
||||
className="text-luxury-gold hover:text-cream transition-colors duration-300 font-elegant-sans font-medium"
|
||||
>
|
||||
excellence@pennyzo.com
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-cream font-elegant-sans opacity-75 mb-2">Concierge Support</p>
|
||||
<a
|
||||
href="tel:+1-855-PENNYZO"
|
||||
className="text-luxury-gold hover:text-cream transition-colors duration-300 font-elegant-sans font-medium"
|
||||
>
|
||||
+1 (855) PENNYZO
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Decorative Divider */}
|
||||
<div className="flex items-center justify-center my-12">
|
||||
<div className="w-24 h-0.5 bg-luxury-gold opacity-30"></div>
|
||||
<div className="w-3 h-3 bg-luxury-gold rounded-full mx-8 opacity-50"></div>
|
||||
<div className="w-24 h-0.5 bg-luxury-gold opacity-30"></div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Bar */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-center pt-8 border-t border-luxury-gold border-opacity-20">
|
||||
<p className="text-cream text-sm mb-6 md:mb-0 font-elegant-sans opacity-75">
|
||||
© 2025 Pennyzo Excellence. Crafted with sophistication.
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-8">
|
||||
<a
|
||||
href="#"
|
||||
className="text-cream hover:text-luxury-gold text-sm transition-colors duration-300 font-elegant-sans opacity-75 hover:opacity-100"
|
||||
>
|
||||
Privacy Excellence
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="text-cream hover:text-luxury-gold text-sm transition-colors duration-300 font-elegant-sans opacity-75 hover:opacity-100"
|
||||
>
|
||||
Terms of Service
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="text-cream hover:text-luxury-gold text-sm transition-colors duration-300 font-elegant-sans opacity-75 hover:opacity-100"
|
||||
>
|
||||
Cookie Preferences
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
54
src/components/Header.tsx
Normal file
54
src/components/Header.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
const Header: React.FC = () => {
|
||||
return (
|
||||
<header className="sticky top-0 z-50 bg-deep-forest bg-opacity-95 backdrop-blur-sm border-b border-luxury-gold border-opacity-20">
|
||||
<div className="container mx-auto px-6 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
{/* Logo */}
|
||||
<div className="flex-shrink-0">
|
||||
<img
|
||||
src="/assets/Dark-LineLogo-cropped.svg"
|
||||
alt="Pennyzo Logo"
|
||||
className="h-10 w-auto"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Navigation Links - Centered */}
|
||||
<nav className="hidden md:flex items-center space-x-10 absolute left-1/2 transform -translate-x-1/2">
|
||||
<a
|
||||
href="#features"
|
||||
className="text-cream hover:text-luxury-gold transition-all duration-300 font-elegant-sans font-medium tracking-wide relative group"
|
||||
>
|
||||
Features
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-luxury-gold transition-all duration-300 group-hover:w-full"></span>
|
||||
</a>
|
||||
<a
|
||||
href="#why-pennyzo"
|
||||
className="text-cream hover:text-luxury-gold transition-all duration-300 font-elegant-sans font-medium tracking-wide relative group"
|
||||
>
|
||||
Why Pennyzo?
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-luxury-gold transition-all duration-300 group-hover:w-full"></span>
|
||||
</a>
|
||||
<a
|
||||
href="#roadmap"
|
||||
className="text-cream hover:text-luxury-gold transition-all duration-300 font-elegant-sans font-medium tracking-wide relative group"
|
||||
>
|
||||
Roadmap
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-luxury-gold transition-all duration-300 group-hover:w-full"></span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<div className="md:hidden">
|
||||
<button className="text-cream hover:text-luxury-gold focus:outline-none focus:text-luxury-gold transition-colors duration-300">
|
||||
<svg className="h-6 w-6 fill-current" viewBox="0 0 24 24">
|
||||
<path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
139
src/components/HeroSection.tsx
Normal file
139
src/components/HeroSection.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import ExclusiveLaunchPopup from './ExclusiveLaunchPopup';
|
||||
|
||||
interface HeroSectionProps {
|
||||
onJoinWaitlist: () => void;
|
||||
}
|
||||
|
||||
const HeroSection: React.FC<HeroSectionProps> = ({ onJoinWaitlist }) => {
|
||||
const [remainingSpots, setRemainingSpots] = useState(892);
|
||||
|
||||
// Simulate live counter decreasing
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setRemainingSpots(prev => {
|
||||
if (prev <= 0) return 0;
|
||||
const shouldDecrease = Math.random() < 0.08;
|
||||
if (shouldDecrease) {
|
||||
const decrease = Math.floor(Math.random() * 2) + 1;
|
||||
return Math.max(0, prev - decrease);
|
||||
}
|
||||
return prev;
|
||||
});
|
||||
}, 3000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="relative min-h-screen overflow-hidden">
|
||||
<ExclusiveLaunchPopup remainingSpots={remainingSpots} onJoinWaitlist={onJoinWaitlist} />
|
||||
|
||||
<div className="relative z-10 container mx-auto px-6 py-16">
|
||||
{/* Main Hero Content */}
|
||||
<div className="flex flex-col lg:flex-row items-center justify-between min-h-[calc(100vh-200px)] gap-16">
|
||||
{/* Left Content */}
|
||||
<div className="flex-1 text-center lg:text-left">
|
||||
<div className="mb-8">
|
||||
<h1 className="font-luxury-serif font-extralight text-6xl md:text-7xl lg:text-8xl xl:text-9xl leading-none mb-6">
|
||||
<span className="block text-luxury-gold tracking-tight">The Future</span>
|
||||
<span className="block text-cream/90 tracking-tight">of Business</span>
|
||||
<span className="block text-luxury-gold tracking-tight">Excellence</span>
|
||||
</h1>
|
||||
|
||||
<div className="w-24 h-px bg-gradient-to-r from-luxury-gold to-transparent mb-8"></div>
|
||||
|
||||
<p className="text-cream/80 font-elegant-sans text-xl md:text-2xl lg:text-3xl font-light leading-relaxed max-w-2xl">
|
||||
Where sophistication meets innovation in
|
||||
<span className="text-luxury-gold font-medium"> enterprise management</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Elegant CTA Section */}
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col sm:flex-row gap-4 items-center lg:items-start lg:justify-start justify-center">
|
||||
<button
|
||||
onClick={onJoinWaitlist}
|
||||
className="group relative bg-luxury-gold hover:bg-luxury-gold/90 text-deep-forest font-elegant-sans font-semibold text-lg px-12 py-4 rounded-none border-0 transition-all duration-500 overflow-hidden min-w-[220px]"
|
||||
>
|
||||
<span className="relative z-10">Join the Waitlist</span>
|
||||
<div className="absolute inset-0 bg-cream transform scale-x-0 group-hover:scale-x-100 transition-transform origin-left duration-300"></div>
|
||||
</button>
|
||||
|
||||
<button className="group border border-luxury-gold/50 text-luxury-gold hover:bg-luxury-gold/10 font-elegant-sans font-medium text-lg px-12 py-4 rounded-none transition-all duration-300 min-w-[220px]">
|
||||
<span className="group-hover:tracking-wider transition-all duration-300">Explore Platform</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center lg:justify-start space-x-6">
|
||||
<div className="text-center">
|
||||
<div className="text-luxury-gold font-luxury-serif text-2xl font-bold">500+</div>
|
||||
<div className="text-cream/60 font-elegant-sans text-xs uppercase tracking-widest">Enterprises</div>
|
||||
</div>
|
||||
<div className="w-px h-8 bg-luxury-gold/30"></div>
|
||||
<div className="text-center">
|
||||
<div className="text-luxury-gold font-luxury-serif text-2xl font-bold">99.9%</div>
|
||||
<div className="text-cream/60 font-elegant-sans text-xs uppercase tracking-widest">Uptime</div>
|
||||
</div>
|
||||
<div className="w-px h-8 bg-luxury-gold/30"></div>
|
||||
<div className="text-center">
|
||||
<div className="text-luxury-gold font-luxury-serif text-2xl font-bold">24/7</div>
|
||||
<div className="text-cream/60 font-elegant-sans text-xs uppercase tracking-widest">Support</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Content - Premium Visual */}
|
||||
<div className="flex-1 relative">
|
||||
<div className="relative max-w-lg mx-auto">
|
||||
{/* Main Card */}
|
||||
<div className="relative bg-gradient-to-br from-deep-forest/40 to-rich-brown/20 backdrop-blur-2xl border border-luxury-gold/20 rounded-3xl p-12 shadow-2xl">
|
||||
<div className="text-center space-y-4">
|
||||
{/* Premium Icon */}
|
||||
{/* <div className="inline-flex items-center justify-center w-20 h-20 bg-gradient-to-br from-luxury-gold/20 to-luxury-gold/10 rounded-2xl border border-luxury-gold/30"> */}
|
||||
<img
|
||||
src="/assets/Dark-Icon-cropped.svg"
|
||||
alt="Pennyzo Icon"
|
||||
className="w-60 h-60 mx-auto"
|
||||
/>
|
||||
{/* </div> */}
|
||||
|
||||
{/* Premium Text */}
|
||||
<div>
|
||||
<h3 className="text-luxury-gold font-luxury-serif text-3xl font-bold mb-4">
|
||||
Executive Suite
|
||||
</h3>
|
||||
<p className="text-cream/70 font-elegant-sans text-base leading-relaxed">
|
||||
Experience the pinnacle of business management with our meticulously crafted platform designed for visionary leaders.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Features List */}
|
||||
<div className="space-y-3 text-left">
|
||||
{['Advanced Analytics Dashboard', 'AI-Powered Insights', 'White-Glove Support'].map((feature, index) => (
|
||||
<div key={index} className="flex items-center space-x-3">
|
||||
<div className="w-2 h-2 bg-luxury-gold rounded-full"></div>
|
||||
<span className="text-cream/80 font-elegant-sans text-sm">{feature}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Elegant Scroll Indicator */}
|
||||
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2">
|
||||
<div className="flex flex-col items-center space-y-2">
|
||||
<div className="text-cream/40 font-elegant-sans text-xs uppercase tracking-widest">Explore</div>
|
||||
<div className="w-px h-16 bg-gradient-to-b from-luxury-gold/50 to-transparent animate-pulse"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroSection;
|
||||
144
src/components/LiveCounter.tsx
Normal file
144
src/components/LiveCounter.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import LoginPage from './LoginPage';
|
||||
|
||||
interface LiveCounterProps {
|
||||
onJoinWaitlist: () => void;
|
||||
}
|
||||
|
||||
const LiveCounter: React.FC<LiveCounterProps> = ({ onJoinWaitlist }) => {
|
||||
const [remainingSpots, setRemainingSpots] = useState(892);
|
||||
const [isLive, setIsLive] = useState(true);
|
||||
const [showLoginPage, setShowLoginPage] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Simulate live counter decreasing
|
||||
const interval = setInterval(() => {
|
||||
setRemainingSpots(prev => {
|
||||
if (prev <= 0) {
|
||||
setIsLive(false);
|
||||
return 0;
|
||||
}
|
||||
// Random decrease between 1-2 spots every few seconds
|
||||
const shouldDecrease = Math.random() < 0.06; // 6% chance every 3 seconds
|
||||
if (shouldDecrease) {
|
||||
const decrease = Math.floor(Math.random() * 2) + 1; // 1-2 spots
|
||||
return Math.max(0, prev - decrease);
|
||||
}
|
||||
return prev;
|
||||
});
|
||||
}, 3000); // Check every 3 seconds
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const percentageLeft = (remainingSpots / 1000) * 100;
|
||||
|
||||
return (
|
||||
<div className="fixed top-6 right-6 z-50 group">
|
||||
<div className="bg-gradient-to-br from-deep-forest/95 to-rich-brown/90 backdrop-blur-2xl border border-luxury-gold/30 rounded-2xl shadow-2xl transition-all duration-300 group-hover:scale-105 group-hover:shadow-3xl">
|
||||
<div className="p-6 max-w-xs">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-5">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className={`w-2 h-2 rounded-full ${isLive ? 'bg-green-400' : 'bg-red-400'} ${isLive ? 'animate-pulse' : ''}`}></div>
|
||||
<span className="text-cream/90 font-elegant-sans text-xs font-medium tracking-wider">
|
||||
{isLive ? 'LIVE' : 'ENDED'}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowLoginPage(true)}
|
||||
className="bg-luxury-gold/20 hover:bg-luxury-gold/30 px-3 py-1.5 rounded-lg transition-all duration-300"
|
||||
>
|
||||
<span className="text-luxury-gold font-elegant-sans text-xs font-semibold tracking-widest">
|
||||
Login
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Counter Display */}
|
||||
<div className="text-center mb-6">
|
||||
<div className="text-luxury-gold font-luxury-serif text-4xl font-bold mb-1 tracking-tight">
|
||||
{remainingSpots.toLocaleString()}
|
||||
</div>
|
||||
<div className="text-cream/70 font-elegant-sans text-sm tracking-wide">
|
||||
exclusive spots remaining
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Elegant Progress Bar */}
|
||||
<div className="mb-6">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-cream/50 font-elegant-sans text-xs">Progress</span>
|
||||
<span className="text-luxury-gold font-elegant-sans text-xs font-medium">
|
||||
{Math.round(percentageLeft)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-full bg-deep-forest/50 rounded-full h-2 overflow-hidden">
|
||||
<div
|
||||
className="bg-gradient-to-r from-luxury-gold via-cream to-luxury-gold h-2 rounded-full transition-all duration-1000 ease-out relative"
|
||||
style={{ width: `${percentageLeft}%` }}
|
||||
>
|
||||
<div className="absolute inset-0 bg-white/20 animate-pulse"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between mt-1">
|
||||
<span className="text-xs text-cream/40 font-elegant-sans">0</span>
|
||||
<span className="text-xs text-cream/40 font-elegant-sans">1,000</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Button */}
|
||||
{isLive ? (
|
||||
<button
|
||||
onClick={onJoinWaitlist}
|
||||
className="w-full bg-gradient-to-r from-luxury-gold to-luxury-gold/90 hover:from-luxury-gold/90 hover:to-luxury-gold text-deep-forest font-elegant-sans font-semibold py-3 px-4 rounded-xl text-sm transition-all duration-300 transform hover:scale-105 hover:shadow-lg relative overflow-hidden group/btn"
|
||||
>
|
||||
<span className="relative z-10">Join the Waitlist</span>
|
||||
<div className="absolute inset-0 bg-cream transform scale-x-0 group-hover/btn:scale-x-100 transition-transform origin-left duration-300"></div>
|
||||
</button>
|
||||
) : (
|
||||
<div className="w-full bg-rich-brown/60 text-cream/60 font-elegant-sans font-semibold py-3 px-4 rounded-xl text-sm text-center border border-luxury-gold/20">
|
||||
All Spots Claimed
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Urgency Message */}
|
||||
{isLive && remainingSpots < 100 && (
|
||||
<div className="mt-4 text-center">
|
||||
<div className="bg-red-900/20 border border-red-400/30 rounded-lg px-3 py-2">
|
||||
<span className="text-red-300 font-elegant-sans text-xs font-medium animate-pulse flex items-center justify-center">
|
||||
<svg className="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||
</svg>
|
||||
Only {remainingSpots} left!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Elite Member Badge */}
|
||||
{isLive && (
|
||||
<div className="mt-4 text-center">
|
||||
<div className="inline-flex items-center space-x-2 bg-luxury-gold/10 border border-luxury-gold/20 rounded-lg px-3 py-1.5">
|
||||
<svg className="w-3 h-3 text-luxury-gold" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
|
||||
</svg>
|
||||
<span className="text-luxury-gold font-elegant-sans text-xs font-medium">
|
||||
Elite Access
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Login Page Modal */}
|
||||
<LoginPage
|
||||
isVisible={showLoginPage}
|
||||
onClose={() => setShowLoginPage(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LiveCounter;
|
||||
187
src/components/LoginPage.tsx
Normal file
187
src/components/LoginPage.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
interface LoginPageProps {
|
||||
isVisible: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const LoginPage: React.FC<LoginPageProps> = ({ isVisible, onClose }) => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [rememberMe, setRememberMe] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
|
||||
// Simulate login process
|
||||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||
|
||||
setIsLoading(false);
|
||||
// Handle login logic here
|
||||
console.log('Login attempt:', { email, password, rememberMe });
|
||||
};
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-[60] flex items-center justify-center bg-deep-forest/80 backdrop-blur-sm">
|
||||
<div className="relative max-w-md w-full mx-4">
|
||||
{/* Close Button */}
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute -top-2 -right-2 w-8 h-8 bg-luxury-gold hover:bg-luxury-gold/90 text-deep-forest rounded-full flex items-center justify-center font-bold z-10 transition-all duration-200 shadow-lg"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
||||
{/* Login Form Container */}
|
||||
<div className="bg-gradient-to-br from-deep-forest/95 to-rich-brown/90 backdrop-blur-2xl border border-luxury-gold/30 rounded-2xl shadow-2xl overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="bg-gradient-to-r from-luxury-gold/10 to-luxury-gold/5 px-8 py-6 border-b border-luxury-gold/20">
|
||||
<div className="text-center">
|
||||
<img
|
||||
src="/assets/Dark-Icon-cropped.svg"
|
||||
alt="Pennyzo Icon"
|
||||
className="w-16 h-16 mx-auto mb-4"
|
||||
/>
|
||||
<h2 className="text-luxury-gold font-luxury-serif text-2xl font-bold mb-2">
|
||||
Welcome Back
|
||||
</h2>
|
||||
<p className="text-cream/70 font-elegant-sans text-sm">
|
||||
Sign in to your executive account
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Login Form */}
|
||||
<div className="p-8">
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* Email Field */}
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="w-full bg-deep-forest/50 border border-luxury-gold/20 rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans"
|
||||
placeholder="enter your email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Password Field */}
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
Password
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full bg-deep-forest/50 border border-luxury-gold/20 rounded-lg px-4 py-3 pr-12 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans"
|
||||
placeholder="enter your password"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-cream/50 hover:text-cream/70 transition-colors duration-200"
|
||||
>
|
||||
{showPassword ? (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L8.464 8.464m1.414 1.414l2.829 2.829m-2.829-2.829l-1.414-1.414M15.121 15.121L13.707 16.535m1.414-1.414L16.535 13.707m-1.414 1.414l-2.829-2.829m2.829 2.829l1.414 1.414" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Remember Me & Forgot Password */}
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="flex items-center space-x-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={rememberMe}
|
||||
onChange={(e) => setRememberMe(e.target.checked)}
|
||||
className="w-4 h-4 text-luxury-gold bg-deep-forest/50 border-luxury-gold/20 rounded focus:ring-luxury-gold/50 focus:ring-2"
|
||||
/>
|
||||
<span className="text-cream/70 font-elegant-sans text-sm">Remember me</span>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
className="text-luxury-gold hover:text-luxury-gold/80 font-elegant-sans text-sm font-medium transition-colors duration-300"
|
||||
>
|
||||
Forgot password?
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Login Button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="w-full bg-gradient-to-r from-luxury-gold to-luxury-gold/90 hover:from-luxury-gold/90 hover:to-luxury-gold text-deep-forest font-elegant-sans font-semibold py-3 px-4 rounded-xl transition-all duration-300 transform hover:scale-105 hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 relative overflow-hidden group"
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center space-x-2">
|
||||
<div className="w-4 h-4 border-2 border-deep-forest border-t-transparent rounded-full animate-spin"></div>
|
||||
<span>Signing In...</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<span className="relative z-10">Sign In</span>
|
||||
<div className="absolute inset-0 bg-cream transform scale-x-0 group-hover:scale-x-100 transition-transform origin-left duration-300"></div>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="my-6 flex items-center">
|
||||
<div className="flex-1 h-px bg-luxury-gold/20"></div>
|
||||
<span className="px-4 text-cream/50 font-elegant-sans text-xs uppercase tracking-widest">
|
||||
or
|
||||
</span>
|
||||
<div className="flex-1 h-px bg-luxury-gold/20"></div>
|
||||
</div>
|
||||
|
||||
{/* Social Login Options */}
|
||||
<div className="space-y-3">
|
||||
<button className="w-full bg-deep-forest/30 hover:bg-deep-forest/40 border border-luxury-gold/20 text-cream font-elegant-sans py-3 px-4 rounded-xl transition-all duration-300 flex items-center justify-center space-x-2">
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
<span>Continue with Google</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Sign Up Link */}
|
||||
<div className="mt-6 text-center">
|
||||
<p className="text-cream/70 font-elegant-sans text-sm">
|
||||
Don't have an account?{' '}
|
||||
<button className="text-luxury-gold hover:text-luxury-gold/80 font-medium transition-colors duration-300">
|
||||
Create one now
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
201
src/components/RoadmapSection.tsx
Normal file
201
src/components/RoadmapSection.tsx
Normal file
@@ -0,0 +1,201 @@
|
||||
import React from 'react';
|
||||
|
||||
interface RoadmapMilestone {
|
||||
timeframe: string;
|
||||
status: 'completed' | 'in-progress' | 'planned';
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const RoadmapSection: React.FC = () => {
|
||||
const milestones: RoadmapMilestone[] = [
|
||||
{
|
||||
timeframe: 'Q1 2024',
|
||||
status: 'completed',
|
||||
title: 'Core Platform Launch',
|
||||
description: 'Released the foundational business management suite with accounting, CRM, and basic reporting capabilities.'
|
||||
},
|
||||
{
|
||||
timeframe: 'Q2 2024',
|
||||
status: 'completed',
|
||||
title: 'Advanced Analytics & Mobile App',
|
||||
description: 'Introduced predictive analytics, custom dashboards, and native mobile applications for iOS and Android.'
|
||||
},
|
||||
{
|
||||
timeframe: 'Q3 2024',
|
||||
status: 'completed',
|
||||
title: 'Integration Marketplace',
|
||||
description: 'Launched our integration hub with 100+ third-party connectors including banks, payment processors, and popular business tools.'
|
||||
},
|
||||
{
|
||||
timeframe: 'Q4 2024',
|
||||
status: 'in-progress',
|
||||
title: 'AI-Powered Automation',
|
||||
description: 'Implementing intelligent automation for invoice processing, expense categorization, and predictive cash flow forecasting.'
|
||||
},
|
||||
{
|
||||
timeframe: 'Q1 2025',
|
||||
status: 'planned',
|
||||
title: 'Advanced HR & Payroll',
|
||||
description: 'Comprehensive human resources management with automated payroll processing, benefits administration, and performance tracking.'
|
||||
},
|
||||
{
|
||||
timeframe: 'Q2 2025',
|
||||
status: 'planned',
|
||||
title: 'Multi-Currency & Global Support',
|
||||
description: 'Full international business support with multi-currency transactions, localized tax compliance, and regional reporting.'
|
||||
},
|
||||
{
|
||||
timeframe: 'Q3 2025',
|
||||
status: 'planned',
|
||||
title: 'Enterprise Security Suite',
|
||||
description: 'Advanced security features including single sign-on (SSO), two-factor authentication, and enterprise-grade audit trails.'
|
||||
},
|
||||
{
|
||||
timeframe: 'Q4 2025',
|
||||
status: 'planned',
|
||||
title: 'Industry-Specific Solutions',
|
||||
description: 'Specialized modules for retail, manufacturing, healthcare, and professional services with industry-specific workflows.'
|
||||
}
|
||||
];
|
||||
|
||||
const getStatusColor = (status: string): string => {
|
||||
switch (status) {
|
||||
case 'completed':
|
||||
return 'bg-green-500';
|
||||
case 'in-progress':
|
||||
return 'bg-blue-500';
|
||||
case 'planned':
|
||||
return 'bg-gray-400';
|
||||
default:
|
||||
return 'bg-gray-400';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusBorderColor = (status: string): string => {
|
||||
switch (status) {
|
||||
case 'completed':
|
||||
return 'border-green-500';
|
||||
case 'in-progress':
|
||||
return 'border-blue-500';
|
||||
case 'planned':
|
||||
return 'border-gray-400';
|
||||
default:
|
||||
return 'border-gray-400';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="roadmap" className="py-20 lg:py-32 relative">
|
||||
{/* Background overlay */}
|
||||
<div className="absolute inset-0 bg-rich-brown bg-opacity-10"></div>
|
||||
|
||||
<div className="container mx-auto px-6 relative z-10">
|
||||
{/* Section Header */}
|
||||
<div className="text-center mb-20">
|
||||
<div className="flex items-center justify-center mb-8">
|
||||
<div className="w-20 h-0.5 bg-luxury-gold mr-6"></div>
|
||||
<div className="w-3 h-3 bg-luxury-gold rounded-full"></div>
|
||||
<div className="w-20 h-0.5 bg-luxury-gold ml-6"></div>
|
||||
</div>
|
||||
<h2 className="text-4xl md:text-5xl lg:text-6xl font-luxury-serif font-bold text-luxury-gold mb-8 tracking-wide">
|
||||
Our Journey
|
||||
<span className="block text-cream mt-2">Ahead</span>
|
||||
</h2>
|
||||
<p className="text-xl text-cream max-w-4xl mx-auto font-elegant-sans font-light leading-relaxed">
|
||||
We are constantly improving based on feedback from users like you.
|
||||
Here's what we've accomplished and what's coming next.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Timeline */}
|
||||
<div className="relative max-w-4xl mx-auto">
|
||||
{/* Central line */}
|
||||
<div className="absolute left-1/2 transform -translate-x-0.5 h-full w-0.5 bg-luxury-gold opacity-30"></div>
|
||||
|
||||
{milestones.map((milestone, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`relative flex items-center mb-16 ${
|
||||
index % 2 === 0 ? 'flex-row' : 'flex-row-reverse'
|
||||
}`}
|
||||
>
|
||||
{/* Timeline Dot */}
|
||||
<div className="absolute left-1/2 transform -translate-x-1/2 z-10">
|
||||
<div className={`w-6 h-6 rounded-full border-4 ${getStatusColor(milestone.status)} ${getStatusBorderColor(milestone.status)} border-opacity-30`}>
|
||||
{milestone.status === 'completed' && (
|
||||
<svg className="w-3 h-3 text-white absolute top-0.5 left-0.5" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||
</svg>
|
||||
)}
|
||||
{milestone.status === 'in-progress' && (
|
||||
<div className="w-2 h-2 bg-white rounded-full absolute top-1 left-1 animate-pulse"></div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className={`w-5/12 ${index % 2 === 0 ? 'text-right pr-8' : 'text-left pl-8'}`}>
|
||||
{/* Timeframe */}
|
||||
<div className="inline-block px-4 py-2 bg-luxury-gold bg-opacity-20 rounded-full mb-4">
|
||||
<span className="text-luxury-gold font-elegant-sans font-semibold text-sm tracking-wide">
|
||||
{milestone.timeframe}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Milestone Card */}
|
||||
<div className="bg-deep-forest bg-opacity-40 backdrop-blur-sm border border-luxury-gold border-opacity-20 rounded-2xl p-6 hover:bg-opacity-60 hover:border-opacity-40 transition-all duration-300 group">
|
||||
<h3 className="text-xl lg:text-2xl font-luxury-serif font-bold text-luxury-gold mb-4 group-hover:text-opacity-90 transition-colors duration-300">
|
||||
{milestone.title}
|
||||
</h3>
|
||||
<p className="text-cream leading-relaxed font-elegant-sans opacity-90 group-hover:opacity-100 transition-opacity duration-300">
|
||||
{milestone.description}
|
||||
</p>
|
||||
|
||||
{/* Status indicator */}
|
||||
<div className="mt-4 flex items-center gap-2">
|
||||
<div className={`w-2 h-2 rounded-full ${getStatusColor(milestone.status)}`}></div>
|
||||
<span className="text-cream text-sm font-elegant-sans opacity-70 capitalize">
|
||||
{milestone.status === 'in-progress' ? 'In Progress' : milestone.status}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Empty space for alternating layout */}
|
||||
<div className="w-5/12"></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="flex justify-center space-x-8 mt-16">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-green-500 rounded-full"></div>
|
||||
<span className="text-cream font-elegant-sans text-sm">Completed</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-blue-500 rounded-full"></div>
|
||||
<span className="text-cream font-elegant-sans text-sm">In Progress</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-gray-400 rounded-full"></div>
|
||||
<span className="text-cream font-elegant-sans text-sm">Planned</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Call to Action */}
|
||||
<div className="text-center mt-20">
|
||||
<p className="text-cream mb-8 font-elegant-sans text-lg">
|
||||
Want to influence our roadmap? Share your feedback and feature requests.
|
||||
</p>
|
||||
<button className="bg-luxury-gold hover:bg-opacity-90 text-deep-forest px-12 py-4 rounded-xl font-elegant-sans font-semibold text-lg tracking-wide transition-all duration-300 transform hover:scale-105 hover:shadow-2xl focus:outline-none focus:ring-4 focus:ring-luxury-gold focus:ring-opacity-50">
|
||||
Share Feedback
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default RoadmapSection;
|
||||
456
src/components/WaitlistForm.tsx
Normal file
456
src/components/WaitlistForm.tsx
Normal file
@@ -0,0 +1,456 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
interface WaitlistFormProps {
|
||||
isVisible: boolean;
|
||||
onClose: () => void;
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
interface FormData {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
companyName: string;
|
||||
companyType: string;
|
||||
gstRegistered: string;
|
||||
cin: string;
|
||||
panNumber: string;
|
||||
industry: string;
|
||||
goals: string;
|
||||
}
|
||||
|
||||
const WaitlistForm: React.FC<WaitlistFormProps> = ({ isVisible, onClose, onBack }) => {
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
email: '',
|
||||
companyName: '',
|
||||
companyType: '',
|
||||
gstRegistered: '',
|
||||
cin: '',
|
||||
panNumber: '',
|
||||
industry: '',
|
||||
goals: ''
|
||||
});
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [errors, setErrors] = useState<Partial<FormData>>({});
|
||||
|
||||
const companyTypes = [
|
||||
'Pvt Ltd',
|
||||
'LLP',
|
||||
'Partnership',
|
||||
'Sole Proprietorship',
|
||||
'One Person Company (OPC)',
|
||||
'Public Limited Company',
|
||||
'Other'
|
||||
];
|
||||
|
||||
const industries = [
|
||||
'Information Technology',
|
||||
'Finance & Banking',
|
||||
'E-commerce',
|
||||
'Manufacturing',
|
||||
'Healthcare',
|
||||
'Education',
|
||||
'Real Estate',
|
||||
'Retail',
|
||||
'Consulting',
|
||||
'Marketing & Advertising',
|
||||
'Food & Beverage',
|
||||
'Transportation',
|
||||
'Other'
|
||||
];
|
||||
|
||||
const handleInputChange = (field: keyof FormData, value: string) => {
|
||||
setFormData(prev => {
|
||||
const newData = { ...prev, [field]: value };
|
||||
|
||||
// Clear conditional fields when company type changes
|
||||
if (field === 'companyType') {
|
||||
// Clear both fields when company type changes
|
||||
newData.cin = '';
|
||||
newData.panNumber = '';
|
||||
}
|
||||
|
||||
// Clear conditional fields when GST registration changes to "yes"
|
||||
if (field === 'gstRegistered' && value === 'yes') {
|
||||
newData.cin = '';
|
||||
newData.panNumber = '';
|
||||
}
|
||||
|
||||
return newData;
|
||||
});
|
||||
|
||||
// Clear error when user starts typing
|
||||
if (errors[field]) {
|
||||
setErrors(prev => ({ ...prev, [field]: '' }));
|
||||
}
|
||||
};
|
||||
|
||||
const validateForm = (): boolean => {
|
||||
const newErrors: Partial<FormData> = {};
|
||||
|
||||
if (!formData.firstName.trim()) newErrors.firstName = 'First name is required';
|
||||
if (!formData.lastName.trim()) newErrors.lastName = 'Last name is required';
|
||||
if (!formData.email.trim()) {
|
||||
newErrors.email = 'Email is required';
|
||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
||||
newErrors.email = 'Please enter a valid email';
|
||||
}
|
||||
if (!formData.companyName.trim()) newErrors.companyName = 'Company name is required';
|
||||
if (!formData.companyType) newErrors.companyType = 'Company type is required';
|
||||
if (!formData.gstRegistered) newErrors.gstRegistered = 'GST registration status is required';
|
||||
|
||||
// Conditional validation - only when GST is NOT registered
|
||||
if (formData.gstRegistered === 'no') {
|
||||
if (['Pvt Ltd', 'LLP'].includes(formData.companyType)) {
|
||||
// For Private Limited and LLP - CIN is required only when GST is not registered
|
||||
if (!formData.cin.trim()) newErrors.cin = 'CIN is required for Private Limited and LLP companies';
|
||||
} else if (['Partnership', 'Sole Proprietorship', 'One Person Company (OPC)', 'Other'].includes(formData.companyType)) {
|
||||
// For Partnership, Proprietorship, Solo/Individual - PAN is required only when GST is not registered
|
||||
if (!formData.panNumber.trim()) newErrors.panNumber = 'PAN Number is required for this company type';
|
||||
}
|
||||
}
|
||||
|
||||
if (!formData.industry) newErrors.industry = 'Industry is required';
|
||||
if (!formData.goals.trim()) newErrors.goals = 'Please tell us about your goals';
|
||||
|
||||
setErrors(newErrors);
|
||||
return Object.keys(newErrors).length === 0;
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateForm()) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
// Simulate form submission
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
setIsLoading(false);
|
||||
console.log('Waitlist form submitted:', formData);
|
||||
// Handle success - maybe show success message or close form
|
||||
onClose();
|
||||
};
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-[60] flex items-center justify-center bg-deep-forest/80 backdrop-blur-sm">
|
||||
<div className="relative max-w-2xl w-full mx-4 max-h-[90vh] overflow-y-auto">
|
||||
{/* Close Button */}
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute -top-2 -right-2 w-8 h-8 bg-luxury-gold hover:bg-luxury-gold/90 text-deep-forest rounded-full flex items-center justify-center font-bold z-10 transition-all duration-200 shadow-lg"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
||||
{/* Back Button */}
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="absolute -top-2 -left-2 w-8 h-8 bg-luxury-gold/20 hover:bg-luxury-gold/30 text-luxury-gold border border-luxury-gold/30 rounded-full flex items-center justify-center font-bold z-10 transition-all duration-200 shadow-lg"
|
||||
>
|
||||
←
|
||||
</button>
|
||||
|
||||
{/* Form Container */}
|
||||
<div className="bg-gradient-to-br from-deep-forest/95 to-rich-brown/90 backdrop-blur-2xl border border-luxury-gold/30 rounded-2xl shadow-2xl overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="bg-gradient-to-r from-luxury-gold/10 to-luxury-gold/5 px-8 py-6 border-b border-luxury-gold/20">
|
||||
<div className="text-center">
|
||||
<img
|
||||
src="/assets/Dark-Icon-cropped.svg"
|
||||
alt="Pennyzo Icon"
|
||||
className="w-16 h-16 mx-auto mb-4"
|
||||
/>
|
||||
<h2 className="text-luxury-gold font-luxury-serif text-2xl font-bold mb-2">
|
||||
Join Our Exclusive Waitlist
|
||||
</h2>
|
||||
<p className="text-cream/70 font-elegant-sans text-sm">
|
||||
Complete your application to secure your spot
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<div className="p-8">
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* Personal Information Section */}
|
||||
<div>
|
||||
<h3 className="text-luxury-gold font-elegant-sans text-lg font-semibold mb-4 flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
Personal Information
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{/* First Name */}
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
First Name <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.firstName}
|
||||
onChange={(e) => handleInputChange('firstName', e.target.value)}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.firstName ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
placeholder="Enter your first name"
|
||||
/>
|
||||
{errors.firstName && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.firstName}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Last Name */}
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
Last Name <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.lastName}
|
||||
onChange={(e) => handleInputChange('lastName', e.target.value)}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.lastName ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
placeholder="Enter your last name"
|
||||
/>
|
||||
{errors.lastName && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.lastName}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
<div className="mt-4">
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
Email Address <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) => handleInputChange('email', e.target.value)}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.email ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
placeholder="Enter your email address"
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.email}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Company Information Section */}
|
||||
<div>
|
||||
<h3 className="text-luxury-gold font-elegant-sans text-lg font-semibold mb-4 flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||
</svg>
|
||||
Company Information
|
||||
</h3>
|
||||
|
||||
{/* Company Name */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
Company Name <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.companyName}
|
||||
onChange={(e) => handleInputChange('companyName', e.target.value)}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.companyName ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
placeholder="Enter your company name"
|
||||
/>
|
||||
{errors.companyName && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.companyName}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
{/* Company Type */}
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
Company Type <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<select
|
||||
value={formData.companyType}
|
||||
onChange={(e) => handleInputChange('companyType', e.target.value)}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.companyType ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
>
|
||||
<option value="">Select company type</option>
|
||||
{companyTypes.map(type => (
|
||||
<option key={type} value={type} className="bg-deep-forest text-cream">
|
||||
{type}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{errors.companyType && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.companyType}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* GST Registered */}
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
GST Registered <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<div className="flex space-x-4 pt-2">
|
||||
<label className="flex items-center space-x-2 cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name="gstRegistered"
|
||||
value="yes"
|
||||
checked={formData.gstRegistered === 'yes'}
|
||||
onChange={(e) => handleInputChange('gstRegistered', e.target.value)}
|
||||
className="w-4 h-4 text-luxury-gold bg-deep-forest/50 border-luxury-gold/20 focus:ring-luxury-gold/50 focus:ring-2"
|
||||
/>
|
||||
<span className="text-cream/90 font-elegant-sans text-sm">Yes</span>
|
||||
</label>
|
||||
<label className="flex items-center space-x-2 cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name="gstRegistered"
|
||||
value="no"
|
||||
checked={formData.gstRegistered === 'no'}
|
||||
onChange={(e) => handleInputChange('gstRegistered', e.target.value)}
|
||||
className="w-4 h-4 text-luxury-gold bg-deep-forest/50 border-luxury-gold/20 focus:ring-luxury-gold/50 focus:ring-2"
|
||||
/>
|
||||
<span className="text-cream/90 font-elegant-sans text-sm">No</span>
|
||||
</label>
|
||||
</div>
|
||||
{errors.gstRegistered && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.gstRegistered}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Conditional CIN Field - shows when company type is Pvt Ltd or LLP AND GST is NOT registered */}
|
||||
{formData.gstRegistered === 'no' && ['Pvt Ltd', 'LLP'].includes(formData.companyType) && (
|
||||
<div className="mb-4">
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
CIN (Company Identification Number) <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.cin}
|
||||
onChange={(e) => handleInputChange('cin', e.target.value.toUpperCase())}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.cin ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
placeholder="e.g., L12345MH2020PLC123456"
|
||||
maxLength={21}
|
||||
/>
|
||||
{errors.cin && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.cin}</p>
|
||||
)}
|
||||
<p className="text-cream/50 text-xs mt-1 font-elegant-sans">
|
||||
21-digit Corporate Identity Number (required when GST not registered)
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Conditional PAN Number Field - shows for other company types AND GST is NOT registered */}
|
||||
{formData.gstRegistered === 'no' && ['Partnership', 'Sole Proprietorship', 'One Person Company (OPC)', 'Other'].includes(formData.companyType) && (
|
||||
<div className="mb-4">
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
PAN Number <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.panNumber}
|
||||
onChange={(e) => handleInputChange('panNumber', e.target.value.toUpperCase())}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.panNumber ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
placeholder="e.g., ABCDE1234F"
|
||||
maxLength={10}
|
||||
/>
|
||||
{errors.panNumber && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.panNumber}</p>
|
||||
)}
|
||||
<p className="text-cream/50 text-xs mt-1 font-elegant-sans">
|
||||
10-digit Permanent Account Number (required when GST not registered)
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Industry */}
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
Industry <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<select
|
||||
value={formData.industry}
|
||||
onChange={(e) => handleInputChange('industry', e.target.value)}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.industry ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans`}
|
||||
>
|
||||
<option value="">Select your industry</option>
|
||||
{industries.map(industry => (
|
||||
<option key={industry} value={industry} className="bg-deep-forest text-cream">
|
||||
{industry}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{errors.industry && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.industry}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Qualifying Question Section */}
|
||||
<div>
|
||||
<h3 className="text-luxury-gold font-elegant-sans text-lg font-semibold mb-4 flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
|
||||
</svg>
|
||||
Tell Us About Your Goals
|
||||
</h3>
|
||||
|
||||
<div>
|
||||
<label className="block text-cream/90 font-elegant-sans text-sm font-medium mb-2">
|
||||
What do you want to achieve with Pennyzo? <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
value={formData.goals}
|
||||
onChange={(e) => handleInputChange('goals', e.target.value)}
|
||||
rows={4}
|
||||
className={`w-full bg-deep-forest/50 border ${errors.goals ? 'border-red-400' : 'border-luxury-gold/20'} rounded-lg px-4 py-3 text-cream placeholder-cream/40 focus:outline-none focus:ring-2 focus:ring-luxury-gold/50 focus:border-luxury-gold/50 transition-all duration-300 font-elegant-sans resize-none`}
|
||||
placeholder="Tell us about your business goals, challenges you're facing, or what you hope to achieve with our platform..."
|
||||
/>
|
||||
{errors.goals && (
|
||||
<p className="text-red-400 text-xs mt-1 font-elegant-sans">{errors.goals}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="pt-4">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="w-full bg-gradient-to-r from-luxury-gold to-luxury-gold/90 hover:from-luxury-gold/90 hover:to-luxury-gold text-deep-forest font-elegant-sans font-semibold py-4 px-4 rounded-xl transition-all duration-300 transform hover:scale-105 hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 relative overflow-hidden group"
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center space-x-2">
|
||||
<div className="w-5 h-5 border-2 border-deep-forest border-t-transparent rounded-full animate-spin"></div>
|
||||
<span>Submitting Application...</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<span className="relative z-10">Submit Application</span>
|
||||
<div className="absolute inset-0 bg-cream transform scale-x-0 group-hover:scale-x-100 transition-transform origin-left duration-300"></div>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Privacy Notice */}
|
||||
<div className="text-center text-cream/50 font-elegant-sans text-xs">
|
||||
By submitting this form, you agree to our terms of service and privacy policy.
|
||||
Your information will be kept confidential and used only for waitlist management.
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WaitlistForm;
|
||||
123
src/components/WhyPennyzoSection.tsx
Normal file
123
src/components/WhyPennyzoSection.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import React from 'react';
|
||||
|
||||
interface Benefit {
|
||||
image: string;
|
||||
headline: string;
|
||||
description: string;
|
||||
imageAlt: string;
|
||||
}
|
||||
|
||||
const WhyPennyzoSection: React.FC = () => {
|
||||
const benefits: Benefit[] = [
|
||||
{
|
||||
image: '/api/placeholder/600/400',
|
||||
imageAlt: 'Time savings dashboard showing automated processes',
|
||||
headline: 'Save 10+ Hours Every Week',
|
||||
description: 'Stop wasting time on manual data entry and repetitive tasks. Our intelligent automation handles routine operations, invoice processing, and report generation automatically. Focus on strategy and growth while Pennyzo takes care of the busy work that used to consume your valuable time.'
|
||||
},
|
||||
{
|
||||
image: '/api/placeholder/600/400',
|
||||
imageAlt: 'Real-time business analytics and insights dashboard',
|
||||
headline: 'Make Smarter Decisions with Real-Time Insights',
|
||||
description: 'Transform your raw business data into actionable intelligence with our advanced analytics suite. Get instant visibility into cash flow, sales performance, and operational metrics. Our predictive analytics help you spot trends early and make confident decisions that drive growth.'
|
||||
},
|
||||
{
|
||||
image: '/api/placeholder/600/400',
|
||||
imageAlt: 'Unified business platform showing all tools integrated',
|
||||
headline: 'Eliminate Tool Juggling Forever',
|
||||
description: 'Say goodbye to switching between dozens of disconnected apps and losing data in translation. Our unified platform brings together accounting, CRM, HR, inventory, and analytics in one seamless experience. Reduce software costs while improving team productivity and data accuracy.'
|
||||
},
|
||||
{
|
||||
image: '/api/placeholder/600/400',
|
||||
imageAlt: 'Scalable business growth visualization',
|
||||
headline: 'Scale Without the Growing Pains',
|
||||
description: 'Whether you\'re a startup or enterprise, our platform grows with you. Add new users, locations, and features effortlessly. Our robust architecture handles increased transaction volumes and complex workflows without compromising performance or requiring costly migrations.'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="why-pennyzo" className="py-20 lg:py-32 relative">
|
||||
{/* Background overlay */}
|
||||
<div className="absolute inset-0 bg-deep-forest bg-opacity-10"></div>
|
||||
|
||||
<div className="container mx-auto px-6 relative z-10">
|
||||
{/* Section Header */}
|
||||
<div className="text-center mb-20">
|
||||
<div className="flex items-center justify-center mb-8">
|
||||
<div className="w-20 h-0.5 bg-luxury-gold mr-6"></div>
|
||||
<div className="w-3 h-3 bg-luxury-gold rounded-full"></div>
|
||||
<div className="w-20 h-0.5 bg-luxury-gold ml-6"></div>
|
||||
</div>
|
||||
<h2 className="text-4xl md:text-5xl lg:text-6xl font-luxury-serif font-bold text-luxury-gold mb-8 tracking-wide">
|
||||
Why Businesses
|
||||
<span className="block text-cream mt-2">Love Pennyzo</span>
|
||||
</h2>
|
||||
<p className="text-xl text-cream max-w-4xl mx-auto font-elegant-sans font-light leading-relaxed">
|
||||
Discover the tangible benefits that thousands of businesses experience
|
||||
when they choose Pennyzo as their growth partner.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Benefits List */}
|
||||
<div className="space-y-24 lg:space-y-32">
|
||||
{benefits.map((benefit, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`flex flex-col lg:flex-row items-center gap-12 lg:gap-16 ${
|
||||
index % 2 === 1 ? 'lg:flex-row-reverse' : ''
|
||||
}`}
|
||||
>
|
||||
{/* Image */}
|
||||
<div className="flex-1 relative group">
|
||||
<div className="absolute inset-0 bg-luxury-gold opacity-0 group-hover:opacity-10 rounded-2xl blur-xl transition-all duration-500"></div>
|
||||
<div className="relative overflow-hidden rounded-2xl border border-luxury-gold border-opacity-20 group-hover:border-opacity-40 transition-all duration-300">
|
||||
<img
|
||||
src={benefit.image}
|
||||
alt={benefit.imageAlt}
|
||||
className="w-full h-80 lg:h-96 object-cover group-hover:scale-105 transition-transform duration-500"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-deep-forest/20 to-transparent"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="flex-1 text-center lg:text-left">
|
||||
<h3 className="text-3xl lg:text-4xl xl:text-5xl font-luxury-serif font-bold text-luxury-gold mb-6 leading-tight">
|
||||
{benefit.headline}
|
||||
</h3>
|
||||
<p className="text-cream text-lg lg:text-xl leading-relaxed font-elegant-sans opacity-90">
|
||||
{benefit.description}
|
||||
</p>
|
||||
|
||||
{/* Decorative element */}
|
||||
<div className={`mt-8 w-20 h-0.5 bg-luxury-gold opacity-60 ${
|
||||
index % 2 === 1 ? 'lg:ml-0' : 'lg:mr-0'
|
||||
} mx-auto lg:mx-0`}></div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Call to Action */}
|
||||
<div className="text-center mt-24">
|
||||
<div className="max-w-2xl mx-auto mb-10">
|
||||
<p className="text-cream text-xl font-elegant-sans font-light mb-8 leading-relaxed">
|
||||
Ready to experience these benefits for your business?
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-6 items-center justify-center">
|
||||
<button className="bg-luxury-gold hover:bg-opacity-90 text-deep-forest px-12 py-4 rounded-xl font-elegant-sans font-semibold text-lg tracking-wide transition-all duration-300 transform hover:scale-105 hover:shadow-2xl focus:outline-none focus:ring-4 focus:ring-luxury-gold focus:ring-opacity-50 min-w-[220px]">
|
||||
Start Free Trial
|
||||
</button>
|
||||
<button className="border-2 border-luxury-gold text-luxury-gold hover:bg-luxury-gold hover:text-deep-forest px-12 py-4 rounded-xl font-elegant-sans font-semibold text-lg tracking-wide transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-4 focus:ring-luxury-gold focus:ring-opacity-50 min-w-[220px]">
|
||||
See Live Demo
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default WhyPennyzoSection;
|
||||
8
src/index.css
Normal file
8
src/index.css
Normal file
@@ -0,0 +1,8 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* Smooth scrolling for navigation */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
13
src/index.tsx
Normal file
13
src/index.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
const container = document.getElementById('root')!;
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
Reference in New Issue
Block a user