improve: enhance promo offers visibility and design

- Move PromoOffersSection higher on dashboard (after subscription card)
- Replace SVG icons with expressive emojis (🏷️ for discounts, 🚀 for test access, 🎁 for general)
- Redesign activate button with gradient, shimmer effect, and hover animation
- Add shadow glow effect to make button more clickable
This commit is contained in:
c0mrade
2026-02-02 06:26:10 +03:00
parent f73579b37f
commit dee89fb118
2 changed files with 13 additions and 40 deletions

View File

@@ -4,16 +4,6 @@ import { useTranslation } from 'react-i18next';
import { promoApi, PromoOffer } from '../api/promo'; import { promoApi, PromoOffer } from '../api/promo';
// Icons // Icons
const GiftIcon = () => (
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M21 11.25v8.25a1.5 1.5 0 01-1.5 1.5H5.25a1.5 1.5 0 01-1.5-1.5v-8.25M12 4.875A2.625 2.625 0 109.375 7.5H12m0-2.625V7.5m0-2.625A2.625 2.625 0 1114.625 7.5H12m0 0V21m-8.625-9.75h18c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125h-18c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z"
/>
</svg>
);
const ClockIcon = () => ( const ClockIcon = () => (
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}> <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path <path
@@ -24,32 +14,12 @@ const ClockIcon = () => (
</svg> </svg>
); );
const SparklesIcon = () => (
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"
/>
</svg>
);
const CheckIcon = () => ( const CheckIcon = () => (
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}> <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" /> <path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
</svg> </svg>
); );
const ServerIcon = () => (
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z"
/>
</svg>
);
// Helper functions // Helper functions
const formatTimeLeft = ( const formatTimeLeft = (
expiresAt: string, expiresAt: string,
@@ -81,9 +51,10 @@ const formatTimeLeft = (
return `${minutes}${t('promo.time.minutes')}`; return `${minutes}${t('promo.time.minutes')}`;
}; };
const getOfferIcon = (effectType: string) => { const getOfferIcon = (effectType: string, discountPercent?: number | null) => {
if (effectType === 'test_access') return <ServerIcon />; if (effectType === 'test_access') return <span className="text-2xl">🚀</span>;
return <SparklesIcon />; if (discountPercent) return <span className="text-2xl">🏷</span>;
return <span className="text-2xl">🎁</span>;
}; };
const getOfferTitle = ( const getOfferTitle = (
@@ -235,8 +206,8 @@ export default function PromoOffersSection({ className = '' }: PromoOffersSectio
className="card border-orange-500/30 bg-gradient-to-br from-orange-500/5 to-transparent transition-colors hover:border-orange-500/50" className="card border-orange-500/30 bg-gradient-to-br from-orange-500/5 to-transparent transition-colors hover:border-orange-500/50"
> >
<div className="flex items-start gap-4"> <div className="flex items-start gap-4">
<div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl bg-orange-500/20 text-orange-400"> <div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-orange-500/30 to-amber-500/20">
{getOfferIcon(offer.effect_type)} {getOfferIcon(offer.effect_type, offer.discount_percent)}
</div> </div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="mb-1 flex items-center gap-2"> <div className="mb-1 flex items-center gap-2">
@@ -258,8 +229,10 @@ export default function PromoOffersSection({ className = '' }: PromoOffersSectio
<button <button
onClick={() => handleClaim(offer.id)} onClick={() => handleClaim(offer.id)}
disabled={claimingId === offer.id} disabled={claimingId === offer.id}
className="flex items-center gap-2 rounded-lg bg-orange-500 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-orange-600 disabled:cursor-not-allowed disabled:opacity-50" className="group relative flex items-center gap-2 overflow-hidden rounded-lg bg-gradient-to-r from-orange-500 to-amber-500 px-5 py-2.5 text-sm font-semibold text-white shadow-lg shadow-orange-500/25 transition-all hover:scale-105 hover:shadow-xl hover:shadow-orange-500/30 active:scale-100 disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:scale-100"
> >
{/* Shimmer effect */}
<span className="absolute inset-0 -translate-x-full bg-gradient-to-r from-transparent via-white/20 to-transparent transition-transform duration-1000 group-hover:translate-x-full" />
{claimingId === offer.id ? ( {claimingId === offer.id ? (
<> <>
<div className="h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" /> <div className="h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" />
@@ -267,7 +240,7 @@ export default function PromoOffersSection({ className = '' }: PromoOffersSectio
</> </>
) : ( ) : (
<> <>
<GiftIcon /> <span className="text-lg">🎁</span>
<span>{t('promo.offers.activate')}</span> <span>{t('promo.offers.activate')}</span>
</> </>
)} )}

View File

@@ -421,6 +421,9 @@ export default function Dashboard() {
</div> </div>
) : null} ) : null}
{/* Promo Offers - показываем сразу после карточки подписки */}
<PromoOffersSection />
{/* Stats Grid */} {/* Stats Grid */}
<div className="bento-grid"> <div className="bento-grid">
{/* Balance */} {/* Balance */}
@@ -615,9 +618,6 @@ export default function Dashboard() {
</div> </div>
)} )}
{/* Promo Offers */}
<PromoOffersSection />
{/* Fortune Wheel Banner */} {/* Fortune Wheel Banner */}
{wheelConfig?.is_enabled && ( {wheelConfig?.is_enabled && (
<Link to="/wheel" className="bento-card-hover group flex items-center justify-between"> <Link to="/wheel" className="bento-card-hover group flex items-center justify-between">