Files
SkinbaseNova/app/Services/Posts/PostAchievementService.php
2026-03-20 21:17:26 +01:00

121 lines
4.3 KiB
PHP

<?php
namespace App\Services\Posts;
use App\Models\Achievement;
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);
}
public function achievementUnlocked(User $user, Achievement $achievement): void
{
$this->createAchievementPost($user, 'unlock_' . $achievement->slug, [
'achievement_id' => $achievement->id,
'achievement_name' => $achievement->name,
'message' => '🎉 Unlocked achievement: ' . $achievement->name,
'xp_reward' => (int) $achievement->xp_reward,
]);
}
// ─────────────────────────────────────────────────────────────────────────
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}");
}
}