From ad6cbaf742b58bfcac6236f8524bd4d8373beea7 Mon Sep 17 00:00:00 2001 From: ghassan Date: Sat, 8 Aug 2026 04:01:06 +0300 Subject: [PATCH] Match highlights: DB-backed rounds/points, draggable point capture, sports sheet Edit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match highlights sidebar (videos/types/match.blade.php) - Replaced hardcoded 3-round/5-point/3-review mock with server-rendered loops over $video->matchRounds (with points) and $video->coachReviews. Owner-only buttons carry real DB ids to the existing JS handlers. - Fixed savePoint create branch: was doing parseInt(rawMmSs) which truncated "1.15" -> 1 second. Now sends the parsed value that edit already used. - Added a point-capture bar: clicking + on a round pauses the video and shows a bottom bar with a big draggable red marker + nudge buttons. Dragging seeks the video live; Confirm reads video.currentTime and opens the Add Point modal with mm.ss pre-filled and Action focused. Fixed both server- and JS-rendered round buttons so dynamic reloads keep the new flow. Edit → sports sheet routing - Added sports_match_id to /videos/{video}/edit JSON. - openEditVideoModal delegates type=match videos to openSportsMatchModal — edit mode when a SportsMatch is linked, create-with-attached-video mode when the video is match-typed but has no SportsMatch row yet. - Sports sheet gained attachExistingVideo() so create-mode can be seeded with a video that's already in the library (skips the upload dropzone). Upload chooser mobile bottom-nav - Bottom nav "Upload" now opens the type chooser (bottom sheet on mobile, centred modal on desktop) instead of hard-navigating to /videos/create. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/Http/Controllers/VideoController.php | 3 + resources/views/layouts/app.blade.php | 16 +- .../partials/edit-video-modal.blade.php | 27 +- .../partials/sports-match-modal.blade.php | 86 +++- resources/views/videos/types/match.blade.php | 481 ++++++++++-------- 5 files changed, 384 insertions(+), 229 deletions(-) diff --git a/app/Http/Controllers/VideoController.php b/app/Http/Controllers/VideoController.php index 7642420..725fc96 100644 --- a/app/Http/Controllers/VideoController.php +++ b/app/Http/Controllers/VideoController.php @@ -1133,6 +1133,9 @@ class VideoController extends Controller 'slides' => $slides, 'language' => $video->language, 'audio_tracks' => $audioTracks, + 'sports_match_id'=> $video->type === 'match' + ? \App\Models\SportsMatch::where('video_id', $video->id)->value('id') + : null, ], ]); } diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 9e363f9..36575f4 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -1362,10 +1362,18 @@ Trending - - - Upload - + @auth + + + Upload + + @else + + + Upload + + @endauth History diff --git a/resources/views/layouts/partials/edit-video-modal.blade.php b/resources/views/layouts/partials/edit-video-modal.blade.php index 8b2f456..7c93933 100644 --- a/resources/views/layouts/partials/edit-video-modal.blade.php +++ b/resources/views/layouts/partials/edit-video-modal.blade.php @@ -233,12 +233,8 @@ window._editCurrentVideoId = null; // ── Modal open / close ──────────────────────────────────────────────────────── function openEditVideoModal(videoId) { - if (window.innerWidth < 992) { - window.location.href = `/videos/${videoId}/edit`; - return; - } - window._editCurrentVideoId = videoId; - + // Always resolve type first so a match video opens the sports-match sheet + // instead of the generic video-edit modal — same for mobile. fetch(`/videos/${videoId}/edit`, { headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}', @@ -251,6 +247,25 @@ function openEditVideoModal(videoId) { if (!data.success) { showToast('Failed to load video data', 'error'); return; } const v = data.video; + // Match videos always route to the sports-match sheet — edit the existing + // match if one is linked, otherwise open create-mode with the video already + // attached so the user can add the match details. + if (v.type === 'match' && typeof window.openSportsMatchModal === 'function') { + if (v.sports_match_id) { + window.openSportsMatchModal(v.sports_match_id); + } else { + window.openSportsMatchModal({ videoId: v.id, videoTitle: v.title }); + } + return; + } + + // Mobile fallback for non-match videos: full-page edit view + if (window.innerWidth < 992) { + window.location.href = `/videos/${videoId}/edit`; + return; + } + window._editCurrentVideoId = videoId; + document.getElementById('edit-form').action = `/videos/${videoId}`; // Header diff --git a/resources/views/layouts/partials/sports-match-modal.blade.php b/resources/views/layouts/partials/sports-match-modal.blade.php index 321666a..369b239 100644 --- a/resources/views/layouts/partials/sports-match-modal.blade.php +++ b/resources/views/layouts/partials/sports-match-modal.blade.php @@ -524,6 +524,72 @@ .sm-img-avatar .sm-img-ph { min-height: 74px; gap: 2px; font-size: 10px; } .sm-img-avatar .sm-img-ph i { font-size: 16px; } .sm-img-avatar .sm-img-preview { width: 74px; height: 74px; max-height: 74px; } + +/* ── Mobile: render as a bottom sheet ─────────────────────────── */ +@media (max-width: 768px) { + #sportsMatchModal .modal-dialog { + margin: 0; + max-width: 100%; + width: 100%; + min-height: 100%; + display: flex; + align-items: flex-end; + } + #sportsMatchModal .sm-content { + border-radius: 20px 20px 0 0; + border-left: none; + border-right: none; + border-bottom: none; + width: 100%; + max-height: 92vh; + display: flex; + flex-direction: column; + box-shadow: 0 -12px 40px rgba(0,0,0,.6); + transform: translateY(100%); + transition: transform .3s cubic-bezier(.22,1,.36,1); + } + #sportsMatchModal.show .sm-content { transform: translateY(0); } + + /* Grabber handle at the top */ + #sportsMatchModal .sm-header { + position: relative; + padding-top: 18px; + } + #sportsMatchModal .sm-header::before { + content: ''; + position: absolute; + top: 6px; left: 50%; + transform: translateX(-50%); + width: 40px; height: 4px; + background: #333; border-radius: 2px; + } + + #sportsMatchModal .modal-body { + overflow-y: auto; + -webkit-overflow-scrolling: touch; + flex: 1 1 auto; + padding-bottom: calc(16px + env(safe-area-inset-bottom)); + } + + #sportsMatchModal .sm-footer { + padding: 10px 14px calc(10px + env(safe-area-inset-bottom)); + gap: 6px; + flex-wrap: wrap; + } + #sportsMatchModal .sm-footer .btn { + flex: 1 1 auto; + font-size: 13px; + padding: 10px 12px; + } + + /* Slide-up animation on the modal fade class as well */ + #sportsMatchModal.fade .modal-dialog { transform: none; } +} + +@media (max-width: 480px) { + #sportsMatchModal .sm-header h5 { font-size: 15px; } + #sportsMatchModal .sm-header-icon { width: 34px; height: 34px; font-size: 16px; } +}