Commit Graph

104 Commits

Author SHA1 Message Date
Unchained f6609f07d7 feat: implement programmatic SEO solutions hub
- Add /solutions hub page with 10 category cards
- Add /solutions/by-concern directory page
- Add /solutions/by-oil directory page
- Add Solutions section to Footer with navigation links
- Add Breadcrumb component for solution pages
- Add translations for all solution pages (sr, en, de, fr)
- Fix ExitIntentDetector JSON parsing error
- Update sitemap with solution pages
- Create 3 sample solution pages with data files
2026-04-05 05:21:57 +02:00
Unchained eb711fbf1a feat(popup): add email capture popup with Mautic integration
Build and Deploy / build (push) Has been cancelled
- Email capture popup with scroll (10%) and exit intent triggers
- First name field and full tracking (UTM, device, time on page)
- Mautic API integration for contact creation
- GeoIP detection for country/region
- 4 locale support (sr, en, de, fr)
- Mautic tracking script in layout
2026-04-03 20:44:15 +02:00
Unchained 4e5481af1a fix(layout): restore ExitIntentDetector and Mautic tracking
Build and Deploy / build (push) Has been cancelled
2026-04-03 20:27:25 +02:00
Unchained 618298b1b1 fix(layout): restore original structure, keep only Rybbit direct URL fix
Build and Deploy / build (push) Has been cancelled
Revert unintended changes from previous commit:
- Restore AnalyticsProvider (was accidentally removed)
- Remove ExitIntentDetector (feature branch code)
- Remove Mautic tracking script (feature branch code)

Keep only the intended Rybbit fix:
- Direct connection to Rybbit instead of server-side proxy
2026-04-03 20:14:07 +02:00
Unchained d999d739d5 fix(analytics): connect directly to Rybbit to preserve real visitor IP
Build and Deploy / build (push) Has been cancelled
Changed Rybbit script loading from server-side rewrite to client-side direct
connection. This prevents Next.js from proxying the request, which was causing
all visitor IPs to show as the Hetzner server IP (138.201.11.251).

Before:
- Browser → Next.js → Rybbit (server-side proxy, loses client IP)

After:
- Browser → Rybbit (direct connection, real IP preserved)

Changes:
- layout.tsx: Use direct Rybbit URL for script src
- next.config.ts: Remove /api/script.js rewrite
2026-04-03 20:10:59 +02:00
Unchained 9124eeedc1 fix: add ts-ignore for request.ip runtime property
Build and Deploy / build (push) Has been cancelled
2026-04-01 10:47:09 +02:00
Unchained 6843d2db36 fix(404): add redirects for broken URLs and custom not-found page
Build and Deploy / build (push) Has been cancelled
- Add permanent redirects for /products/manoon to /products
- Strip malformed /contact suffix from product URLs
- Create custom branded 404 page with product navigation
- Add NotFound translations for en and sr locales
2026-04-01 10:24:09 +02:00
Unchained 0b9ddeedc8 fix(analytics): properly forward client IPs to Rybbit and OpenPanel
- Create new API route /api/rybbit/track to proxy Rybbit tracking requests
- Extract real client IP from Cloudflare headers (cf-connecting-ip)
- Forward X-Forwarded-For and X-Real-IP headers to analytics backends
- Update OpenPanel proxy to also forward client IP
- Update next.config.ts rewrite to use internal API route

This fixes geo-location issues where all traffic appeared to come from
Cloudflare edge locations instead of actual visitor countries.
2026-04-01 10:24:09 +02:00
Unchained a3873bb50d fix(analytics): properly forward client IPs to Rybbit and OpenPanel
- Create new API route /api/rybbit/track to proxy Rybbit tracking requests
- Extract real client IP from Cloudflare headers (cf-connecting-ip)
- Forward X-Forwarded-For and X-Real-IP headers to analytics backends
- Update OpenPanel proxy to also forward client IP
- Update next.config.ts rewrite to use internal API route

This fixes geo-location issues where all traffic appeared to come from
Cloudflare edge locations instead of actual visitor countries.
2026-04-01 07:42:34 +02:00
Unchained 27af03ba3a feat(performance): optimize Core Web Vitals with CSS animations and lazy analytics
- Replace framer-motion with CSS animations in TrustBadges, AsSeenIn, ProblemSection
- Create AnalyticsProvider client component for OpenPanel lazy-loading
- Fix HeroVideo CLS with explicit aspect-ratio (4/3)
- Remove deprecated swcMinify from next.config (enabled by default)
- Add optimizePackageImports for better tree-shaking
2026-04-01 06:14:49 +02:00
Unchained edd5c1582b feat(performance): add ISR and Cloudflare cache headers
- Add revalidate=3600 to homepage and products page (1hr ISR)
- Add middleware to set cache headers for HTML pages
- Bypass cache for checkout and cart pages
2026-03-31 20:08:56 +02:00
Unchained dff78b28a5 fix(analytics): restore OpenPanel proxy routes
Build and Deploy / build (push) Has been cancelled
2026-03-31 13:47:14 +02:00
Unchained b4905ce4ee chore: remove OpenPanel proxy routes (keeping core vitals changes)
Build and Deploy / build (push) Has been cancelled
2026-03-31 13:44:53 +02:00
Unchained e87c655a5b Merge branch 'feature/web-vitals-optimization' into dev
Build and Deploy / build (push) Has been cancelled
2026-03-31 13:22:45 +02:00
Unchained 1c5ec1a271 fix: remove framer-motion from HeroVideo for instant content visibility 2026-03-31 13:22:45 +02:00
Unchained 8eb9f24b33 feat(performance): Core Web Vitals optimizations
- Font optimization: Replace @font-face with next/font/google (DM Sans, Inter) for faster font loading and no render-blocking
- Image optimization: Add Unsplash to remotePatterns, configure AVIF/WebP formats, add device/image sizes
- Convert native <img> tags to next/image with proper sizing and priority for LCP images
- Add optimizePackageImports for lucide-react and framer-motion to reduce bundle size
- Fix CLS: Urgency message uses fixed min-height instead of animated height
- Fix CLS: ProductCard quick-add button uses opacity instead of translate for hover
- Convert HeroVideo scroll indicator to CSS animation
- Script loading: Rybbit uses lazyOnload strategy for better INP
2026-03-31 12:03:34 +02:00
Unchained bce2d19ca3 fix(analytics): fix OpenPanel apiUrl to not include /track
Build and Deploy / build (push) Has been cancelled
2026-03-31 07:23:03 +02:00
Unchained cee3b71454 fix(analytics): use route handler for OpenPanel script to fix query param issue
Build and Deploy / build (push) Has been cancelled
2026-03-31 07:19:14 +02:00
Unchained 1cdda7db3c fix(analytics): use rewrites instead of route handler for OpenPanel proxy
Build and Deploy / build (push) Has been cancelled
2026-03-31 06:37:17 +02:00
Unchained 1dd7e1dfe7 fix(analytics): use local proxy for OpenPanel to avoid ad blockers
Build and Deploy / build (push) Has been cancelled
2026-03-31 06:31:48 +02:00
Unchained 56c05cc8fc feat(analytics): add Rybbit proxy rewrites and env vars
Build and Deploy / build (push) Has been cancelled
- Add Next.js rewrites to proxy /api/script.js and /api/track through self-hosted Rybbit
- This bypasses ad blockers that would block rybbit.nodecrew.me directly
- Add NEXT_PUBLIC_RYBBIT_HOST and NEXT_PUBLIC_RYBBIT_SITE_ID env vars to K8s deployment
2026-03-31 05:17:57 +02:00
Unchained 511c3078c5 fix: update all fallback URLs from dev.manoonoils.com to manoonoils.com
Build and Deploy / build (push) Has been cancelled
2026-03-31 00:53:37 +02:00
Unchained 44091fc72a fix: inline Rybbit config to avoid client directive in server component
Build and Deploy / build (push) Has been cancelled
2026-03-31 00:50:33 +02:00
Unchained b3efebd3e4 feat: integrate Rybbit analytics alongside OpenPanel
Build and Deploy / build (push) Has been cancelled
- Add RybbitService for tracking e-commerce events
- Update useAnalytics hook to track with both OpenPanel and Rybbit
- Add Rybbit script to layout for page view tracking
- Track all applicable store events: product views, cart, checkout, orders, search, etc.
2026-03-31 00:38:38 +02:00
Unchained 044aefae94 fix: remove dev.manoonoils.com from ingress and update OpenPanel API URL
Build and Deploy / build (push) Has been cancelled
- Remove dev.manoonoils.com from storefront ingress to prevent cross-domain tracking issues
- Use environment variable for OpenPanel API URL in route handler
- Fixes session state conflicts from multiple domains
2026-03-30 20:40:17 +02:00
Unchained f1c30b7141 fix: replace {{productName}} template in product page keywords
Build and Deploy / build (push) Has been cancelled
- Add template replacement logic for product keywords
- Replace {{productName}} with actual product.name
- Keywords now show correct product name instead of template variable
2026-03-30 13:07:40 +02:00
Unchained d9473e3f9e fix: add missing SEO to About and Contact pages
- Add keywords, canonical, OpenGraph to About page
- Refactor Contact page to server component with generateMetadata
- Create ContactPageClient for form functionality
- All pages now have complete SEO coverage
2026-03-30 12:21:26 +02:00
Unchained fd0490c3e1 feat: integrate SEO system into pages
- Add OrganizationSchema to root layout
- Add ProductSchema with metadata to product pages
- Add enhanced metadata to homepage with keywords
- Add enhanced metadata to products listing page
- Add noindex to checkout page via layout
- Implement canonical URLs, OpenGraph, and Twitter cards
2026-03-30 11:42:58 +02:00
Unchained 25e60457cc fix: shipping cost calculation and performance optimization
- Fix shipping cost not included in checkout total
- Add useShippingMethodSelector hook for proper abstraction
- Remove blocking initCheckout from Header for better performance
- Checkout now initializes lazily when cart opens or item added
2026-03-30 06:31:52 +02:00
Unchained adb28c2a91 feat: Implement dual client/server analytics tracking
Complete analytics overhaul with redundant tracking:

CLIENT-SIDE (useAnalytics hook):
- Tracks user behavior in real-time
- Product views, add to cart, checkout steps
- Revenue tracking via op.revenue()
- Captures user session data

SERVER-SIDE (API route + server functions):
- POST /api/analytics/track-order endpoint
- trackOrderCompletedServer() function
- Reliable tracking that can't be blocked
- Works even if browser closes

DUAL TRACKING for order completion:
1. Client tracks immediately (session data)
2. API call to server endpoint (reliable)
3. Both sources recorded with 'source' property

Files:
- src/lib/analytics.ts - Client-side with dual tracking
- src/lib/analytics-server.ts - Server-side tracking
- src/app/api/analytics/track-order/route.ts - API endpoint

Benefits:
-  100% revenue capture (server-side backup)
-  Real-time client tracking
-  Ad blocker resistant
-  Browser-close resistant
-  Full funnel visibility
2026-03-30 05:41:05 +02:00
Unchained 6ae7b045a7 fix: Track order completion BEFORE clearing checkout
The checkout was being cleared before tracking, causing getTotal()
to return 0. Fixed by reordering operations:
1. Track order completion (while checkout data exists)
2. Then clear the checkout

Added console log to verify total is captured correctly.
2026-03-30 05:02:34 +02:00
Unchained a516b3a536 fix: Remove auto-order confirmation code
The order confirmation requires MANAGE_ORDERS permission which
the storefront API token doesn't have. Removing the auto-confirmation
attempt to prevent console errors. Orders will remain UNCONFIRMED
until manually confirmed in Saleor Dashboard.
2026-03-29 20:49:52 +02:00
Unchained 51a41cbb89 fix: Add missing currency field to checkout items tracking
CartItemData requires currency field for each item.
Added currency extraction from variant pricing.
2026-03-29 20:31:57 +02:00
Unchained de4eb0852c feat: Add order auto-confirmation (best effort)
Added order confirmation after checkout completion.
Note: This requires MANAGE_ORDERS permission which currently
has the same bug as HANDLE_PAYMENTS. The try-catch ensures
checkout won't fail if confirmation fails. Orders will be
UNCONFIRMED until manually confirmed in dashboard.
2026-03-29 19:33:04 +02:00
Unchained 9c3d8b0d11 fix: Remove COD transaction creation to fix checkout errors
The transaction creation was failing due to HANDLE_PAYMENTS permission issues.
Removed the code to get checkout working again. Will implement via
order metadata or core-extensions webhook instead.
2026-03-29 19:17:06 +02:00
Unchained e15e6470d2 fix: Add SALEOR_API_TOKEN auth for COD transaction creation
- Add SALEOR_API_TOKEN environment variable support
- Update Apollo client to include auth header
- Enable COD transaction creation after checkout
2026-03-29 18:22:16 +02:00
Unchained 5f9b7bac3a fix: set checkout languageCode to ensure emails are sent in correct language
- Add CHECKOUT_LANGUAGE_CODE_UPDATE mutation to update checkout language
- Call language code update before completing checkout
- Language code (SR, EN, DE, FR) is now set on checkout before order creation
- This ensures order confirmation emails are sent in the customer's language
- Update step numbering in checkout flow (now 6 steps total)
2026-03-29 14:42:52 +02:00
Unchained fbe0761609 fix: remove manual transaction creation causing 400 error
- Remove CREATE_TRANSACTION_MUTATION call that's causing 400 error
- Saleor's checkoutComplete already creates order with NOT_CHARGED status for COD
- Order doesn't need manual transaction - staff handles fulfillment in dashboard
- Keep payment method selection and UI components intact
2026-03-29 14:31:42 +02:00
Unchained 10b18c6010 feat: add 30-day money back guarantee trust badge above complete order button
- Add green trust badge with checkmark icon above 'Complete Order' button
- Add translations for all locales (EN, SR, DE, FR)
- Badge includes: '30-Day Money-Back Guarantee' text
- Styled with green background and border to match trust/conversion theme
2026-03-29 14:27:05 +02:00
Unchained ff481f18c3 feat: implement Cash on Delivery (COD) payment method
This commit adds comprehensive COD support using Saleor's native Transaction system:

**Architecture:**
- Uses Saleor's native Transaction objects (not metadata)
- Modular payment method configuration
- Extensible design for future payment types (cards, bank transfer, etc.)

**New Components:**
- PaymentMethodSelector: Reusable payment method selection UI
- PaymentMethodCard: Individual payment method card
- CODInstructions: COD-specific instructions and guidance
- PaymentSection: Checkout integration wrapper

**Core Features:**
- COD selected by default for Serbia (default-channel)
- Transaction created automatically on order completion
- Transaction visible in Saleor Dashboard
- Multi-language support (EN, SR, DE, FR)
- No additional fees
- Instructions shown to customer (prepare cash, inspect order, no fee)

**Files Added:**
- docs/COD-IMPLEMENTATION-PLAN.md
- src/lib/config/paymentMethods.ts
- src/lib/saleor/payments/types.ts
- src/lib/saleor/payments/cod.ts
- src/components/payment/PaymentMethodSelector.tsx
- src/components/payment/PaymentMethodCard.tsx
- src/components/payment/CODInstructions.tsx
- src/components/payment/index.ts
- src/app/[locale]/checkout/components/PaymentSection.tsx

**Files Modified:**
- src/app/[locale]/checkout/page.tsx (added payment section, transaction creation)
- src/i18n/messages/{en,sr,de,fr}.json (payment translations)

**Technical Details:**
- Transaction status: NOT_CHARGED
- Available actions: [CHARGE]
- PSP Reference format: COD-{orderNumber}-{timestamp}
- Staff collects cash and fulfills order via Dashboard

Closes: Cash on Delivery payment implementation
2026-03-29 06:02:51 +02:00
Unchained 322c4c805b fix: add back email update step in checkout 2026-03-28 18:09:57 +02:00
Unchained bcf74e1fd1 feat: implement one-page checkout with dynamic shipping 2026-03-28 18:03:12 +02:00
Unchained a419337d99 feat: store userLanguage in checkout metadata for multi-language emails
Adds userLanguage and userLocale to checkout metadata during order completion.
This allows N8N workflows to detect the customer's selected language and
send order confirmation emails in the correct language (sr, en, de, fr).
2026-03-28 07:27:09 +02:00
Unchained 09294fd752 refactor: Remove email functionality - migrated to core-extensions app
Removed:
- Webhook handlers (src/app/api/webhooks/saleor/)
- Email templates (src/emails/)
- OrderNotificationService (src/lib/services/)

Emails now handled by saleor-core-extensions service
Manifest: https://core-extensions.manoonoils.com/api/manifest
2026-03-26 08:50:58 +02:00
Unchained 2e6668ff0d fix(webhook): prevent duplicate revenue tracking
Move analytics tracking inside ORDER_CONFIRMED conditional block
so revenue is only tracked once when order is confirmed, not twice
(once for ORDER_CREATED and once for ORDER_CONFIRMED).
2026-03-25 20:35:39 +02:00
Unchained ab7dfbe48b refactor(webhook): modularize email and analytics code
Create service-oriented architecture for better maintainability:

- AnalyticsService: Centralized analytics tracking with OpenPanel
  - trackOrderReceived(), trackRevenue(), track()
  - Error handling that doesn't break main flow
  - Singleton pattern for single instance

- OrderNotificationService: Encapsulates all order email logic
  - sendOrderConfirmation() - customer + admin
  - sendOrderShipped() - with tracking info
  - sendOrderCancelled() - with reason
  - sendOrderPaid() - payment confirmation
  - Translation logic moved from webhook to service
  - Email formatting utilities encapsulated

- Webhook route refactored:
  - Reduced from 605 lines to ~250 lines
  - No business logic - only HTTP handling
  - Delegates to services for emails and analytics
  - Cleaner separation of concerns

- New utils file: formatPrice() shared between services

This prevents future bugs by:
1. Centralizing email logic in one place
2. Making code testable (services can be unit tested)
3. Easier to add new webhook handlers
4. Translation logic not mixed with HTTP code
5. Analytics failures don't break order processing
2026-03-25 20:22:55 +02:00
Unchained 646d057970 Merge branch 'feature/saleor-emails' into dev 2026-03-25 19:58:17 +02:00
Unchained a0fa0f5401 fix(analytics): add OpenPanel revenue tracking to webhooks
Add OpenPanel import and initialization that was missing from webhook route.
Add order_received and revenue tracking when orders are confirmed.
Revenue tracking uses op.revenue() method with amount, currency,
order_id, and order_number properties.
2026-03-25 19:57:43 +02:00
Unchained aa7a0ed3c8 fix(webhook): remove incorrect /100 division from formatPrice
Saleor stores amounts as actual currency values (e.g., 5479 RSD),
not as cents (e.g., 547900). The formatPrice function was incorrectly
dividing by 100, causing prices like 5479 RSD to display as 55 RSD.
2026-03-25 19:53:08 +02:00
Unchained 15a65758d7 fix(webhook): remove incorrect /100 division from formatPrice
Saleor stores amounts as actual currency values (e.g., 5479 RSD),
not as cents (e.g., 547900). The formatPrice function was incorrectly
dividing by 100, causing prices like 5479 RSD to display as 55 RSD.
2026-03-25 19:51:27 +02:00