mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 18:52:56 +00:00
835 lines
22 KiB
Markdown
835 lines
22 KiB
Markdown
# Premium Version - Quick Start Guide
|
|
|
|
## 🚀 Implementation in 9 Days
|
|
|
|
This guide provides step-by-step instructions for implementing the premium version toggle system.
|
|
|
|
---
|
|
|
|
## Day 1: Setup & Backend (8 hours)
|
|
|
|
### Morning (4h): Analysis & Configuration
|
|
|
|
#### 1. Review Premium Assets (1h)
|
|
```bash
|
|
cd /home/tdvorak/Desktop/PROG+HTML/Fotbal/fotbal-club/pro
|
|
|
|
# Count assets
|
|
ls css/ | wc -l # 45 CSS files
|
|
ls js/ | wc -l # 41 JS files
|
|
|
|
# Review key files
|
|
cat index.html | head -100
|
|
cat blog.html | head -100
|
|
cat 404.html
|
|
```
|
|
|
|
#### 2. Update Environment Files (30min)
|
|
```bash
|
|
# Edit .env.example
|
|
cat >> .env.example << 'EOF'
|
|
|
|
# Premium Mode Configuration
|
|
PREMIUM_MODE=false
|
|
PREMIUM_HOMEPAGE=false
|
|
PREMIUM_BLOG=false
|
|
PREMIUM_404=false
|
|
PREMIUM_DISABLE_MYUIBRIX=false
|
|
EOF
|
|
|
|
# Copy to .env
|
|
cp .env.example .env
|
|
```
|
|
|
|
#### 3. Update Backend Config (1h)
|
|
**File:** `internal/config/config.go`
|
|
|
|
```go
|
|
type Config struct {
|
|
// ... existing fields
|
|
|
|
PremiumMode bool `env:"PREMIUM_MODE" envDefault:"false"`
|
|
PremiumHomepage bool `env:"PREMIUM_HOMEPAGE" envDefault:"false"`
|
|
PremiumBlog bool `env:"PREMIUM_BLOG" envDefault:"false"`
|
|
Premium404 bool `env:"PREMIUM_404" envDefault:"false"`
|
|
DisableMyUIbrix bool `env:"PREMIUM_DISABLE_MYUIBRIX" envDefault:"false"`
|
|
}
|
|
```
|
|
|
|
#### 4. Create Database Migration (1.5h)
|
|
```bash
|
|
cd database/migrations
|
|
|
|
# Create migration files
|
|
cat > 000XXX_add_premium_settings.up.sql << 'EOF'
|
|
-- Add premium mode settings to settings table
|
|
ALTER TABLE settings ADD COLUMN IF NOT EXISTS premium_mode_active BOOLEAN DEFAULT FALSE;
|
|
ALTER TABLE settings ADD COLUMN IF NOT EXISTS premium_features TEXT;
|
|
ALTER TABLE settings ADD COLUMN IF NOT EXISTS premium_theme_variant VARCHAR(50) DEFAULT 'default';
|
|
|
|
-- Create index for faster queries
|
|
CREATE INDEX IF NOT EXISTS idx_settings_premium_mode ON settings(premium_mode_active);
|
|
|
|
-- Add comment
|
|
COMMENT ON COLUMN settings.premium_mode_active IS 'Whether premium/pro theme is active';
|
|
COMMENT ON COLUMN settings.premium_features IS 'JSON array of enabled premium features';
|
|
EOF
|
|
|
|
cat > 000XXX_add_premium_settings.down.sql << 'EOF'
|
|
-- Rollback premium settings
|
|
DROP INDEX IF EXISTS idx_settings_premium_mode;
|
|
ALTER TABLE settings DROP COLUMN IF EXISTS premium_theme_variant;
|
|
ALTER TABLE settings DROP COLUMN IF EXISTS premium_features;
|
|
ALTER TABLE settings DROP COLUMN IF EXISTS premium_mode_active;
|
|
EOF
|
|
|
|
# Run migration
|
|
make migrate-up
|
|
```
|
|
|
|
### Afternoon (4h): Middleware & Routes
|
|
|
|
#### 5. Create Premium Middleware (2h)
|
|
**File:** `internal/middleware/premium_mode.go`
|
|
|
|
```go
|
|
package middleware
|
|
|
|
import (
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/yourusername/fotbal-club/internal/config"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// PremiumModeMiddleware adds premium mode context to requests
|
|
func PremiumModeMiddleware(cfg *config.Config) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if cfg.PremiumMode {
|
|
c.Set("premium_mode", true)
|
|
c.Set("disable_myuibrix", cfg.DisableMyUIbrix)
|
|
|
|
premiumFeatures := map[string]bool{
|
|
"homepage": cfg.PremiumHomepage,
|
|
"blog": cfg.PremiumBlog,
|
|
"404": cfg.Premium404,
|
|
}
|
|
c.Set("premium_features", premiumFeatures)
|
|
|
|
logrus.WithFields(logrus.Fields{
|
|
"path": c.Request.URL.Path,
|
|
"premium_features": premiumFeatures,
|
|
}).Debug("Premium mode active")
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|
|
```
|
|
|
|
Register middleware in `internal/routes/routes.go`:
|
|
|
|
```go
|
|
func SetupRoutes(router *gin.Engine, cfg *config.Config) {
|
|
// ... existing middleware
|
|
|
|
// Premium mode middleware
|
|
router.Use(middleware.PremiumModeMiddleware(cfg))
|
|
|
|
// ... rest of routes
|
|
}
|
|
```
|
|
|
|
#### 6. Add Static Asset Routes (1h)
|
|
**File:** `internal/routes/routes.go`
|
|
|
|
```go
|
|
// Serve premium static assets
|
|
router.Static("/premium/css", "./pro/css")
|
|
router.Static("/premium/js", "./pro/js")
|
|
router.Static("/premium/img", "./pro/img")
|
|
|
|
// Add cache headers for premium assets
|
|
router.Use(func(c *gin.Context) {
|
|
if strings.HasPrefix(c.Request.URL.Path, "/premium/") {
|
|
c.Header("Cache-Control", "public, max-age=31536000")
|
|
}
|
|
c.Next()
|
|
})
|
|
```
|
|
|
|
#### 7. Extend Settings Controller (1h)
|
|
**File:** `internal/controllers/base_controller.go`
|
|
|
|
```go
|
|
func (ctrl *BaseController) GetPublicSettings(c *gin.Context) {
|
|
settings, err := ctrl.DB.GetSettings()
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
cfg := config.GetConfig()
|
|
|
|
// Add premium mode info
|
|
response := gin.H{
|
|
"settings": settings,
|
|
"premium": gin.H{
|
|
"enabled": cfg.PremiumMode,
|
|
"disable_myuibrix": cfg.DisableMyUIbrix,
|
|
},
|
|
}
|
|
|
|
if cfg.PremiumMode {
|
|
response["premium"].(gin.H)["features"] = gin.H{
|
|
"homepage": cfg.PremiumHomepage,
|
|
"blog": cfg.PremiumBlog,
|
|
"404": cfg.Premium404,
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
```
|
|
|
|
**Test Backend:**
|
|
```bash
|
|
# Restart backend
|
|
make docker-restart-backend
|
|
|
|
# Test settings endpoint
|
|
curl http://localhost:8080/api/v1/settings/public | jq '.premium'
|
|
|
|
# Test static routes
|
|
curl -I http://localhost:8080/premium/css/bizoni.css
|
|
```
|
|
|
|
---
|
|
|
|
## Day 2-3: Frontend Structure (16 hours)
|
|
|
|
### Day 2 Morning (4h): Asset Utilities
|
|
|
|
#### 8. Create Premium Asset Loader (2h)
|
|
**File:** `frontend/src/utils/premiumAssets.ts`
|
|
|
|
```typescript
|
|
// Copy the full implementation from PREMIUM_ARCHITECTURE.md
|
|
// Includes: loadCSS(), loadJS(), loadPremiumAssets(), cleanupPremiumAssets()
|
|
```
|
|
|
|
#### 9. Create Premium Theme Hook (2h)
|
|
**File:** `frontend/src/hooks/usePremiumTheme.ts`
|
|
|
|
```typescript
|
|
// Copy implementation from PREMIUM_ARCHITECTURE.md
|
|
```
|
|
|
|
### Day 2 Afternoon (4h): Premium Layout
|
|
|
|
#### 10. Create Premium Layout Component (4h)
|
|
**File:** `frontend/src/layouts/PremiumLayout.tsx`
|
|
|
|
```typescript
|
|
// Full implementation with asset loading, theme injection
|
|
// See PREMIUM_ARCHITECTURE.md for complete code
|
|
```
|
|
|
|
**Test Layout:**
|
|
```bash
|
|
cd frontend
|
|
npm run dev
|
|
|
|
# Visit http://localhost:3000
|
|
# Check browser console for asset loading logs
|
|
```
|
|
|
|
### Day 3 Morning (4h): Navigation & Footer
|
|
|
|
#### 11. Create Premium Navigation (2h)
|
|
**File:** `frontend/src/components/premium/PremiumNav.tsx`
|
|
|
|
```typescript
|
|
import React from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { useSettings } from '../../hooks/useSettings';
|
|
import { assetUrl } from '../../utils/url';
|
|
|
|
export const PremiumNav: React.FC = () => {
|
|
const { settings } = useSettings();
|
|
|
|
return (
|
|
<div id="lte-nav-wrapper" className="lte-layout-transparent-full lte-nav-color-white">
|
|
<nav className="lte-navbar affix" data-spy="affix" data-offset-top="0">
|
|
<div className="container">
|
|
<div className="lte-navbar-logo">
|
|
<Link to="/" className="lte-logo">
|
|
<img src={settings?.club_logo_url || '/img/logo.png'} alt={settings?.club_name} />
|
|
</Link>
|
|
</div>
|
|
|
|
<div className="lte-navbar-items navbar-collapse" id="navbar">
|
|
<ul className="lte-ul-nav">
|
|
<li><Link to="/"><span>Domů</span></Link></li>
|
|
<li><Link to="/o-nas"><span>O nás</span></Link></li>
|
|
<li><Link to="/blog"><span>Blog</span></Link></li>
|
|
<li><Link to="/kontakt"><span>Kontakt</span></Link></li>
|
|
<li><a href={settings?.gallery_url} target="_blank"><span>Fotogalerie</span></a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<button type="button" className="lte-navbar-toggle" id="open-button">
|
|
<span className="icon-bar top-bar"></span>
|
|
<span className="icon-bar middle-bar"></span>
|
|
<span className="icon-bar bottom-bar"></span>
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
#### 12. Create Premium Footer (2h)
|
|
**File:** `frontend/src/components/premium/PremiumFooter.tsx`
|
|
|
|
```typescript
|
|
// Similar structure to footer in pro/index.html
|
|
// Inject dynamic data from settings
|
|
```
|
|
|
|
### Day 3 Afternoon (4h): Zoom Slider
|
|
|
|
#### 13. Create Zoom Slider Component (4h)
|
|
**File:** `frontend/src/components/premium/ZoomSlider.tsx`
|
|
|
|
**This is the most complex component!**
|
|
|
|
```typescript
|
|
import React, { useEffect, useRef } from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { useArticles } from '../../hooks/useArticles';
|
|
import { useSettings } from '../../hooks/useSettings';
|
|
|
|
interface Slide {
|
|
image: string;
|
|
title: string;
|
|
subtitle?: string;
|
|
link: string;
|
|
}
|
|
|
|
export const ZoomSlider: React.FC = () => {
|
|
const { settings } = useSettings();
|
|
const { articles } = useArticles({ limit: 5, featured: true });
|
|
const sliderRef = useRef<HTMLDivElement>(null);
|
|
|
|
const slides: Slide[] = [
|
|
{
|
|
image: '/premium/img/2025.jpg',
|
|
title: `${settings?.club_name || 'FC'} 2025/2026`,
|
|
link: '/',
|
|
},
|
|
...articles.map(article => ({
|
|
image: article.image_url,
|
|
title: article.title,
|
|
subtitle: article.category?.name,
|
|
link: `/blog/${article.slug}`,
|
|
}))
|
|
];
|
|
|
|
useEffect(() => {
|
|
if (!sliderRef.current || !window.jQuery) return;
|
|
|
|
// Initialize zoom slider
|
|
const $slider = window.jQuery(sliderRef.current);
|
|
$slider.zoomSlider({
|
|
src: slides.map(s => s.image),
|
|
speed: 20000,
|
|
interval: 4500,
|
|
switchSpeed: 7000,
|
|
bullets: 'bottom',
|
|
overlay: 'black',
|
|
});
|
|
|
|
return () => {
|
|
// Cleanup
|
|
if ($slider.data('zoomSlider')) {
|
|
$slider.data('zoomSlider').destroy();
|
|
}
|
|
};
|
|
}, [slides]);
|
|
|
|
return (
|
|
<div
|
|
ref={sliderRef}
|
|
className="lte-slider-zoom zoom-default lte-zs-overlay-black bullets-bottom"
|
|
>
|
|
<div className="container lte-zs-slider-wrapper">
|
|
{slides.map((slide, index) => (
|
|
<div
|
|
key={index}
|
|
className={`lte-zs-slider-inner lte-zs-slide-${index}`}
|
|
data-index={index}
|
|
>
|
|
<div className="elementor elementor-36123">
|
|
<section className="elementor-section">
|
|
<div className="elementor-container">
|
|
<div className="elementor-column">
|
|
<div className="elementor-widget-wrap">
|
|
<h2 className="lte-header">
|
|
{slide.title} {slide.subtitle && <span>{slide.subtitle}</span>}
|
|
</h2>
|
|
<div className="lte-btn-wrap">
|
|
<Link to={slide.link} className="lte-btn btn-lg color-hover-white">
|
|
<span className="lte-btn-inner">
|
|
<span className="lte-btn-before"></span>
|
|
Zjistit více
|
|
</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// TypeScript declarations
|
|
declare global {
|
|
interface Window {
|
|
jQuery: any;
|
|
}
|
|
|
|
interface JQuery {
|
|
zoomSlider(options?: any): JQuery;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Day 4-5: Premium Pages (16 hours)
|
|
|
|
### Day 4: Premium Homepage (8h)
|
|
|
|
#### 14. Create Premium Homepage (8h)
|
|
**File:** `frontend/src/pages/PremiumHomePage.tsx`
|
|
|
|
```typescript
|
|
import React from 'react';
|
|
import { PremiumLayout } from '../layouts/PremiumLayout';
|
|
import { PremiumNav } from '../components/premium/PremiumNav';
|
|
import { PremiumFooter } from '../components/premium/PremiumFooter';
|
|
import { ZoomSlider } from '../components/premium/ZoomSlider';
|
|
import { usePremiumTheme } from '../hooks/usePremiumTheme';
|
|
// Import other sections as needed
|
|
|
|
export const PremiumHomePage: React.FC = () => {
|
|
const { settings } = usePremiumTheme();
|
|
|
|
return (
|
|
<PremiumLayout pageType="home">
|
|
<div className="lte-header-wrapper">
|
|
<PremiumNav />
|
|
</div>
|
|
|
|
{/* Hero Section */}
|
|
<section className="elementor-section">
|
|
<ZoomSlider />
|
|
</section>
|
|
|
|
{/* Next Match Section */}
|
|
<section className="next-match-section">
|
|
{/* Use existing NextMatch component */}
|
|
</section>
|
|
|
|
{/* News Section */}
|
|
<section className="news-section">
|
|
{/* Use existing NewsList component */}
|
|
</section>
|
|
|
|
{/* Other sections... */}
|
|
|
|
<PremiumFooter />
|
|
</PremiumLayout>
|
|
);
|
|
};
|
|
```
|
|
|
|
### Day 5: Blog & 404 Pages (8h)
|
|
|
|
#### 15. Create Premium Blog Page (6h)
|
|
**File:** `frontend/src/pages/PremiumBlogPage.tsx`
|
|
|
|
```typescript
|
|
import React from 'react';
|
|
import { useParams } from 'react-router-dom';
|
|
import { PremiumLayout } from '../layouts/PremiumLayout';
|
|
import { PremiumNav } from '../components/premium/PremiumNav';
|
|
import { PremiumFooter } from '../components/premium/PremiumFooter';
|
|
import { useArticle } from '../hooks/useArticles';
|
|
|
|
export const PremiumBlogPage: React.FC = () => {
|
|
const { slug } = useParams<{ slug: string }>();
|
|
const { article, isLoading } = useArticle(slug);
|
|
|
|
if (isLoading) return <div>Loading...</div>;
|
|
if (!article) return <PremiumNotFoundPage />;
|
|
|
|
return (
|
|
<PremiumLayout pageType="blog">
|
|
<div className="lte-content-wrapper">
|
|
<PremiumNav />
|
|
|
|
<header className="lte-page-header lte-parallax-yes">
|
|
<div className="container">
|
|
<h1 className="lte-header long">{article.title}</h1>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="container main-wrapper">
|
|
<div className="inner-page margin-post">
|
|
<div className="row row-center">
|
|
<div className="col-xl-8">
|
|
<section className="blog-post">
|
|
<article>
|
|
{article.image_url && (
|
|
<div className="image">
|
|
<img src={article.image_url} alt={article.title} />
|
|
</div>
|
|
)}
|
|
|
|
<div className="lte-description">
|
|
<div
|
|
className="text lte-text-page clearfix"
|
|
dangerouslySetInnerHTML={{ __html: article.content }}
|
|
/>
|
|
</div>
|
|
</article>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<PremiumFooter />
|
|
</div>
|
|
</PremiumLayout>
|
|
);
|
|
};
|
|
```
|
|
|
|
#### 16. Create Premium 404 Page (2h)
|
|
**File:** `frontend/src/pages/PremiumNotFoundPage.tsx`
|
|
|
|
```typescript
|
|
// Simple 404 page with premium styling
|
|
// See pro/404.html for structure
|
|
```
|
|
|
|
---
|
|
|
|
## Day 6-7: Integration & Testing (16 hours)
|
|
|
|
### Day 6: Router Integration (8h)
|
|
|
|
#### 17. Update App Router (4h)
|
|
**File:** `frontend/src/App.tsx`
|
|
|
|
```typescript
|
|
import { useSettings } from './hooks/useSettings';
|
|
import { PremiumHomePage } from './pages/PremiumHomePage';
|
|
import { PremiumBlogPage } from './pages/PremiumBlogPage';
|
|
import { PremiumNotFoundPage } from './pages/PremiumNotFoundPage';
|
|
|
|
const App: React.FC = () => {
|
|
const { settings, isLoading } = useSettings();
|
|
|
|
if (isLoading) return <LoadingScreen />;
|
|
|
|
const isPremium = settings?.premium_mode_active;
|
|
|
|
return (
|
|
<BrowserRouter>
|
|
<Routes>
|
|
<Route path="/" element={isPremium ? <PremiumHomePage /> : <HomePage />} />
|
|
<Route path="/blog/:slug" element={isPremium ? <PremiumBlogPage /> : <BlogPage />} />
|
|
<Route path="*" element={isPremium ? <PremiumNotFoundPage /> : <NotFoundPage />} />
|
|
|
|
{/* Other routes stay standard */}
|
|
<Route path="/hraci" element={<PlayersPage />} />
|
|
<Route path="/kontakt" element={<ContactPage />} />
|
|
{/* ... */}
|
|
</Routes>
|
|
</BrowserRouter>
|
|
);
|
|
};
|
|
```
|
|
|
|
#### 18. Test Mode Switching (4h)
|
|
```bash
|
|
# Test 1: Standard Mode
|
|
cd /path/to/project
|
|
echo "PREMIUM_MODE=false" >> .env
|
|
make docker-restart
|
|
# Visit http://localhost:3000 - should see standard site
|
|
|
|
# Test 2: Premium Mode
|
|
echo "PREMIUM_MODE=true" >> .env
|
|
make docker-restart
|
|
# Visit http://localhost:3000 - should see premium site
|
|
|
|
# Test 3: Hybrid Mode
|
|
echo "PREMIUM_MODE=true" >> .env
|
|
echo "PREMIUM_HOMEPAGE=true" >> .env
|
|
echo "PREMIUM_BLOG=false" >> .env
|
|
make docker-restart
|
|
# Homepage premium, blog standard
|
|
```
|
|
|
|
### Day 7: Performance Testing (8h)
|
|
|
|
#### 19. Run Performance Audits (4h)
|
|
```bash
|
|
# Lighthouse audit
|
|
npm install -g lighthouse
|
|
lighthouse http://localhost:3000 --view
|
|
|
|
# Bundle analysis
|
|
cd frontend
|
|
npx webpack-bundle-analyzer stats.json
|
|
|
|
# Load time testing
|
|
curl -w "@curl-format.txt" -o /dev/null -s http://localhost:3000
|
|
```
|
|
|
|
#### 20. Cross-Browser Testing (4h)
|
|
- Test on Chrome, Firefox, Safari, Edge
|
|
- Test mobile responsive (360px, 768px, 1024px)
|
|
- Verify animations work
|
|
- Check console for errors
|
|
|
|
---
|
|
|
|
## Day 8-9: Documentation & Polish (16 hours)
|
|
|
|
### Day 8: Documentation (8h)
|
|
|
|
#### 21. Write User Guide (4h)
|
|
- How to enable premium mode
|
|
- Feature comparison
|
|
- Troubleshooting guide
|
|
|
|
#### 22. Write Developer Guide (4h)
|
|
- Architecture overview
|
|
- How to add new premium pages
|
|
- Customization guide
|
|
|
|
### Day 9: Final Polish (8h)
|
|
|
|
#### 23. Code Review & Cleanup (4h)
|
|
- Remove console.logs
|
|
- Add TypeScript types
|
|
- Fix linter warnings
|
|
- Optimize imports
|
|
|
|
#### 24. Deployment Preparation (4h)
|
|
```bash
|
|
# Update .env.example
|
|
cat >> .env.example << 'EOF'
|
|
# Premium Mode (Production)
|
|
PREMIUM_MODE=true
|
|
PREMIUM_HOMEPAGE=true
|
|
PREMIUM_BLOG=true
|
|
PREMIUM_404=true
|
|
PREMIUM_DISABLE_MYUIBRIX=true
|
|
EOF
|
|
|
|
# Create deployment checklist
|
|
cat > DEPLOYMENT_CHECKLIST.md << 'EOF'
|
|
- [ ] Run database migration
|
|
- [ ] Copy premium assets to /var/www/premium
|
|
- [ ] Update Nginx config
|
|
- [ ] Test in staging
|
|
- [ ] Backup current database
|
|
- [ ] Deploy to production
|
|
- [ ] Test premium mode
|
|
- [ ] Monitor logs
|
|
- [ ] Rollback plan ready
|
|
EOF
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Quick Commands
|
|
|
|
### Enable Premium Mode
|
|
```bash
|
|
# Set environment
|
|
export PREMIUM_MODE=true
|
|
export PREMIUM_HOMEPAGE=true
|
|
export PREMIUM_BLOG=true
|
|
|
|
# Or edit .env file
|
|
echo "PREMIUM_MODE=true" >> .env
|
|
|
|
# Restart
|
|
make docker-restart
|
|
```
|
|
|
|
### Disable Premium Mode
|
|
```bash
|
|
# Edit .env
|
|
sed -i 's/PREMIUM_MODE=true/PREMIUM_MODE=false/' .env
|
|
|
|
# Restart
|
|
make docker-restart
|
|
```
|
|
|
|
### Test Premium Assets
|
|
```bash
|
|
# Test CSS loading
|
|
curl http://localhost:8080/premium/css/bizoni.css | head
|
|
|
|
# Test JS loading
|
|
curl http://localhost:8080/premium/js/jquery.min.js | head
|
|
|
|
# Test images
|
|
curl -I http://localhost:8080/premium/img/logo.png
|
|
```
|
|
|
|
### Debug Premium Mode
|
|
```bash
|
|
# Check settings API
|
|
curl http://localhost:8080/api/v1/settings/public | jq '.premium'
|
|
|
|
# Check backend logs
|
|
docker logs fotbal-club-backend | grep premium
|
|
|
|
# Check frontend console
|
|
# Open browser DevTools → Console → Filter "premium"
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Verification Checklist
|
|
|
|
### Backend
|
|
- [ ] Environment variables added
|
|
- [ ] Database migration successful
|
|
- [ ] Static routes working (`/premium/css/*`, `/premium/js/*`)
|
|
- [ ] Settings API returns premium config
|
|
- [ ] Middleware adds context correctly
|
|
|
|
### Frontend
|
|
- [ ] Premium components created
|
|
- [ ] Asset loader working
|
|
- [ ] Theme hook injecting colors
|
|
- [ ] Navigation working
|
|
- [ ] Zoom slider animating
|
|
- [ ] Blog pages rendering
|
|
- [ ] 404 page showing
|
|
|
|
### Integration
|
|
- [ ] Router switches based on `premium_mode_active`
|
|
- [ ] MyUIbrix disabled when premium active
|
|
- [ ] Standard mode still works
|
|
- [ ] Can toggle between modes
|
|
- [ ] No console errors
|
|
|
|
### Performance
|
|
- [ ] Page load < 3s
|
|
- [ ] Lighthouse score > 85
|
|
- [ ] No memory leaks
|
|
- [ ] Assets cached properly
|
|
|
|
### Cross-Browser
|
|
- [ ] Chrome works
|
|
- [ ] Firefox works
|
|
- [ ] Safari works
|
|
- [ ] Mobile responsive
|
|
|
|
---
|
|
|
|
## 🚨 Common Issues & Solutions
|
|
|
|
### Issue: Premium CSS not loading
|
|
**Solution:**
|
|
```bash
|
|
# Check static route
|
|
curl -I http://localhost:8080/premium/css/bizoni.css
|
|
|
|
# Check file exists
|
|
ls pro/css/bizoni.css
|
|
|
|
# Check Nginx config (production)
|
|
sudo nano /etc/nginx/sites-available/fotbal-club
|
|
```
|
|
|
|
### Issue: Zoom slider not working
|
|
**Solution:**
|
|
```typescript
|
|
// Check jQuery loaded first
|
|
useEffect(() => {
|
|
console.log('jQuery:', typeof window.jQuery);
|
|
console.log('zoomSlider:', typeof window.jQuery?.fn?.zoomSlider);
|
|
}, []);
|
|
|
|
// Load jQuery before zoom slider
|
|
const jsFiles = [
|
|
'/premium/js/jquery.min.js', // FIRST
|
|
'/premium/js/jquery.zoomslider.js', // AFTER jQuery
|
|
];
|
|
```
|
|
|
|
### Issue: Colors not matching club theme
|
|
**Solution:**
|
|
```typescript
|
|
// Check settings loaded
|
|
const { settings } = useSettings();
|
|
console.log('Club colors:', settings?.primary_color);
|
|
|
|
// Check CSS variables applied
|
|
const root = document.documentElement;
|
|
console.log('CSS var:', getComputedStyle(root).getPropertyValue('--lte-main-color'));
|
|
```
|
|
|
|
### Issue: Router not switching
|
|
**Solution:**
|
|
```typescript
|
|
// Debug in App.tsx
|
|
console.log('Settings:', settings);
|
|
console.log('Premium active:', settings?.premium_mode_active);
|
|
console.log('Is premium:', isPremium);
|
|
|
|
// Check API response
|
|
fetch('/api/v1/settings/public')
|
|
.then(r => r.json())
|
|
.then(data => console.log('API response:', data));
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Next Steps After Implementation
|
|
|
|
1. **Train Admins**: Show how to toggle premium mode in settings
|
|
2. **Monitor Performance**: Track Lighthouse scores, load times
|
|
3. **Collect Feedback**: Survey users on premium vs standard
|
|
4. **Plan Enhancements**: Additional premium pages, more templates
|
|
5. **Document Customizations**: How to modify premium templates
|
|
|
|
---
|
|
|
|
## 🎉 Success Criteria
|
|
|
|
✅ **Backend:** Environment toggle works, assets served correctly
|
|
✅ **Frontend:** Premium pages render, animations work, responsive
|
|
✅ **Integration:** Can switch modes without errors
|
|
✅ **Performance:** Load time < 3s, Lighthouse > 85
|
|
✅ **Documentation:** User guide, developer guide, troubleshooting
|
|
|
|
**Congratulations! Premium mode is live!** 🚀
|