Initial commit: SmoothSchedule multi-tenant scheduling platform

This commit includes:
- Django backend with multi-tenancy (django-tenants)
- React + TypeScript frontend with Vite
- Platform administration API with role-based access control
- Authentication system with token-based auth
- Quick login dev tools for testing different user roles
- CORS and CSRF configuration for local development
- Docker development environment setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
poduck
2025-11-27 01:43:20 -05:00
commit 2e111364a2
567 changed files with 96410 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import PricingCard from '../../components/marketing/PricingCard';
import FAQAccordion from '../../components/marketing/FAQAccordion';
import CTASection from '../../components/marketing/CTASection';
const PricingPage: React.FC = () => {
const { t } = useTranslation();
const [billingPeriod, setBillingPeriod] = useState<'monthly' | 'annual'>('monthly');
const faqItems = [
{
question: t('marketing.faq.questions.freePlan.question'),
answer: t('marketing.faq.questions.freePlan.answer'),
},
{
question: t('marketing.faq.questions.cancel.question'),
answer: t('marketing.faq.questions.cancel.answer'),
},
{
question: t('marketing.faq.questions.payment.question'),
answer: t('marketing.faq.questions.payment.answer'),
},
{
question: t('marketing.faq.questions.migrate.question'),
answer: t('marketing.faq.questions.migrate.answer'),
},
{
question: t('marketing.faq.questions.support.question'),
answer: t('marketing.faq.questions.support.answer'),
},
{
question: t('marketing.faq.questions.customDomain.question'),
answer: t('marketing.faq.questions.customDomain.answer'),
},
];
return (
<div>
{/* Header Section */}
<section className="py-20 lg:py-28 bg-gradient-to-br from-white via-brand-50/30 to-white dark:from-gray-900 dark:via-gray-900 dark:to-gray-900">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-4">
{t('marketing.pricing.title')}
</h1>
<p className="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
{t('marketing.pricing.subtitle')}
</p>
</div>
{/* Billing Toggle */}
<div className="flex flex-wrap items-center justify-center gap-3 mb-12">
<div className="flex items-center gap-3">
<span
className={`text-sm font-medium whitespace-nowrap transition-colors ${
billingPeriod === 'monthly'
? 'text-gray-900 dark:text-white'
: 'text-gray-500 dark:text-gray-400'
}`}
>
{t('marketing.pricing.monthly')}
</span>
<button
onClick={() => setBillingPeriod(billingPeriod === 'monthly' ? 'annual' : 'monthly')}
className="relative flex-shrink-0 w-12 h-6 bg-brand-600 rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900"
aria-label="Toggle billing period"
>
<span
className={`absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition-transform duration-200 ${
billingPeriod === 'annual' ? 'translate-x-6' : 'translate-x-0'
}`}
/>
</button>
<span
className={`text-sm font-medium whitespace-nowrap transition-colors ${
billingPeriod === 'annual'
? 'text-gray-900 dark:text-white'
: 'text-gray-500 dark:text-gray-400'
}`}
>
{t('marketing.pricing.annual')}
</span>
</div>
{billingPeriod === 'annual' && (
<span className="px-2 py-1 text-xs font-semibold text-brand-700 bg-brand-100 dark:bg-brand-900/30 dark:text-brand-300 rounded-full whitespace-nowrap">
{t('marketing.pricing.annualSave')}
</span>
)}
</div>
{/* Pricing Cards */}
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
<PricingCard tier="free" billingPeriod={billingPeriod} />
<PricingCard tier="professional" billingPeriod={billingPeriod} highlighted />
<PricingCard tier="business" billingPeriod={billingPeriod} />
<PricingCard tier="enterprise" billingPeriod={billingPeriod} />
</div>
</div>
</section>
{/* FAQ Section */}
<section className="py-20 lg:py-28 bg-gray-50 dark:bg-gray-800/50">
<div className="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
{t('marketing.faq.title')}
</h2>
<p className="text-lg text-gray-600 dark:text-gray-400">
{t('marketing.faq.subtitle')}
</p>
</div>
<FAQAccordion items={faqItems} />
</div>
</section>
{/* CTA Section */}
<CTASection variant="minimal" />
</div>
);
};
export default PricingPage;