Add full notification preferences system
Users can now control which in-app and email notifications they receive from their Settings tab on their channel page. Bell (in-app) preferences: - New comment on my video (default: on) - Reply to my comment (default: on) - Comment liked (default: on) - Video liked (default: on) - New subscriber (default: on) - New video from channels I follow (default: on) - New post from channels I follow (default: on) - New user registration — super admins only (default: on) Email preferences (same set plus): - Comment liked (default: off — too noisy) - Video liked (default: off — too noisy) - New post from channels I follow (default: off) - My video finished processing (default: on) - Weekly activity digest every Monday (default: on) - New user registration — super admins only (default: on) Implementation: - Migration: notification_preferences JSON column on users table - User::notificationPref($key) helper with typed defaults - All existing notification classes updated to check prefs in via() - 4 new notification classes: NewSubscriberNotification, VideoLikedNotification, NewPostNotification, WeeklyDigestNotification - 8 new email views matching existing dark theme - SendWeeklyDigest artisan command, scheduled every Monday 09:00 - NewSubscriberNotification wired into UserController::toggleSubscribe - VideoLikedNotification wired into UserController::toggleLike - NewPostNotification wired into PostController::store (to all subscribers) - Bell renderer updated for new_subscriber, video_like, new_post types - Preferences saved via AJAX (POST /settings/notifications) — instant toggle with automatic revert on failure Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
1 parent
3fe167e33f
commit
f8d13457fa
26 files changed
+808
-18
No files matched your search
@@ -0,0 +1,27 @@
|
||||
<x-emails.layout subject="{{ $liker->name }} liked your comment">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">👍</div>
|
||||
|
||||
<h1 class="email-title">Your comment got a like!</h1>
|
||||
<p class="email-subtitle">On the video <strong style="color:#f1f1f1;">{{ $video->title }}</strong>.</p>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $recipient->name }}</strong>,</p>
|
||||
<p class="email-text">
|
||||
<strong style="color:#f1f1f1;">{{ $liker->name }}</strong> liked your comment:
|
||||
</p>
|
||||
|
||||
<div class="email-infobox">
|
||||
<div class="email-infobox-label">Your Comment</div>
|
||||
<div style="color:#e0e0e0;font-size:14px;line-height:1.6;padding:4px 0;">
|
||||
"{{ \Illuminate\Support\Str::limit(strip_tags($comment->body), 200) }}"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('videos.show', $video) }}" class="email-btn">▶ View Video</a>
|
||||
</div>
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
@@ -0,0 +1,27 @@
|
||||
<x-emails.layout subject="{{ $commenter->name }} commented on your video">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">💬</div>
|
||||
|
||||
<h1 class="email-title">New comment on your video</h1>
|
||||
<p class="email-subtitle">Someone left a comment on <strong style="color:#f1f1f1;">{{ $video->title }}</strong>.</p>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $recipient->name }}</strong>,</p>
|
||||
<p class="email-text">
|
||||
<strong style="color:#f1f1f1;">{{ $commenter->name }}</strong> commented on your video:
|
||||
</p>
|
||||
|
||||
<div class="email-infobox">
|
||||
<div class="email-infobox-label">Comment</div>
|
||||
<div style="color:#e0e0e0;font-size:14px;line-height:1.6;padding:4px 0;">
|
||||
"{{ \Illuminate\Support\Str::limit(strip_tags($comment->body), 200) }}"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('videos.show', $video) }}" class="email-btn">💬 View Comment</a>
|
||||
</div>
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
@@ -0,0 +1,26 @@
|
||||
<x-emails.layout subject="{{ $author->name }} posted something new">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">📝</div>
|
||||
|
||||
<h1 class="email-title">New post from {{ $author->name }}</h1>
|
||||
<p class="email-subtitle">A channel you follow shared something.</p>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $recipient->name }}</strong>,</p>
|
||||
|
||||
@if($post->body)
|
||||
<div class="email-infobox">
|
||||
<div class="email-infobox-label">Post</div>
|
||||
<div style="color:#e0e0e0;font-size:14px;line-height:1.6;padding:4px 0;">
|
||||
"{{ \Illuminate\Support\Str::limit(strip_tags($post->body), 300) }}"
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('channel', $author->channel) }}" class="email-btn">📝 View Post</a>
|
||||
</div>
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
@@ -0,0 +1,27 @@
|
||||
<x-emails.layout subject="{{ $replier->name }} replied to your comment">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">↩️</div>
|
||||
|
||||
<h1 class="email-title">Someone replied to your comment</h1>
|
||||
<p class="email-subtitle">On the video <strong style="color:#f1f1f1;">{{ $video->title }}</strong>.</p>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $recipient->name }}</strong>,</p>
|
||||
<p class="email-text">
|
||||
<strong style="color:#f1f1f1;">{{ $replier->name }}</strong> replied to your comment:
|
||||
</p>
|
||||
|
||||
<div class="email-infobox">
|
||||
<div class="email-infobox-label">Reply</div>
|
||||
<div style="color:#e0e0e0;font-size:14px;line-height:1.6;padding:4px 0;">
|
||||
"{{ \Illuminate\Support\Str::limit(strip_tags($reply->body), 200) }}"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('videos.show', $video) }}" class="email-btn">↩️ View Reply</a>
|
||||
</div>
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
@@ -0,0 +1,21 @@
|
||||
<x-emails.layout subject="{{ $subscriber->name }} subscribed to your channel">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">🔔</div>
|
||||
|
||||
<h1 class="email-title">You have a new subscriber!</h1>
|
||||
<p class="email-subtitle">Your channel is growing.</p>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $recipient->name }}</strong>,</p>
|
||||
<p class="email-text">
|
||||
<strong style="color:#f1f1f1;">{{ $subscriber->name }}</strong> just subscribed to your channel.
|
||||
Keep creating great content!
|
||||
</p>
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('channel', $subscriber->channel) }}" class="email-btn">👤 View Their Profile</a>
|
||||
</div>
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
@@ -0,0 +1,44 @@
|
||||
<x-emails.layout subject="{{ $uploader->name }} uploaded a new video">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">🎬</div>
|
||||
|
||||
<h1 class="email-title">New video from {{ $uploader->name }}</h1>
|
||||
<p class="email-subtitle">A channel you follow just posted.</p>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $recipient->name }}</strong>,</p>
|
||||
<p class="email-text">
|
||||
<strong style="color:#f1f1f1;">{{ $uploader->name }}</strong> uploaded a new video:
|
||||
<strong style="color:#f1f1f1;">"{{ $video->title }}"</strong>
|
||||
</p>
|
||||
|
||||
@if($video->thumbnail)
|
||||
<div class="email-thumb-wrap">
|
||||
<a href="{{ route('videos.show', $video) }}">
|
||||
<img src="{{ route('media.thumbnail', $video->thumbnail) }}" alt="{{ $video->title }}">
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="email-infobox">
|
||||
@if($video->description)
|
||||
<div class="email-inforow">
|
||||
<span class="email-inforow-key">Description</span>
|
||||
<span class="email-inforow-val">{{ \Illuminate\Support\Str::limit($video->description, 100) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($video->formatted_duration)
|
||||
<div class="email-inforow">
|
||||
<span class="email-inforow-key">Duration</span>
|
||||
<span class="email-inforow-val">{{ $video->formatted_duration }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('videos.show', $video) }}" class="email-btn">▶ Watch Now</a>
|
||||
</div>
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
@@ -0,0 +1,28 @@
|
||||
<x-emails.layout subject="{{ $liker->name }} liked your video">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">❤️</div>
|
||||
|
||||
<h1 class="email-title">Someone liked your video!</h1>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $recipient->name }}</strong>,</p>
|
||||
<p class="email-text">
|
||||
<strong style="color:#f1f1f1;">{{ $liker->name }}</strong> liked your video
|
||||
<strong style="color:#f1f1f1;">"{{ $video->title }}"</strong>.
|
||||
</p>
|
||||
|
||||
@if($video->thumbnail)
|
||||
<div class="email-thumb-wrap">
|
||||
<a href="{{ route('videos.show', $video) }}">
|
||||
<img src="{{ route('media.thumbnail', $video->thumbnail) }}" alt="{{ $video->title }}">
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('videos.show', $video) }}" class="email-btn">▶ Watch Video</a>
|
||||
</div>
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
@@ -0,0 +1,63 @@
|
||||
<x-emails.layout subject="Your weekly TAKEONE summary 📊">
|
||||
|
||||
<div style="width:64px;height:64px;border-radius:50%;background:rgba(230,30,30,.12);border:1px solid rgba(230,30,30,.25);margin:0 auto 24px;text-align:center;line-height:64px;font-size:28px;">📊</div>
|
||||
|
||||
<h1 class="email-title">Your week in numbers</h1>
|
||||
<p class="email-subtitle">Here's how your channel did in the last 7 days.</p>
|
||||
|
||||
<p class="email-text">Hi <strong style="color:#f1f1f1;">{{ $creator->name }}</strong>,</p>
|
||||
|
||||
<div class="email-infobox">
|
||||
<div class="email-infobox-label">This Week's Stats</div>
|
||||
<div class="email-inforow">
|
||||
<span class="email-inforow-key">👀 Views</span>
|
||||
<span class="email-inforow-val">{{ number_format($stats['views']) }}</span>
|
||||
</div>
|
||||
<div class="email-inforow">
|
||||
<span class="email-inforow-key">❤️ Likes</span>
|
||||
<span class="email-inforow-val">{{ number_format($stats['likes']) }}</span>
|
||||
</div>
|
||||
<div class="email-inforow">
|
||||
<span class="email-inforow-key">🔔 New Subscribers</span>
|
||||
<span class="email-inforow-val">{{ number_format($stats['new_subs']) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($stats['top_video'])
|
||||
<p class="email-text" style="margin-top:20px;">Your top video this week:</p>
|
||||
|
||||
@if($stats['top_video']->thumbnail)
|
||||
<div class="email-thumb-wrap">
|
||||
<a href="{{ route('videos.show', $stats['top_video']) }}">
|
||||
<img src="{{ route('media.thumbnail', $stats['top_video']->thumbnail) }}" alt="{{ $stats['top_video']->title }}">
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="email-infobox">
|
||||
<div class="email-inforow">
|
||||
<span class="email-inforow-key">Title</span>
|
||||
<span class="email-inforow-val">{{ $stats['top_video']->title }}</span>
|
||||
</div>
|
||||
<div class="email-inforow">
|
||||
<span class="email-inforow-key">Views this week</span>
|
||||
<span class="email-inforow-val">{{ number_format($stats['top_video']->week_views ?? 0) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('videos.show', $stats['top_video']) }}" class="email-btn">▶ Watch Top Video</a>
|
||||
</div>
|
||||
@else
|
||||
<p class="email-text" style="text-align:center;color:var(--text-secondary);">
|
||||
Upload your first video to start tracking performance!
|
||||
</p>
|
||||
<div class="email-btn-wrap">
|
||||
<a href="{{ route('home') }}" class="email-btn">🎬 Go to TAKEONE</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<hr class="email-divider">
|
||||
<p class="email-note">You can manage your notification preferences in your <a href="{{ route('settings') }}">account settings</a>.</p>
|
||||
|
||||
</x-emails.layout>
|
||||
Reference in new issue
Block a user