feat: forum rich-text editor, emoji picker, mentions, discover nav, feed, uploads, profile
Forum: - TipTap WYSIWYG editor with full toolbar - @emoji-mart/react emoji picker (consistent with tweets) - @mention autocomplete with user search API - Fix PHP 8.4 parse errors in Blade templates - Fix thread data display (paginator items) - Align forum page widths to max-w-5xl Discover: - Extract shared _nav.blade.php partial - Add missing nav links to for-you page - Add Following link for authenticated users Feed/Posts: - Post model, controllers, policies, migrations - Feed page components (PostComposer, FeedCard, etc) - Post reactions, comments, saves, reports, sharing - Scheduled publishing support - Link preview controller Profile: - Profile page components (ProfileHero, ProfileTabs) - Profile API controller Uploads: - Upload wizard enhancements - Scheduled publish picker - Studio status bar and readiness checklist
This commit is contained in:
109
app/Services/Posts/PostAchievementService.php
Normal file
109
app/Services/Posts/PostAchievementService.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Posts;
|
||||
|
||||
use App\Models\Post;
|
||||
use App\Models\PostTarget;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Creates achievement posts for significant milestones.
|
||||
*
|
||||
* Achievement types stored in post.meta.achievement_type:
|
||||
* - follower_100 / follower_500 / follower_1000 / follower_5000 / follower_10000
|
||||
* - artwork_100_views / artwork_1000_views / artwork_1000_favs
|
||||
* - award_received
|
||||
*/
|
||||
class PostAchievementService
|
||||
{
|
||||
private const FOLLOWER_MILESTONES = [100, 500, 1_000, 5_000, 10_000, 50_000];
|
||||
private const VIEW_MILESTONES = [100, 1_000, 10_000, 100_000];
|
||||
private const FAV_MILESTONES = [10, 100, 500, 1_000];
|
||||
|
||||
/**
|
||||
* Check if a follower count crosses a milestone and create an achievement post.
|
||||
*/
|
||||
public function maybeFollowerMilestone(User $user, int $newFollowerCount): void
|
||||
{
|
||||
foreach (self::FOLLOWER_MILESTONES as $milestone) {
|
||||
if ($newFollowerCount === $milestone) {
|
||||
$this->createAchievementPost($user, "follower_{$milestone}", [
|
||||
'milestone' => $milestone,
|
||||
'message' => "🎉 Just reached {$milestone} followers! Thank you all!",
|
||||
]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an artwork's view count crosses a milestone.
|
||||
*/
|
||||
public function maybeArtworkViewMilestone(User $user, int $artworkId, int $newViewCount): void
|
||||
{
|
||||
foreach (self::VIEW_MILESTONES as $milestone) {
|
||||
if ($newViewCount === $milestone) {
|
||||
$this->createAchievementPost($user, "artwork_{$milestone}_views", [
|
||||
'artwork_id' => $artworkId,
|
||||
'milestone' => $milestone,
|
||||
'message' => "🎨 One of my artworks just hit {$milestone} views!",
|
||||
], $artworkId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an achievement post for receiving an award.
|
||||
*/
|
||||
public function awardReceived(User $user, string $awardName, ?int $artworkId = null): void
|
||||
{
|
||||
$this->createAchievementPost($user, 'award_received', [
|
||||
'award_name' => $awardName,
|
||||
'artwork_id' => $artworkId,
|
||||
'message' => "🏆 Just received the \"{$awardName}\" award!",
|
||||
], $artworkId);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private function createAchievementPost(
|
||||
User $user,
|
||||
string $achievementType,
|
||||
array $meta,
|
||||
?int $artworkId = null,
|
||||
): void {
|
||||
// Deduplicate: don't create the same achievement post twice
|
||||
$exists = Post::where('user_id', $user->id)
|
||||
->where('type', Post::TYPE_ACHIEVEMENT)
|
||||
->whereJsonContains('meta->achievement_type', $achievementType)
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($user, $achievementType, $meta, $artworkId) {
|
||||
$post = Post::create([
|
||||
'user_id' => $user->id,
|
||||
'type' => Post::TYPE_ACHIEVEMENT,
|
||||
'visibility' => Post::VISIBILITY_PUBLIC,
|
||||
'body' => $meta['message'] ?? null,
|
||||
'status' => Post::STATUS_PUBLISHED,
|
||||
'meta' => array_merge($meta, ['achievement_type' => $achievementType]),
|
||||
]);
|
||||
|
||||
if ($artworkId) {
|
||||
PostTarget::create([
|
||||
'post_id' => $post->id,
|
||||
'target_type' => 'artwork',
|
||||
'target_id' => $artworkId,
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
Log::info("PostAchievementService: created '{$achievementType}' post for user #{$user->id}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user