13 Commits
Author SHA1 Message Date
ahp 3bf6dae724 feat: manual cert gating, chat layout overhaul, and video player UX fixes
- Certificate: Hardcode approval gate — completely removed the auto-issue path;
  `certRequiresApproval()` now strictly returns `true`, ignoring DB configuration.
- Certificate: Quiz completion now queues a pending record and triggers a
  "Pending approval" notification instead of falsely confirming issuance.
- Certificate: Public endpoints now enforce a guard on `status=issued`; frontend
  strips the auto-issue side effect and claim button (issuance restricted to admins).
- Chats tab: Refactor layout into a full-width centered banner above two
  equal-height side-by-side panels (`grid-cols-1 lg:grid-cols-2`), utilizing
  `max-h` and `overflow-y-auto` to eliminate whitespace bleed.
- Video player: Fix settings flyout prematurely closing on mouse movement (removed
  `setSettingsOpen` from `poke`); add a click-outside listener via `mousedown`.
- Video player: Deduplicate controls — the speed pill now directly cycles playback
  speed, leaving the gear icon as the single entry point for settings (eliminating
  overlapping popovers).
- Video player: Implement full-bleed theater mode using the `-mx-[50vw] w-screen`
  technique, keeping the progress strip constrained to `max-w-5xl` below.
2026-10-18 12:09:30 +03:30
ahp 6228e66d2c feat: production-grade video player — ambient mode, speed controls, hls.js, double-tap, settings flyout
- Ambient canvas (32×18, ~8fps rAF, blur(55px)) behind video; toggleable, persisted
  - Speed controls 0.5×–2× via settings flyout; capRate replaces lockRate, anti-cheat
  preserved
  - hls.js dynamic import for .m3u8 URLs; Safari native HLS fallback; MP4 unchanged
  - Double-tap left=seek back 10s, right=blocked; single-tap toggles play on touch
  - Keyboard: Space/K play-pause, J/← back, L/→ blocked, ↑↓ volume, M mute, F fullscreen
  - Settings flyout with speed picker + ambient toggle (animated, framer-motion)
  - Theater mode toggle, fullscreen API, volume slider with localStorage persistence
  - Buffer visualization behind progress bar, hover timestamp tooltip, playhead thumb
  - All anti-cheat intact: maxTrustedPosRef, PiP block, visibility pause, heartbeat system
2026-10-18 11:10:11 +03:30
ahpandClaude Sonnet 4.6 089c114019 feat: mobile-first responsive overhaul — safe areas, touch targets, bottom sheet, bottom nav
Viewport:
- Add `viewport` export with `viewport-fit=cover` (enables CSS safe-area-inset-*
  on bezel-less iOS/Android) and `interactive-widget=resizes-content` (prevents
  layout jumps from virtual keyboard open/close)

iOS zoom prevention:
- input.tsx, textarea.tsx: change text-sm (14px) → text-base sm:text-sm (16px)
  on mobile; iOS Safari auto-zooms any input with font-size < 16px

Touch targets:
- button.tsx: default h-10 → h-11 (44px), sm h-8 → h-9 (36px), icon h-10→h-11
  matching the 44×44px iOS HIG and WCAG 2.5.5 minimum
- Add touch-manipulation to buttons, inputs, textarea to eliminate 300ms tap delay

Dialog → mobile bottom sheet:
- On mobile (< 640px): anchored to bottom with full width, rounded top corners,
  slide-in-from-bottom / slide-out-to-bottom animation, drag handle affordance,
  max-h-[90svh] + overflow-y-auto to prevent viewport overflow
- Safe area padding: pb-[max(1.25rem,env(safe-area-inset-bottom))]
- On desktop (sm+): unchanged centered modal with zoom animation
- Close button gets a 32×32 tap area on mobile

Mobile navigation:
- New bottom-nav.tsx: persistent 3-tab bottom bar (مسیر/مرکز/لیگ) shown below
  md: breakpoint, hidden on desktop; 56px height + safe-area-inset-bottom;
  active tab gets heavier stroke and scale
- Only shown for authenticated non-admin users
- app-shell.tsx: injects BottomNav; main content gets dynamic padding-bottom to
  clear the bar (56px + safe area) on mobile, reverts to py-10 on md:
- Footer: safe-area-inset-bottom padding so content clears iPhone home indicator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-18 10:51:37 +03:30
ahpandClaude Sonnet 4.6 602d3f2f4d feat: remove glassmorphism from notification toast; improve video player UX
Task 4 — Event Registration Confirmation (glassmorphism removal):
- Replace translucent gradient + backdrop-blur-md toast in use-realtime.tsx
  with a solid bg-card container, full-opacity border, and a colored
  left accent bar — high contrast, readable in all themes, no blur

Task 5 — Video player UX (within anti-cheat constraints):
- Keyboard shortcuts: Space (play/pause), M (mute), ← (seek back 10s),
  F (fullscreen) — active globally, disabled when an input is focused
- Fullscreen button added to the control bar (F key shortcut)
- Volume slider (0–100%) replaces mute-only toggle; volume is persisted
  to localStorage across sessions under key `pargar:volume`
- Buffer range visualized as a translucent white bar behind the playback
  progress track so users see how much is buffered
- Exponential backoff auto-retry on video error: 1s, 2s, 4s … 30s cap;
  retry count shown in error message; manual retry clears the timer
- Speed controls (0.75x–2x) are intentionally absent: the verified-watch
  anti-cheat locks playbackRate=1; changing it would break the heartbeat
  accumulation that gates quiz unlock and certification
- HLS/ABR requires backend FFmpeg transcoding; the player is structured
  so swapping src=mp4 → src=.m3u8 + hls.js is a one-file change when
  the backend pipeline is ready

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-18 10:40:13 +03:30
ahpandClaude Sonnet 4.6 40fa0b8581 fix: quality audit — memory leaks, dead prose classes, stale state scope
- safe-markdown: add `cancelled` flag to async useEffect; no more
  setState after unmount when component is destroyed mid-import
- rich-editor: same cleanup for preview tab effect; also remove dead
  `prose prose-sm max-w-none` classes (Tailwind Typography not installed)
  and replace with explicit arbitrary-selector markdown styling that
  actually renders using existing design tokens
- profile-certificate-slot: drop dead `ORDER_LABEL`, `order` variable,
  and `physicalOrder` from `MineCertificateResponse`; physical orders
  are disabled — these were leftover references causing lint noise
- learning-panel: change `issuingCert: boolean` → `issuingCertFor:
  number | null` so only the targeted user's button shows a spinner;
  a boolean shared across all users caused the wrong row to animate
  when the admin switched selected users mid-request

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-18 10:29:58 +03:30
ahpandClaude Sonnet 4.6 b4a7e7e1d3 fix: resolve TipTap v3 type errors in RichEditor
- Cast editor.storage to any for tiptap-markdown's getMarkdown (untyped extension storage)
- Replace setContent(value, false) with setContent(value, { emitUpdate: false }) for TipTap v3 API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-18 10:18:51 +03:30
ahp 03610bc3d3 feat: implement 8 features across full stack
- Leaderboard: rank-based percentile tiers (champion/gold/silver/bronze),
    deterministic tie-breaking (xp DESC, user_id ASC)
  - Mentor chat: md: breakpoints, safe-area-inset-bottom padding
  - Learning progress: server-side progressPct, curriculum expansion safety
  - Physical orders: hard-disabled with 410 Gone
  - Certificate approval: pending/issued flow, admin issue/revoke endpoints,
    certificate_requires_approval setting (migration 0031)
  - Draft/publish: is_published on lessons and chapters, admin publish UI
    (migration 0030)
  - Video panel: static thumbnails (no preload), client-side pagination
  - Rich editor: TipTap + tiptap-markdown for lesson descriptions,
    marked + DOMPurify for SafeMarkdown rendering
2026-10-18 10:14:22 +03:30
ahp 22d92c133d feat: release v0.2.0 profiles, chat, freeze, and bots
Ship the product pass on the v0.1.3 schema with additive migrations, a replica migration lock, and bot accounts kept out of people lists.
2026-10-10 16:42:35 +03:30
ahp d9a2abb44f feat: release v0.1.3 chat, profiles, and media
Keep read receipts for the other person only, and let photos, voice, and files stay cached until they are actually replaced.
2026-10-09 19:05:59 +03:30
ahp 0958bd365b feat(frontend): wire App Router pages for the LMS flows
Connect login, learning path, quiz, profile, community, and admin routes to the shared feature components.
2026-10-07 19:40:26 +03:30
ahp 5fbf30a70b feat(frontend): add mentor chat and admin studio
Ship realtime mentor messaging and staff control panels for curriculum, users, and registration gates.
2026-10-07 19:40:26 +03:30
ahp 5b4936903a feat(frontend): add learning, community, and profile feature components
Cover verified playback, quizzes, skill tree, certificates, events, league, and registration UI.
2026-10-07 19:40:26 +03:30
ahp 680db7dce0 feat(frontend): add shared client libraries and UI primitives
Introduce API helpers, types, hooks, design-system components, and the authenticated app shell.
2026-10-07 19:40:26 +03:30