Commit Graph

261 Commits

Author SHA1 Message Date
dwindown
15760d6430 Fix React error #310 by ensuring hooks are called before conditional returns
- Moved useMemo calls before early returns in VideoPlayer component
- This ensures hooks are always called in the same order on every render
- Fixed violation of Rules of Hooks that caused error in production

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-04 11:39:39 +07:00
dwindown
ab7033b82e Fix bootcamp video reloading issue and duplicate component error
- Moved VideoPlayer component outside main Bootcamp component to prevent re-creation on every render
- Memoized video source object and URL values to ensure stability
- Removed duplicate Bootcamp component declaration that caused build failure
- Video player now persists across Bootcamp re-renders, fixing continuous reload from 00:00
- Timeline clicking now works correctly without triggering video reload

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-04 11:34:49 +07:00
dwindown
b7bde1df04 Fix video player reloading by moving VideoPlayer component outside main component
- Move VideoPlayer component outside Bootcamp component to prevent re-creation on every render
- This prevents useAdiloPlayer and all hooks from re-initializing unnecessarily
- Video now plays and jumps correctly without reloading
- Component structure now matches WebinarRecording page pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-04 11:25:01 +07:00
dwindown
2b98a5460d Fix video reloading issue by memoizing video source and resetting resume prompt
- Memoize video source object in Bootcamp to prevent unnecessary re-renders
- Reset resume prompt flag when videoId changes to allow prompt for new lessons
- Remove key prop from VideoPlayerWithChapters to prevent unmounting
- Video now plays correctly without reloading on every interaction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-04 11:17:38 +07:00
dwindown
44484afb84 Fix timeline borders, revert sidebar accordion, and fix video reloading
- Remove border-bottom from TimelineChapters component for better readability
- Revert collapsible timeline changes from bootcamp sidebar
- Fix video reloading issue by adding key prop to force remount on lesson change
- Prevent resume prompt from showing multiple times during video playback
- Resume prompt now only shows once when component mounts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-04 11:09:59 +07:00
dwindown
963160d165 Improve Bootcamp timeline with collapsible modules and HTML support
- Add collapsible structure: Module → Lesson → Timeline (as sublesson)
- Support HTML in timeline titles with DOMPurify sanitization
- Add inline code styling for timeline content
- Fix vertical alignment (items-start instead of items-center)
- Add soft borders between timeline items
- Change layout from 2-column grid to single column (video full width, timeline below)
- Align Bootcamp page layout with WebinarRecording page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-04 10:47:59 +07:00
dwindown
ce10be63f3 Fix content field not loading in product edit form
- Add 'content' field to fetchProducts SELECT query
- Fixes Rich Text Editor showing empty when editing products

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 22:25:24 +07:00
dwindown
8217261706 replace favicon.ico 2026-01-03 21:46:25 +07:00
dwindown
053465afa3 Fix email system and implement OTP confirmation flow
Email System Fixes:
- Fix email sending after payment: handle-order-paid now calls send-notification
  instead of send-email-v2 directly, properly processing template variables
- Fix order_created email timing: sent immediately after order creation,
  before payment QR code generation
- Update email templates to use short order ID (8 chars) instead of full UUID
- Add working "Akses Sekarang" buttons to payment_success and access_granted emails
- Add platform_url column to platform_settings for email links

OTP Verification Flow:
- Create dedicated /confirm-otp page for users who close registration modal
- Add link in checkout modal and email to dedicated OTP page
- Update OTP email template with better copywriting and dedicated page link
- Fix send-auth-otp to fetch platform settings for dynamic brand_name and platform_url
- Auto-login users after OTP verification in checkout flow

Admin Features:
- Add delete user functionality with cascade deletion of all related data
- Update IntegrasiTab to read/write email settings from platform_settings only
- Add test email template for email configuration testing

Cleanup:
- Remove obsolete send-consultation-reminder and send-test-email functions
- Update send-email-v2 to read email config from platform_settings
- Remove footer links (Ubah Preferensi/Unsubscribe) from email templates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 18:02:25 +07:00
dwindown
4f9a6f4ae3 Fix variable replacement format in send-notification
The replaceVariables function was only supporting {{key}} format but
the email templates use {key} format (single braces). Updated to support
both formats for compatibility.

Changes:
- Added support for {key} format in addition to {{key}}
- Ensures all template variables are properly replaced

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 09:10:19 +07:00
dwindown
9f8ee0d7d2 Add Mailketing API support to send-notification function
The send-notification function was using SMTP by default and failing with
ConnectionRefused errors. Added Mailketing API integration to match the
email provider used by other functions (send-auth-otp, send-email-v2).

Changes:
- Added sendViaMailketing() function with form-encoded body
- Added "mailketing" case to provider switch (now the default)
- Changed default provider from "smtp" to "mailketing"
- Reads API token from mailketing_api_token or api_token settings

This ensures order_created emails are sent successfully via Mailketing
just like other email notifications in the system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 09:06:27 +07:00
dwindown
1fbaf4d360 Fix column names in send-notification and migration
Updated to use the correct database column names:
- email_subject (not subject)
- email_body_html (not body_html)

Changes:
- send-notification/index.ts: Added fallback to check both email_subject/subject
  and email_body_html/body_html for compatibility
- Migration: Updated to use correct column names (email_subject, email_body_html)

This matches the actual database schema shown in the notification_templates table.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 08:59:49 +07:00
dwindown
485263903f Add order_created email template with QR code section
This migration updates the order_created email template to include:
- QR code image display for payment
- Order summary section with all details
- Payment link button
- QR expiry time display
- Professional layout and styling

The template uses these shortcodes:
- {qr_code_image} - Base64 QR code image generated by send-notification
- {qr_expiry_time} - QR code expiration timestamp
- {nama}, {email}, {order_id}, {tanggal_pesanan}
- {total}, {metode_pembayaran}, {produk}
- {payment_link}, {thank_you_page}, {platform_name}

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 08:53:31 +07:00
dwindown
00de020b6c Fix template lookup column name in send-notification
The function was using .eq("template_key") but the actual column name
in notification_templates table is "key". This caused "Template not found"
errors even when the template existed and was active.

Changes:
- send-notification/index.ts: Changed .eq("template_key") to .eq("key")
- Matches the pattern used in send-auth-otp and other edge functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 08:52:32 +07:00
dwindown
5f753464fd Fix order_created email by waiting for send-notification before navigation
The early termination issue was caused by the page navigating away before
the send-notification function call could complete. Changed from fire-and-forget
to awaiting the email send result before redirecting.

Changes:
- Checkout.tsx: Changed send-notification call to use await instead of .then()/.catch()
- Now waits for email send to complete before navigating to order detail page
- Email failures are caught in try/catch but navigation still proceeds

Technical details:
- Browser was terminating pending requests when navigate() was called immediately
- Early termination: isolate warning indicated function was being killed mid-execution
- Awaiting the function call ensures it completes before page navigation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 07:40:59 +07:00
dwindown
1749056542 Add order_created email with QR code generation
Enhanced email notification system to send order confirmation emails immediately after order creation with embedded QR code for payment.

Changes:
- Checkout.tsx: Added send-notification call after payment creation with comprehensive logging
- send-notification: Added QRCode library integration for generating base64 QR images for order_created emails
- NotifikasiTab.tsx: Added QR code section to default order_created template and updated shortcodes list

Technical details:
- QR code generated as base64 data URL for email client compatibility
- Fire-and-forget pattern ensures checkout flow isn't blocked
- Added detailed console logging for debugging email send issues
- New shortcodes: {qr_code_image}, {qr_expiry_time}

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 06:58:55 +07:00
dwindown
2ce5c2efe8 Fix missing signIn and signUp destructuring in Checkout
The auth functions were being called but not destructured from useAuth hook,
causing ReferenceError at runtime.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 20:57:34 +07:00
dwindown
72799b981d Add timeline clickability control and checkout auth modal
- Add clickable prop to TimelineChapters component for marketing vs purchased users
- Make timeline non-clickable in product preview pages with lock icons
- Keep timeline clickable in actual content pages (WebinarRecording, Bootcamp)
- Add inline auth modal in checkout with login/register tabs
- Replace "Login untuk Checkout" button with seamless auth flow
- Add form validation and error handling for auth forms

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 20:38:43 +07:00
dwindown
eee6339074 Fix email unconfirmed login flow with OTP resend and update email API field names 2026-01-02 19:33:51 +07:00
dwindown
8f46c5cfd9 Add EmailComponents and ShortcodeProcessor to shared email template renderer
- Add EmailComponents utility functions (button, alert, otpBox, etc.)
- Add ShortcodeProcessor class with DEFAULT_DATA
- Now matches src/lib/email-templates/master-template.ts exactly
- Edge functions can now use helpful components like EmailComponents.otpBox()
2026-01-02 17:20:48 +07:00
dwindown
74bc709684 Add current status document with remaining work 2026-01-02 17:17:22 +07:00
dwindown
dafa4eeeb3 Refactor: Extract master template to shared file and add unconfirmed email handling
- Create supabase/shared/email-template-renderer.ts for code reuse
- Update send-auth-otp to import from shared file (eliminates 260 lines of duplication)
- Add isResendOTP state to track existing user email confirmation
- Update login error handler to detect unconfirmed email
- Show helpful message when user tries to login with unconfirmed email

This addresses:
1. Code duplication between src/lib and edge functions
2. User experience for unconfirmed email login attempts
2026-01-02 17:16:59 +07:00
dwindown
da9a68f084 Add quick deploy checklist for email template fix 2026-01-02 15:20:33 +07:00
dwindown
3196c0ac01 Add comprehensive OTP implementation summary 2026-01-02 15:20:08 +07:00
dwindown
bd3841b716 Add master template wrapper to OTP emails
- Add EmailTemplateRenderer class to send-auth-otp edge function
- Wrap OTP email content in master template with brutalist design
- Email now includes proper header, footer, and styling
- No changes needed to checkout flow (uses auth page for registration)

Benefits:
- Professional branded emails with ACCESS HUB header
- Consistent brutalist design across all emails
- Responsive layout
- Better email client compatibility
2026-01-02 15:19:41 +07:00
dwindown
967829b612 Add .env to .gitignore for security 2026-01-02 15:08:00 +07:00
dwindown
08e56a22d8 Fix send-auth-otp: Remove notification_logs references
- Remove notification_logs table references (table doesn't exist)
- This was causing the function to crash after sending email
- Now the function should complete successfully
- Added better email payload logging
- Keep .env file for local development
2026-01-02 15:07:41 +07:00
dwindown
fa1adcf291 Add comprehensive OTP testing guide
- Step-by-step frontend testing instructions
- Console log examples for each step
- Network tab debugging guide
- Database verification queries
- Common issues and solutions
- Environment variables checklist
2026-01-02 14:34:41 +07:00
dwindown
079c0f947c Improve auth flow error handling and add debug logging
- Add early returns for better error handling flow
- Add console.log for SignUp result to debug user creation
- Ensure loading state is always reset properly
- Add explicit check for missing user data after signUp
2026-01-02 14:34:09 +07:00
dwindown
06d6845456 Fix API token mapping and add extensive debug logging
- Fixed api_token vs mailketing_api_token column mapping
- Added comprehensive debug logging to send-auth-otp
- Added fallback logic for missing settings fields
- Improved error messages for troubleshooting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 14:31:23 +07:00
dwindown
219ad11202 Add debug logging for OTP auth flow 2026-01-02 13:52:28 +07:00
dwindown
c6250d2b47 Fix notification_templates table column names
Update auth email template migration and edge function to use correct column names:
- template_key → key
- subject → email_subject
- html_content → email_body_html

Matches existing notification_templates schema used in NotifikasiTab.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 13:41:30 +07:00
dwindown
0d29c953c1 Implement OTP-based email verification system
Add custom email verification using 6-digit OTP codes via Mailketing API:

Database:
- Create auth_otps table with 15-minute expiry
- Add indexes and RLS policies for security
- Add cleanup function for expired tokens
- Insert default auth_email_verification template

Edge Functions:
- send-auth-otp: Generate OTP, store in DB, send via Mailketing
- verify-auth-otp: Validate OTP, confirm email in Supabase Auth

Frontend:
- Add OTP input state to auth page
- Implement send/verify OTP in useAuth hook
- Add resend countdown timer (60 seconds)
- Update auth flow: signup → OTP verification → login

Features:
- Instant email delivery (no queue/cron)
- 6-digit OTP with 15-minute expiry
- Resend OTP with cooldown
- Admin-configurable email templates
- Indonesian UI text

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 13:27:46 +07:00
dwindown
b1aefea526 Fix production build with esbuild minification
- Switch from Terser to esbuild minifier (Vite's default)
- Set target to es2015 for better browser compatibility
- Remove manual chunking that was causing load order issues
- Result: 3MB bundle (down from 6.5MB) with proper minification

This should resolve the production build errors caused by improper
chunk loading order and duplicate module bundling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 11:26:20 +07:00
dwindown
e6e3bc39d4 Fix production build error with proper vendor chunk splitting
- Configure Vite to split vendor chunks (React, DOMPurify, video libs, Supabase)
- Add manual chunk configuration to prevent duplicate module bundling
- Clean Docker build cache and node_modules cache during build
- Update Dockerfile to force clean rebuilds

This should resolve the 'Identifier already declared' error in production
caused by DOMPurify's @xmldom dependency being bundled multiple times.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 11:21:39 +07:00
dwindown
2f7797803c Disable minification completely to fix production errors
Disabled minification entirely as Terser continued to cause variable
collision errors even with conservative settings.

Changes:
- Set minify: false in vite.config.ts
- This eliminates all minification-related variable conflicts
- Trade-off: Bundle size 3MB → 6.5MB (unminified)
- The app should now load correctly in production

This is a temporary solution. The root cause appears to be related
to how the codebase is structured causing Terser to create duplicate
identifiers during chunk optimization.

Next steps could include:
- Investigating code duplication issues
- Switching to esbuild minifier
- Restructuring problematic imports

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 11:01:45 +07:00
dwindown
877223342e Fix production build variable collision with safer Terser config
Disabled aggressive Terser optimizations that were causing variable
name conflicts (like 'xL' and 'Hf' already declared errors).

Changes:
- Disabled sequences, properties, and join_vars optimizations
- Disabled reduce_funcs and reduce_vars to prevent variable mangling
- Disabled hoist_funs to prevent scope issues
- Disabled evaluate to prevent constant folding issues
- Set keep_fnames: true to preserve function names
- This trades some bundle size (3MB → 3.2MB) for stability

The app should now load correctly in production without minification errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 10:56:35 +07:00
dwindown
0d1f8d795e Fix production build minification error causing blank page
Fixed the "Identifier 'xL' has already been declared" error that occurred
in production builds by switching from SWC minifier to Terser.

Changes:
- Updated vite.config.ts to explicitly use Terser minifier
- Added terser as dev dependency
- Configured safe Terser options to prevent variable name conflicts
- Disabled unsafe optimizations that can cause identifier collisions

This resolves the blank page issue in production while maintaining
bundle size optimization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 10:47:10 +07:00
dwindown
db882f48c4 Add back to home button on auth page
Added a "Kembali ke Beranda" (Back to Home) button on the login/signup
page to allow users to navigate back to the home page without needing
to authenticate.

Changes:
- Imported Link and ArrowLeft icon from lucide-react
- Added button above the auth card that links to "/"
- Wrapped content in a space-y-4 container for proper spacing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 10:42:01 +07:00
dwindown
60baf32f73 Display bootcamp lesson chapters on Product Detail page as marketing content
This commit implements displaying lesson chapters/timeline as marketing content
on the Product Detail page for bootcamp products, helping potential buyers
understand the detailed breakdown of what they'll learn.

## Changes

### Product Detail Page (src/pages/ProductDetail.tsx)
- Updated Lesson interface to include optional chapters property
- Modified fetchCurriculum to fetch chapters along with lessons
- Enhanced renderCurriculumPreview to display chapters as nested content under lessons
- Chapters shown with timestamps and titles, clickable to navigate to bootcamp access page
- Visual hierarchy: Module → Lesson → Chapters with proper indentation and styling

### Review System Fixes
- Fixed review prompt re-appearing after submission (before admin approval)
- Added hasSubmittedReview check to prevent showing prompt when review exists
- Fixed edit review functionality to pre-populate form with existing data
- ReviewModal now handles both INSERT (new) and UPDATE (edit) operations
- Edit resets is_approved to false requiring re-approval

### Video Player Enhancements
- Implemented Adilo/Video.js integration for M3U8/HLS playback
- Added video progress tracking with refs pattern for reliability
- Implemented chapter navigation for both Adilo and YouTube players
- Added keyboard shortcuts (Space, Arrows, F, M, J, L)
- Resume prompt for returning users with saved progress

### Database Migrations
- Added Adilo video support fields (m3u8_url, mp4_url, video_host)
- Created video_progress table for tracking user watch progress
- Fixed consulting slots user_id foreign key
- Added chapters support to products and bootcamp_lessons tables

### Documentation
- Added Adilo implementation plan and quick reference docs
- Cleaned up transcript analysis files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 23:54:32 +07:00
dwindown
41f7b797e7 Fix Plyr player initialization with proper error handling
Added robust error handling for Plyr player instance:
- Check if player.on method exists before using events
- Fallback to polling time updates every 500ms if events unavailable
- Use setInterval to wait for player initialization
- Properly cleanup intervals on component unmount
- Prevents "L.on is not a function" error

This ensures the video player works even if Plyr's event system
has issues initializing, using a reliable polling fallback.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 10:34:45 +07:00
dwindown
7c6d335fa1 Implement Plyr-based video player with comprehensive YouTube UI blocking
Rewrote VideoPlayerWithChapters component using plyr-react with best practices:
- Use Plyr React component wrapper for proper integration
- Aggressive YouTube UI hiding with correct parameters (controls=0, disablekb=1, fs=0)
- Block right-click context menu globally
- Block developer tools shortcuts (F12, Ctrl+Shift+I/J, Ctrl+U)
- CSS pointer-events manipulation to block YouTube iframe interactions
- Only Plyr controls remain interactive
- Accurate time tracking via Plyr's timeupdate event
- Chapter jump functionality via Plyr's currentTime API
- Custom accent color support for Plyr controls
- Hide YouTube's native play button with ::after overlay

This implementation provides:
 Working timeline with accurate duration tracking
 Chapter navigation that jumps to correct timestamps
 Maximum prevention of YouTube UI access
 Custom Plyr controls with your accent color
 Right-click and dev tools blocking
 No "Watch on YouTube" or copy link buttons
 Clean user experience

Based on recommended plyr-react implementation patterns.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 10:30:45 +07:00
dwindown
314cfa6c65 Add strategic overlays to block YouTube UI elements
Implemented multiple overlay divs to prevent access to YouTube branding:
- Top overlay blocks "Watch on YouTube" button and title overlay
- Bottom-right overlay blocks YouTube logo
- Full-screen overlay with context menu prevention blocks right-click
- Set controls=0 parameter to hide YouTube controls completely
- Keep YouTube API working for time tracking and chapter navigation

This prevents users from:
- Clicking "Watch on YouTube" button
- Seeing YouTube logo
- Copying video URL via context menu
- Accessing YouTube native controls

While maintaining:
- Accurate time tracking via getCurrentTime()
- Chapter jump functionality via seekTo()
- Custom timeline with chapters
- Fullscreen capability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 02:13:24 +07:00
dwindown
2357e6ebdd Implement YouTube API for accurate video time tracking and chapter navigation
Replaces Plyr-based implementation with native YouTube IFrame Player API to fix:
- Accurate time tracking via getCurrentTime() polling every 500ms
- Chapter jump functionality using seekTo() and playVideo() API calls
- Right-click prevention with transparent overlay
- Proper chapter highlighting based on current playback time

Technical changes:
- Load YouTube IFrame API script on component mount
- Create YT.Player instance for programmatic control
- Poll getCurrentTime() in interval for real-time tracking
- Use getPlayerById() to retrieve player for jumpToTime operations
- Add pointer-events: none overlay with context menu prevention
- Generate unique iframe IDs for proper API targeting

This approach balances working timeline/jump functionality with preventing
direct URL access via overlay blocking right-click context menus.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 02:09:17 +07:00
dwindown
b7e5385d65 Remove Plyr and YouTube API - use native YouTube iframe
Complete rewrite using YouTube's native iframe embed instead of Plyr + YouTube API.
This fixes all the bugs caused by API conflicts.

Changes:
- Remove Plyr library dependency
- Remove YouTube IFrame API script loading
- Use native YouTube iframe with enablejsapi=1
- Track time via postMessage events (infoDelivery)
- Jump to time via postMessage commands
- Remove all strategic overlays (not needed with native controls)
- Remove custom CSS for hiding YouTube elements
- Simple, clean iframe wrapper with 16:9 aspect ratio
- Enable YouTube's native controls (controls=1)
- Remove sandbox attribute that was blocking features

This approach:
 Fixes fullscreen permissions error
 Time tracking works reliably
 Chapter jump works via postMessage
 No overlays blocking controls
 Native YouTube controls available
 Much simpler code

The trade-off is that users can access YouTube UI, but this is better than
a broken player. The original goal of blocking YouTube UI is not achievable
without introducing significant bugs and complexity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 02:04:08 +07:00
dwindown
a1acbd9395 Fix video player bugs and improve overlay behavior
Fixed issues:
1. Duration now displays correctly using Plyr's time tracking instead of YouTube API
2. Chapter jump functionality now works using Plyr's currentTime property
3. Overlays now properly avoid Plyr controls - only show when paused/ended
4. Hidden YouTube's native play button with CSS

Key changes:
- Use Plyr's native time tracking (player.currentTime) instead of YouTube API
- Jump to time uses Plyr's seek (player.currentTime = time, then play)
- Top overlay only appears when paused/ended (not when playing)
- Paused/ended overlays start at bottom: 80px to avoid Plyr controls
- Added CSS to hide .ytp-large-play-button and .html5-video-player background
- Moved time tracking to onReady callback to ensure player is initialized
- Removed dependencies on chapters from useEffect to prevent re-initialization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 01:51:47 +07:00
dwindown
b2a5d2fca6 Implement YouTube UI blocking with strategic overlays
Based on web research, implemented a comprehensive solution to prevent
users from accessing YouTube UI elements and copying/sharing video URLs.

Changes:
- Load YouTube IFrame Player API to track player state accurately
- Create YT Player instance to detect play/pause/end events
- Add strategic overlays to block specific YouTube UI elements:
  - Top overlay (60px) - blocks "Copy Link" and title (always on)
  - Bottom right overlay - blocks YouTube logo (always on)
  - Bottom left overlay - blocks "Watch on YouTube" (before start)
  - Center overlay - blocks "More Videos" (when paused)
  - Large overlay - blocks related videos wall (when ended)
- Add sandbox attribute to iframe to prevent popups
- Track player state: -1=unstarted, 0=ended, 1=playing, 2=paused, 3=buffering, 5=cued
- All overlays prevent context menu and clicks with preventDefault

This approach is based on successful implementations found in:
- Medium article "How We Safely Embed YouTube Videos"
- xFanatical Safe Doc approach for educational content

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 01:46:30 +07:00
dwindown
50d7d6a8dc Manually create poster element for YouTube UI blocking
Key changes:
- Create .plyr__poster element manually (Plyr doesn't auto-create for YouTube)
- Set z-index: 10 and pointer-events: auto when visible
- Add 500ms delay before hiding poster on play (matches reference)
- Clear timeout if paused before poster fully hides
- poster blocks YouTube UI when paused/initial, fades out when playing

This matches the reference implementation behavior exactly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 01:37:02 +07:00
dwindown
b335164a58 Fix overlay to use Plyr's built-in poster element
Instead of custom overlay, use Plyr's .plyr__poster element which:
- Naturally covers the iframe when paused/initial load
- Allows Plyr controls to receive clicks (z-index hierarchy)
- Hides (opacity: 0) when playing, shows (opacity: 1) when paused
- Blocks YouTube UI interactions when visible

This matches the reference implementation behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 01:33:22 +07:00
dwindown
0df57bbac5 Fix overlay to block YouTube UI when video is paused
Track playback state and show overlay with pointer-events:auto when paused,
pointer-events:none when playing. This blocks YouTube UI (copy link, logo)
when video is paused or initially loaded, while allowing Plyr controls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 01:28:27 +07:00