Style: Unify cart Continue Shopping button with wishlist style

Updated cart dropdown Continue Shopping buttons to use btn-outline
class (matching wishlist style) instead of btn-text across all pages.

Changes:
- shop.html: btn-text → btn-outline
- contact.html: btn-text → btn-outline
- product.html: btn-text → btn-outline
- about.html: btn-text → btn-outline

All cart Continue Shopping buttons now have consistent styling
with the wishlist Continue Shopping button (purple outline style).
This commit is contained in:
Local Server
2026-01-14 20:47:32 -06:00
parent a888d70174
commit f818fff3a5
7 changed files with 114 additions and 46 deletions

View File

@@ -1,4 +1,5 @@
# Performance Optimization Report # Performance Optimization Report
## SkyArtShop Website Performance Enhancements ## SkyArtShop Website Performance Enhancements
**Date:** January 14, 2026 **Date:** January 14, 2026
@@ -10,6 +11,7 @@
## Executive Summary ## Executive Summary
Successfully optimized SkyArtShop for maximum performance without changing any functionality. All optimizations focus on: Successfully optimized SkyArtShop for maximum performance without changing any functionality. All optimizations focus on:
- Faster load times - Faster load times
- Reduced memory usage - Reduced memory usage
- Efficient API calls - Efficient API calls
@@ -17,6 +19,7 @@ Successfully optimized SkyArtShop for maximum performance without changing any f
- Intelligent caching - Intelligent caching
**Key Results:** **Key Results:**
- ✅ API response times: 7-12ms (excellent performance) - ✅ API response times: 7-12ms (excellent performance)
- ✅ Backend cache providing 0-41% performance gains - ✅ Backend cache providing 0-41% performance gains
- ✅ All 30+ database indexes verified and optimized - ✅ All 30+ database indexes verified and optimized
@@ -29,6 +32,7 @@ Successfully optimized SkyArtShop for maximum performance without changing any f
### New Indexes Created ### New Indexes Created
#### Products Table #### Products Table
```sql ```sql
-- Slug lookup optimization (for product detail pages) -- Slug lookup optimization (for product detail pages)
CREATE INDEX idx_products_slug ON products(slug) WHERE isactive = true; CREATE INDEX idx_products_slug ON products(slug) WHERE isactive = true;
@@ -45,6 +49,7 @@ CREATE INDEX idx_products_active_category ON products(isactive, category)
**Impact:** Product queries now use optimized index scans instead of full table scans. **Impact:** Product queries now use optimized index scans instead of full table scans.
#### Blog Posts Table #### Blog Posts Table
```sql ```sql
-- Slug lookup for individual blog posts -- Slug lookup for individual blog posts
CREATE INDEX idx_blogposts_slug ON blogposts(slug) WHERE ispublished = true; CREATE INDEX idx_blogposts_slug ON blogposts(slug) WHERE ispublished = true;
@@ -57,6 +62,7 @@ CREATE INDEX idx_blogposts_published ON blogposts(ispublished, createdat DESC)
**Impact:** Blog post queries execute 40-60% faster with index-only scans. **Impact:** Blog post queries execute 40-60% faster with index-only scans.
#### Portfolio Projects Table #### Portfolio Projects Table
```sql ```sql
-- Composite index for main portfolio query -- Composite index for main portfolio query
CREATE INDEX idx_portfolio_active_display CREATE INDEX idx_portfolio_active_display
@@ -89,6 +95,7 @@ VACUUM ANALYZE;
### New File: `/website/public/assets/js/api-cache.js` ### New File: `/website/public/assets/js/api-cache.js`
**Features:** **Features:**
- **Intelligent Caching:** Automatic caching of GET requests with configurable TTL - **Intelligent Caching:** Automatic caching of GET requests with configurable TTL
- **Request Deduplication:** Multiple simultaneous requests to same endpoint only fetch once - **Request Deduplication:** Multiple simultaneous requests to same endpoint only fetch once
- **Memory Management:** Automatic cleanup of expired cache entries every 60 seconds - **Memory Management:** Automatic cleanup of expired cache entries every 60 seconds
@@ -155,6 +162,7 @@ const response = await window.apiCache.fetch('/api/products');
### Script Loading Order ### Script Loading Order
All pages now load scripts in this optimized order: All pages now load scripts in this optimized order:
```html ```html
<script src="/assets/js/api-cache.js"></script> <!-- Load cache first --> <script src="/assets/js/api-cache.js"></script> <!-- Load cache first -->
<script src="/assets/js/shop-system.js"></script> <script src="/assets/js/shop-system.js"></script>
@@ -169,11 +177,13 @@ All pages now load scripts in this optimized order:
The backend already had excellent performance optimizations in place: The backend already had excellent performance optimizations in place:
### Existing Backend Caching ### Existing Backend Caching
- **Route-level caching:** Using `cacheMiddleware(ttl)` - **Route-level caching:** Using `cacheMiddleware(ttl)`
- **Query-level caching:** In-memory cache for SELECT queries - **Query-level caching:** In-memory cache for SELECT queries
- **Response optimization:** Field filtering, pagination, ETag generation - **Response optimization:** Field filtering, pagination, ETag generation
### Existing Database Optimizations ### Existing Database Optimizations
- **Connection pooling:** 10-30 connections with keepAlive - **Connection pooling:** 10-30 connections with keepAlive
- **Query timeout:** 30s safeguard - **Query timeout:** 30s safeguard
- **Prepared statements:** Automatic query plan caching - **Prepared statements:** Automatic query plan caching
@@ -182,6 +192,7 @@ The backend already had excellent performance optimizations in place:
### API Route Performance ### API Route Performance
All routes use: All routes use:
```javascript ```javascript
// Cached for 5-30 minutes depending on endpoint // Cached for 5-30 minutes depending on endpoint
cacheMiddleware(300000), // 5 minutes cacheMiddleware(300000), // 5 minutes
@@ -210,6 +221,7 @@ Automated testing of all endpoints with timing:
### Test Results ### Test Results
#### API Endpoints (Cold vs Warm) #### API Endpoints (Cold vs Warm)
``` ```
/api/products /api/products
HTTP 200 | Cold: 12ms | Warm: 7ms | Gain: 41% HTTP 200 | Cold: 12ms | Warm: 7ms | Gain: 41%
@@ -233,6 +245,7 @@ Automated testing of all endpoints with timing:
**Analysis:** Responses are already extremely fast (7-12ms). Backend cache shows up to 41% improvement on complex queries. **Analysis:** Responses are already extremely fast (7-12ms). Backend cache shows up to 41% improvement on complex queries.
#### Page Load Times #### Page Load Times
``` ```
/home | HTTP 200 | Load: 8ms /home | HTTP 200 | Load: 8ms
/shop | HTTP 200 | Load: 7ms /shop | HTTP 200 | Load: 7ms
@@ -249,21 +262,26 @@ Automated testing of all endpoints with timing:
### All Endpoints Verified ✅ ### All Endpoints Verified ✅
**Products API:** **Products API:**
- ✅ GET /api/products - Returns all products with images - ✅ GET /api/products - Returns all products with images
- ✅ GET /api/products/featured - Returns 4 featured products - ✅ GET /api/products/featured - Returns 4 featured products
- ✅ GET /api/products/:id - Returns single product by ID/slug - ✅ GET /api/products/:id - Returns single product by ID/slug
- ✅ GET /api/categories - Returns unique categories - ✅ GET /api/categories - Returns unique categories
**Portfolio API:** **Portfolio API:**
- ✅ GET /api/portfolio/projects - Returns 6 projects with images - ✅ GET /api/portfolio/projects - Returns 6 projects with images
**Blog API:** **Blog API:**
- ✅ GET /api/blog/posts - Returns 3 published posts - ✅ GET /api/blog/posts - Returns 3 published posts
**Pages API:** **Pages API:**
- ✅ GET /api/pages - Returns all active custom pages - ✅ GET /api/pages - Returns all active custom pages
### Response Format (Consistent) ### Response Format (Consistent)
```json ```json
{ {
"success": true, "success": true,
@@ -273,7 +291,9 @@ Automated testing of all endpoints with timing:
``` ```
### Error Handling ### Error Handling
All pages implement proper error handling: All pages implement proper error handling:
```javascript ```javascript
try { try {
const response = await window.apiCache.fetch('/api/...'); const response = await window.apiCache.fetch('/api/...');
@@ -294,12 +314,14 @@ try {
### Frontend Memory Management ### Frontend Memory Management
**API Cache Memory:** **API Cache Memory:**
- Maximum 500 cached entries (configurable) - Maximum 500 cached entries (configurable)
- Automatic cleanup every 60 seconds - Automatic cleanup every 60 seconds
- Expired entries removed from memory - Expired entries removed from memory
- Memory-efficient crypto-based cache keys (MD5 hash) - Memory-efficient crypto-based cache keys (MD5 hash)
**Cache Statistics Available:** **Cache Statistics Available:**
```javascript ```javascript
// Get cache stats in browser console // Get cache stats in browser console
window.apiCache.getStats(); window.apiCache.getStats();
@@ -307,6 +329,7 @@ window.apiCache.getStats();
``` ```
**Manual Cache Control:** **Manual Cache Control:**
```javascript ```javascript
// Clear specific entry // Clear specific entry
window.apiCache.clear('/api/products'); window.apiCache.clear('/api/products');
@@ -318,6 +341,7 @@ window.clearAPICache();
### Backend Memory Management ### Backend Memory Management
Already optimized: Already optimized:
- Connection pool limits (max 30) - Connection pool limits (max 30)
- Query cache size limits - Query cache size limits
- Automatic connection recycling - Automatic connection recycling
@@ -328,18 +352,21 @@ Already optimized:
## 8. Load Time Improvements ## 8. Load Time Improvements
### Before Optimization (Estimated) ### Before Optimization (Estimated)
- Cold API calls: ~15-20ms - Cold API calls: ~15-20ms
- Repeated API calls: ~15-20ms (no caching) - Repeated API calls: ~15-20ms (no caching)
- Database queries: Full table scans on some queries - Database queries: Full table scans on some queries
- Multiple simultaneous requests: Duplicate network calls - Multiple simultaneous requests: Duplicate network calls
### After Optimization ### After Optimization
- Cold API calls: 7-12ms (backend cache + indexes) - Cold API calls: 7-12ms (backend cache + indexes)
- Repeated API calls: <1ms (frontend cache hit) - Repeated API calls: <1ms (frontend cache hit)
- Database queries: Index-only scans - Database queries: Index-only scans
- Multiple simultaneous requests: Deduplicated (single fetch) - Multiple simultaneous requests: Deduplicated (single fetch)
### Improvement Summary ### Improvement Summary
- **Database queries:** 40-60% faster with new indexes - **Database queries:** 40-60% faster with new indexes
- **API responses:** Already excellent (7-12ms) - **API responses:** Already excellent (7-12ms)
- **Frontend cache hits:** Near-instant (<1ms) - **Frontend cache hits:** Near-instant (<1ms)
@@ -353,6 +380,7 @@ Already optimized:
### Browser Console Logging ### Browser Console Logging
Cache activity is logged for monitoring: Cache activity is logged for monitoring:
```javascript ```javascript
[Cache] FETCH: /api/products [Cache] FETCH: /api/products
[Cache] SET: /api/products (TTL: 300000ms) [Cache] SET: /api/products (TTL: 300000ms)
@@ -364,12 +392,14 @@ Cache activity is logged for monitoring:
### Performance Monitoring ### Performance Monitoring
Check cache statistics: Check cache statistics:
```javascript ```javascript
// In browser console // In browser console
console.log(window.apiCache.getStats()); console.log(window.apiCache.getStats());
``` ```
Output: Output:
```javascript ```javascript
{ {
size: 6, // Cached entries size: 6, // Cached entries
@@ -389,11 +419,13 @@ Output:
### Database Monitoring ### Database Monitoring
Verify indexes: Verify indexes:
```bash ```bash
./test-api-performance.sh ./test-api-performance.sh
``` ```
Check query performance: Check query performance:
```sql ```sql
-- In PostgreSQL -- In PostgreSQL
EXPLAIN ANALYZE SELECT * FROM products WHERE isactive = true; EXPLAIN ANALYZE SELECT * FROM products WHERE isactive = true;
@@ -404,30 +436,35 @@ EXPLAIN ANALYZE SELECT * FROM products WHERE isactive = true;
## 10. Best Practices Implemented ## 10. Best Practices Implemented
### ✅ Database ### ✅ Database
- Partial indexes with WHERE clauses (smaller, faster) - Partial indexes with WHERE clauses (smaller, faster)
- Composite indexes for multi-column queries - Composite indexes for multi-column queries
- Regular ANALYZE for updated statistics - Regular ANALYZE for updated statistics
- VACUUM for space reclamation - VACUUM for space reclamation
### ✅ Caching ### ✅ Caching
- Appropriate TTL per data type - Appropriate TTL per data type
- Automatic cache invalidation - Automatic cache invalidation
- Request deduplication - Request deduplication
- Memory-efficient storage - Memory-efficient storage
### ✅ Frontend ### ✅ Frontend
- Minimal dependencies - Minimal dependencies
- Progressive enhancement - Progressive enhancement
- Error boundaries - Error boundaries
- User-friendly error messages - User-friendly error messages
### ✅ Backend ### ✅ Backend
- Query timeout safeguards - Query timeout safeguards
- Connection pooling - Connection pooling
- Response compression - Response compression
- Security headers (Helmet.js) - Security headers (Helmet.js)
### ✅ Testing ### ✅ Testing
- Automated performance testing - Automated performance testing
- Cold vs warm comparison - Cold vs warm comparison
- Comprehensive endpoint coverage - Comprehensive endpoint coverage
@@ -440,6 +477,7 @@ EXPLAIN ANALYZE SELECT * FROM products WHERE isactive = true;
### Cache Management ### Cache Management
**Clear frontend cache:** **Clear frontend cache:**
```javascript ```javascript
// In browser console // In browser console
window.clearAPICache(); window.clearAPICache();
@@ -447,6 +485,7 @@ window.clearAPICache();
**Adjust cache TTL:** **Adjust cache TTL:**
Edit `/website/public/assets/js/api-cache.js`: Edit `/website/public/assets/js/api-cache.js`:
```javascript ```javascript
this.ttlConfig = { this.ttlConfig = {
'/api/products': 5 * 60 * 1000, // Change to desired ms '/api/products': 5 * 60 * 1000, // Change to desired ms
@@ -457,12 +496,14 @@ this.ttlConfig = {
### Database Maintenance ### Database Maintenance
**Add new indexes:** **Add new indexes:**
```sql ```sql
-- In backend/optimize-database-indexes.sql -- In backend/optimize-database-indexes.sql
CREATE INDEX CONCURRENTLY idx_name ON table(column); CREATE INDEX CONCURRENTLY idx_name ON table(column);
``` ```
**Update statistics:** **Update statistics:**
```bash ```bash
PGPASSWORD=SkyArt2025Pass psql -h localhost -U skyartapp -d skyartshop -c "ANALYZE;" PGPASSWORD=SkyArt2025Pass psql -h localhost -U skyartapp -d skyartshop -c "ANALYZE;"
``` ```
@@ -470,12 +511,14 @@ PGPASSWORD=SkyArt2025Pass psql -h localhost -U skyartapp -d skyartshop -c "ANALY
### Performance Testing ### Performance Testing
**Run comprehensive test:** **Run comprehensive test:**
```bash ```bash
cd /media/pts/Website/SkyArtShop cd /media/pts/Website/SkyArtShop
./test-api-performance.sh ./test-api-performance.sh
``` ```
**Monitor PM2 logs:** **Monitor PM2 logs:**
```bash ```bash
pm2 logs skyartshop pm2 logs skyartshop
``` ```
@@ -485,11 +528,13 @@ pm2 logs skyartshop
## 12. Files Modified ## 12. Files Modified
### New Files Created ### New Files Created
-`backend/optimize-database-indexes.sql` - Database optimization script -`backend/optimize-database-indexes.sql` - Database optimization script
-`website/public/assets/js/api-cache.js` - Frontend caching system -`website/public/assets/js/api-cache.js` - Frontend caching system
-`test-api-performance.sh` - Automated testing script -`test-api-performance.sh` - Automated testing script
### Modified Files ### Modified Files
-`website/public/portfolio.html` - Added api-cache integration -`website/public/portfolio.html` - Added api-cache integration
-`website/public/blog.html` - Added api-cache integration -`website/public/blog.html` - Added api-cache integration
-`website/public/shop.html` - Added api-cache integration -`website/public/shop.html` - Added api-cache integration
@@ -519,6 +564,7 @@ pm2 logs skyartshop
While current performance is excellent, these could provide marginal gains: While current performance is excellent, these could provide marginal gains:
### Advanced Optimizations (Optional) ### Advanced Optimizations (Optional)
1. **Image Lazy Loading:** Already implemented with `loading="lazy"` 1. **Image Lazy Loading:** Already implemented with `loading="lazy"`
2. **CDN Integration:** Consider CDN for static assets 2. **CDN Integration:** Consider CDN for static assets
3. **Service Worker:** Add offline caching for PWA 3. **Service Worker:** Add offline caching for PWA
@@ -526,6 +572,7 @@ While current performance is excellent, these could provide marginal gains:
5. **WebP Images:** Convert images to WebP format 5. **WebP Images:** Convert images to WebP format
### Monitoring (Optional) ### Monitoring (Optional)
1. **Real User Monitoring:** Track actual user load times 1. **Real User Monitoring:** Track actual user load times
2. **Error Tracking:** Sentry or similar for production errors 2. **Error Tracking:** Sentry or similar for production errors
3. **Analytics:** Track cache hit rates in production 3. **Analytics:** Track cache hit rates in production
@@ -544,6 +591,7 @@ While current performance is excellent, these could provide marginal gains:
**Performance Grade: A+** **Performance Grade: A+**
The SkyArtShop website is now highly optimized for: The SkyArtShop website is now highly optimized for:
- Fast load times (< 10ms) - Fast load times (< 10ms)
- Low memory usage (automatic cleanup) - Low memory usage (automatic cleanup)
- Efficient API calls (cached + deduplicated) - Efficient API calls (cached + deduplicated)

View File

@@ -3,21 +3,25 @@
## What Was Done ## What Was Done
### 🗄️ Database (Backend) ### 🗄️ Database (Backend)
- Added 6 new high-performance indexes - Added 6 new high-performance indexes
- Total: **44 active indexes** - Total: **44 active indexes**
- All tables analyzed and optimized - All tables analyzed and optimized
- Vacuum completed for space reclamation - Vacuum completed for space reclamation
### 🚀 Frontend API Cache ### 🚀 Frontend API Cache
- New file: `api-cache.js` (intelligent caching) - New file: `api-cache.js` (intelligent caching)
- Request deduplication (prevents duplicate calls) - Request deduplication (prevents duplicate calls)
- Auto-cleanup every 60 seconds - Auto-cleanup every 60 seconds
- Custom TTL per endpoint (5-30 minutes) - Custom TTL per endpoint (5-30 minutes)
### 📄 Pages Updated ### 📄 Pages Updated
All pages now use optimized API cache: All pages now use optimized API cache:
- [home.html](website/public/home.html) - [home.html](website/public/home.html)
- [shop.html](website/public/shop.html) - [shop.html](website/public/shop.html)
- [portfolio.html](website/public/portfolio.html) - [portfolio.html](website/public/portfolio.html)
- [blog.html](website/public/blog.html) - [blog.html](website/public/blog.html)
- [product.html](website/public/product.html) - [product.html](website/public/product.html)
@@ -35,6 +39,7 @@ Frontend-Backend: ✅ Verified Working
## Verify It's Working ## Verify It's Working
### 1. Browser Console (F12) ### 1. Browser Console (F12)
```javascript ```javascript
// You should see cache messages like: // You should see cache messages like:
[Cache] FETCH: /api/products [Cache] FETCH: /api/products
@@ -46,11 +51,13 @@ window.apiCache.getStats()
``` ```
### 2. Network Tab (F12 → Network) ### 2. Network Tab (F12 → Network)
- First page visit: You'll see API calls - First page visit: You'll see API calls
- Navigate to another page and back: Fewer/no API calls - Navigate to another page and back: Fewer/no API calls
- This means cache is working! 🎉 - This means cache is working! 🎉
### 3. Command Line Test ### 3. Command Line Test
```bash ```bash
cd /media/pts/Website/SkyArtShop cd /media/pts/Website/SkyArtShop
./test-api-performance.sh ./test-api-performance.sh
@@ -59,12 +66,14 @@ cd /media/pts/Website/SkyArtShop
## How It Works ## How It Works
### Before Optimization ### Before Optimization
``` ```
User → Page → fetch('/api/products') → Server → Database → Response User → Page → fetch('/api/products') → Server → Database → Response
User → Page → fetch('/api/products') → Server → Database → Response (duplicate!) User → Page → fetch('/api/products') → Server → Database → Response (duplicate!)
``` ```
### After Optimization ### After Optimization
``` ```
User → Page → apiCache.fetch('/api/products') → Server → Database → Response → CACHE User → Page → apiCache.fetch('/api/products') → Server → Database → Response → CACHE
User → Page → apiCache.fetch('/api/products') → CACHE (instant!) ⚡ User → Page → apiCache.fetch('/api/products') → CACHE (instant!) ⚡
@@ -73,13 +82,16 @@ User → Page → apiCache.fetch('/api/products') → CACHE (instant!) ⚡
## Cache Control ## Cache Control
### Clear Cache Manually ### Clear Cache Manually
```javascript ```javascript
// In browser console (F12) // In browser console (F12)
window.clearAPICache(); // Clears all cached data window.clearAPICache(); // Clears all cached data
``` ```
### Adjust Cache Time ### Adjust Cache Time
Edit `website/public/assets/js/api-cache.js`: Edit `website/public/assets/js/api-cache.js`:
```javascript ```javascript
this.ttlConfig = { this.ttlConfig = {
'/api/products': 5 * 60 * 1000, // 5 minutes (default) '/api/products': 5 * 60 * 1000, // 5 minutes (default)
@@ -90,6 +102,7 @@ this.ttlConfig = {
## Monitoring ## Monitoring
### Check Active Indexes ### Check Active Indexes
```sql ```sql
SELECT indexname FROM pg_indexes SELECT indexname FROM pg_indexes
WHERE schemaname = 'public' WHERE schemaname = 'public'
@@ -97,6 +110,7 @@ AND indexname LIKE 'idx_%';
``` ```
### Watch PM2 Logs ### Watch PM2 Logs
```bash ```bash
pm2 logs skyartshop pm2 logs skyartshop
``` ```
@@ -111,6 +125,7 @@ pm2 logs skyartshop
## What Was NOT Changed ## What Was NOT Changed
**Zero functionality changes** **Zero functionality changes**
- All features work exactly the same - All features work exactly the same
- User experience unchanged - User experience unchanged
- Admin panel unchanged - Admin panel unchanged
@@ -122,16 +137,19 @@ pm2 logs skyartshop
## Troubleshooting ## Troubleshooting
### Cache not working? ### Cache not working?
1. Hard refresh: `Ctrl+Shift+R` 1. Hard refresh: `Ctrl+Shift+R`
2. Check console for errors 2. Check console for errors
3. Verify api-cache.js loads: `curl http://localhost:5000/assets/js/api-cache.js` 3. Verify api-cache.js loads: `curl http://localhost:5000/assets/js/api-cache.js`
### Slow queries? ### Slow queries?
1. Run: `./test-api-performance.sh` 1. Run: `./test-api-performance.sh`
2. Check if responses are >50ms 2. Check if responses are >50ms
3. Review database indexes 3. Review database indexes
### Pages not loading? ### Pages not loading?
1. Check PM2: `pm2 status` 1. Check PM2: `pm2 status`
2. Check logs: `pm2 logs skyartshop` 2. Check logs: `pm2 logs skyartshop`
3. Restart: `pm2 restart skyartshop` 3. Restart: `pm2 restart skyartshop`

View File

@@ -119,7 +119,7 @@
<a href="/checkout" class="btn-primary-full" <a href="/checkout" class="btn-primary-full"
>Proceed to Checkout</a >Proceed to Checkout</a
> >
<a href="/shop" class="btn-text">Continue Shopping</a> <a href="/shop" class="btn-outline">Continue Shopping</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -11,28 +11,28 @@ class APICache {
this.cache = new Map(); this.cache = new Map();
this.pendingRequests = new Map(); this.pendingRequests = new Map();
this.defaultTTL = 5 * 60 * 1000; // 5 minutes default this.defaultTTL = 5 * 60 * 1000; // 5 minutes default
// Custom TTL for different endpoints // Custom TTL for different endpoints
this.ttlConfig = { this.ttlConfig = {
'/api/products': 5 * 60 * 1000, // 5 min "/api/products": 5 * 60 * 1000, // 5 min
'/api/products/featured': 10 * 60 * 1000, // 10 min "/api/products/featured": 10 * 60 * 1000, // 10 min
'/api/categories': 30 * 60 * 1000, // 30 min "/api/categories": 30 * 60 * 1000, // 30 min
'/api/portfolio/projects': 10 * 60 * 1000, // 10 min "/api/portfolio/projects": 10 * 60 * 1000, // 10 min
'/api/blog/posts': 5 * 60 * 1000, // 5 min "/api/blog/posts": 5 * 60 * 1000, // 5 min
'/api/pages': 10 * 60 * 1000, // 10 min "/api/pages": 10 * 60 * 1000, // 10 min
}; };
// Start periodic cleanup // Start periodic cleanup
this.startCleanup(); this.startCleanup();
} }
/** /**
* Get cache key from URL * Get cache key from URL
*/ */
getCacheKey(url) { getCacheKey(url) {
return url; return url;
} }
/** /**
* Get TTL for specific endpoint * Get TTL for specific endpoint
*/ */
@@ -45,46 +45,46 @@ class APICache {
} }
return this.defaultTTL; return this.defaultTTL;
} }
/** /**
* Check if cache entry is valid * Check if cache entry is valid
*/ */
isValid(entry) { isValid(entry) {
return entry && Date.now() - entry.timestamp < entry.ttl; return entry && Date.now() - entry.timestamp < entry.ttl;
} }
/** /**
* Get from cache * Get from cache
*/ */
get(url) { get(url) {
const key = this.getCacheKey(url); const key = this.getCacheKey(url);
const entry = this.cache.get(key); const entry = this.cache.get(key);
if (this.isValid(entry)) { if (this.isValid(entry)) {
console.log(`[Cache] HIT: ${url}`); console.log(`[Cache] HIT: ${url}`);
return entry.data; return entry.data;
} }
console.log(`[Cache] MISS: ${url}`); console.log(`[Cache] MISS: ${url}`);
return null; return null;
} }
/** /**
* Set cache entry * Set cache entry
*/ */
set(url, data) { set(url, data) {
const key = this.getCacheKey(url); const key = this.getCacheKey(url);
const ttl = this.getTTL(url); const ttl = this.getTTL(url);
this.cache.set(key, { this.cache.set(key, {
data, data,
timestamp: Date.now(), timestamp: Date.now(),
ttl ttl,
}); });
console.log(`[Cache] SET: ${url} (TTL: ${ttl}ms)`); console.log(`[Cache] SET: ${url} (TTL: ${ttl}ms)`);
} }
/** /**
* Clear specific cache entry * Clear specific cache entry
*/ */
@@ -93,24 +93,24 @@ class APICache {
this.cache.delete(key); this.cache.delete(key);
console.log(`[Cache] CLEAR: ${url}`); console.log(`[Cache] CLEAR: ${url}`);
} }
/** /**
* Clear all cache * Clear all cache
*/ */
clearAll() { clearAll() {
this.cache.clear(); this.cache.clear();
console.log('[Cache] CLEARED ALL'); console.log("[Cache] CLEARED ALL");
} }
/** /**
* Fetch with caching and deduplication * Fetch with caching and deduplication
*/ */
async fetch(url, options = {}) { async fetch(url, options = {}) {
// Only cache GET requests // Only cache GET requests
if (options.method && options.method !== 'GET') { if (options.method && options.method !== "GET") {
return fetch(url, options); return fetch(url, options);
} }
// Check cache first // Check cache first
const cached = this.get(url); const cached = this.get(url);
if (cached) { if (cached) {
@@ -118,51 +118,51 @@ class APICache {
json: async () => cached, json: async () => cached,
ok: true, ok: true,
status: 200, status: 200,
fromCache: true fromCache: true,
}; };
} }
// Check if request is already pending // Check if request is already pending
if (this.pendingRequests.has(url)) { if (this.pendingRequests.has(url)) {
console.log(`[Cache] DEDUP: ${url} - Waiting for pending request`); console.log(`[Cache] DEDUP: ${url} - Waiting for pending request`);
return this.pendingRequests.get(url); return this.pendingRequests.get(url);
} }
// Make new request // Make new request
console.log(`[Cache] FETCH: ${url}`); console.log(`[Cache] FETCH: ${url}`);
const requestPromise = fetch(url, options) const requestPromise = fetch(url, options)
.then(async response => { .then(async (response) => {
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP ${response.status}`); throw new Error(`HTTP ${response.status}`);
} }
const data = await response.json(); const data = await response.json();
// Cache successful response // Cache successful response
this.set(url, data); this.set(url, data);
// Remove from pending // Remove from pending
this.pendingRequests.delete(url); this.pendingRequests.delete(url);
return { return {
json: async () => data, json: async () => data,
ok: true, ok: true,
status: response.status, status: response.status,
fromCache: false fromCache: false,
}; };
}) })
.catch(error => { .catch((error) => {
// Remove from pending on error // Remove from pending on error
this.pendingRequests.delete(url); this.pendingRequests.delete(url);
throw error; throw error;
}); });
// Store as pending // Store as pending
this.pendingRequests.set(url, requestPromise); this.pendingRequests.set(url, requestPromise);
return requestPromise; return requestPromise;
} }
/** /**
* Periodic cleanup of expired entries * Periodic cleanup of expired entries
*/ */
@@ -180,7 +180,7 @@ class APICache {
} }
}, 60000); // Run every minute }, 60000); // Run every minute
} }
/** /**
* Get cache statistics * Get cache statistics
*/ */
@@ -192,8 +192,8 @@ class APICache {
url: key, url: key,
age: Date.now() - entry.timestamp, age: Date.now() - entry.timestamp,
ttl: entry.ttl, ttl: entry.ttl,
valid: this.isValid(entry) valid: this.isValid(entry),
})) })),
}; };
} }
} }

View File

@@ -127,7 +127,7 @@
<a href="/checkout" class="btn-primary-full" <a href="/checkout" class="btn-primary-full"
>Proceed to Checkout</a >Proceed to Checkout</a
> >
<a href="/shop" class="btn-text">Continue Shopping</a> <a href="/shop" class="btn-outline">Continue Shopping</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -153,7 +153,7 @@
<a href="/checkout" class="btn-primary-full" <a href="/checkout" class="btn-primary-full"
>Proceed to Checkout</a >Proceed to Checkout</a
> >
<a href="/shop" class="btn-text">Continue Shopping</a> <a href="/shop" class="btn-outline">Continue Shopping</a>
</div> </div>
</div> </div>
</div> </div>
@@ -259,7 +259,9 @@
"Fetching product from API:", "Fetching product from API:",
`/api/products/${productId}` `/api/products/${productId}`
); );
const response = await window.apiCache.fetch(`/api/products/${productId}`); const response = await window.apiCache.fetch(
`/api/products/${productId}`
);
const data = await response.json(); const data = await response.json();
console.log("API response:", data); console.log("API response:", data);

View File

@@ -684,7 +684,7 @@
<a href="/checkout" class="btn-primary-full" <a href="/checkout" class="btn-primary-full"
>Proceed to Checkout</a >Proceed to Checkout</a
> >
<a href="/shop" class="btn-text">Continue Shopping</a> <a href="/shop" class="btn-outline">Continue Shopping</a>
</div> </div>
</div> </div>
</div> </div>