Files
smoothschedule/legacy_reference/frontend/src/components/TrialBanner.tsx
poduck 2e111364a2 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>
2025-11-27 01:43:20 -05:00

93 lines
3.1 KiB
TypeScript

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Clock, X, ArrowRight, Sparkles } from 'lucide-react';
import { Business } from '../types';
interface TrialBannerProps {
business: Business;
}
/**
* TrialBanner Component
* Shows at the top of the business layout when trial is active
* Displays days remaining and upgrade CTA
* Dismissible but reappears on page reload
*/
const TrialBanner: React.FC<TrialBannerProps> = ({ business }) => {
const { t } = useTranslation();
const [isDismissed, setIsDismissed] = useState(false);
const navigate = useNavigate();
if (isDismissed || !business.isTrialActive || !business.daysLeftInTrial) {
return null;
}
const daysLeft = business.daysLeftInTrial;
const isUrgent = daysLeft <= 3;
const trialEndDate = business.trialEnd ? new Date(business.trialEnd).toLocaleDateString() : '';
const handleUpgrade = () => {
navigate('/upgrade');
};
const handleDismiss = () => {
setIsDismissed(true);
};
return (
<div
className={`relative ${
isUrgent
? 'bg-gradient-to-r from-red-500 to-orange-500'
: 'bg-gradient-to-r from-blue-600 to-blue-500'
} text-white shadow-md`}
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3">
<div className="flex items-center justify-between gap-4">
{/* Left: Trial Info */}
<div className="flex items-center gap-3 flex-1">
<div className={`p-2 rounded-full ${isUrgent ? 'bg-white/20' : 'bg-white/20'} backdrop-blur-sm`}>
{isUrgent ? (
<Clock size={20} className="animate-pulse" />
) : (
<Sparkles size={20} />
)}
</div>
<div className="flex-1">
<p className="font-semibold text-sm sm:text-base">
{t('trial.banner.title')} - {t('trial.banner.daysLeft', { days: daysLeft })}
</p>
<p className="text-xs sm:text-sm text-white/90 hidden sm:block">
{t('trial.banner.expiresOn', { date: trialEndDate })}
</p>
</div>
</div>
{/* Right: CTA Button */}
<div className="flex items-center gap-2">
<button
onClick={handleUpgrade}
className="group px-4 py-2 bg-white text-blue-600 hover:bg-blue-50 rounded-lg font-semibold text-sm transition-all shadow-lg hover:shadow-xl flex items-center gap-2"
>
{t('trial.banner.upgradeNow')}
<ArrowRight size={16} className="group-hover:translate-x-1 transition-transform" />
</button>
{/* Dismiss Button */}
<button
onClick={handleDismiss}
className="p-2 hover:bg-white/20 rounded-lg transition-colors"
aria-label={t('trial.banner.dismiss')}
>
<X size={20} />
</button>
</div>
</div>
</div>
</div>
);
};
export default TrialBanner;