where('user_id', $user->id) ->whereNotIn('status', [NovaCardChallengeEntry::STATUS_HIDDEN, NovaCardChallengeEntry::STATUS_REJECTED]) ->selectRaw('challenge_id, COUNT(*) as aggregate') ->groupBy('challenge_id') ->pluck('aggregate', 'challenge_id'); $recentEntriesQuery = NovaCardChallengeEntry::query() ->with(['challenge', 'card']) ->where('user_id', $user->id) ->whereNotIn('status', [NovaCardChallengeEntry::STATUS_HIDDEN, NovaCardChallengeEntry::STATUS_REJECTED]) ->whereHas('challenge') ->whereHas('card'); $recentEntries = $recentEntriesQuery ->latest('created_at') ->limit(8) ->get() ->map(fn (NovaCardChallengeEntry $entry): array => $this->mapEntry($entry)) ->values() ->all(); $activeChallenges = NovaCardChallenge::query() ->whereIn('status', [NovaCardChallenge::STATUS_ACTIVE, NovaCardChallenge::STATUS_COMPLETED]) ->orderByRaw('CASE WHEN featured = 1 THEN 0 ELSE 1 END') ->orderByRaw("CASE WHEN status = 'active' THEN 0 ELSE 1 END") ->orderBy('ends_at') ->orderByDesc('starts_at') ->limit(10) ->get() ->map(fn (NovaCardChallenge $challenge): array => $this->mapChallenge($challenge, $entryCounts)) ->values(); $spotlight = $activeChallenges->first(); $cardLeaders = NovaCard::query() ->where('user_id', $user->id) ->whereNull('deleted_at') ->where('challenge_entries_count', '>', 0) ->orderByDesc('challenge_entries_count') ->orderByDesc('published_at') ->limit(6) ->get() ->map(fn (NovaCard $card): array => [ 'id' => (int) $card->id, 'title' => (string) $card->title, 'status' => (string) $card->status, 'challenge_entries_count' => (int) $card->challenge_entries_count, 'views_count' => (int) $card->views_count, 'comments_count' => (int) $card->comments_count, 'preview_url' => route('studio.cards.preview', ['id' => $card->id]), 'edit_url' => route('studio.cards.edit', ['id' => $card->id]), 'analytics_url' => route('studio.cards.analytics', ['id' => $card->id]), ]) ->values() ->all(); $cardsAvailable = (int) NovaCard::query() ->where('user_id', $user->id) ->whereNull('deleted_at') ->whereNotIn('status', [NovaCard::STATUS_HIDDEN, NovaCard::STATUS_REJECTED]) ->count(); $entryCount = (int) $entryCounts->sum(); $featuredEntries = (int) (clone $recentEntriesQuery) ->whereIn('status', [NovaCardChallengeEntry::STATUS_FEATURED, NovaCardChallengeEntry::STATUS_WINNER]) ->count(); $winnerEntries = (int) (clone $recentEntriesQuery) ->where('status', NovaCardChallengeEntry::STATUS_WINNER) ->count(); return [ 'summary' => [ 'active_challenges' => (int) $activeChallenges->where('status', NovaCardChallenge::STATUS_ACTIVE)->count(), 'joined_challenges' => (int) $entryCounts->keys()->count(), 'entries_submitted' => $entryCount, 'featured_entries' => $featuredEntries, 'winner_entries' => $winnerEntries, 'cards_available' => $cardsAvailable, ], 'spotlight' => $spotlight, 'active_challenges' => $activeChallenges->all(), 'recent_entries' => $recentEntries, 'card_leaders' => $cardLeaders, 'reminders' => $this->reminders($cardsAvailable, $entryCount, $activeChallenges, $featuredEntries, $winnerEntries), ]; } private function mapChallenge(NovaCardChallenge $challenge, Collection $entryCounts): array { return [ 'id' => (int) $challenge->id, 'slug' => (string) $challenge->slug, 'title' => (string) $challenge->title, 'description' => $challenge->description, 'prompt' => $challenge->prompt, 'status' => (string) $challenge->status, 'official' => (bool) $challenge->official, 'featured' => (bool) $challenge->featured, 'entries_count' => (int) $challenge->entries_count, 'starts_at' => $challenge->starts_at?->toIso8601String(), 'ends_at' => $challenge->ends_at?->toIso8601String(), 'is_joined' => $entryCounts->has($challenge->id), 'submission_count' => (int) ($entryCounts->get($challenge->id) ?? 0), 'url' => route('cards.challenges.show', ['slug' => $challenge->slug]), ]; } private function mapEntry(NovaCardChallengeEntry $entry): array { return [ 'id' => (int) $entry->id, 'status' => (string) $entry->status, 'submitted_at' => $entry->created_at?->toIso8601String(), 'note' => $entry->note, 'challenge' => [ 'id' => (int) $entry->challenge_id, 'title' => (string) ($entry->challenge?->title ?? 'Challenge'), 'status' => (string) ($entry->challenge?->status ?? ''), 'official' => (bool) ($entry->challenge?->official ?? false), 'url' => $entry->challenge ? route('cards.challenges.show', ['slug' => $entry->challenge->slug]) : route('cards.challenges'), ], 'card' => [ 'id' => (int) $entry->card_id, 'title' => (string) ($entry->card?->title ?? 'Card'), 'preview_url' => $entry->card ? route('studio.cards.preview', ['id' => $entry->card->id]) : route('studio.cards.index'), 'edit_url' => $entry->card ? route('studio.cards.edit', ['id' => $entry->card->id]) : route('studio.cards.create'), 'analytics_url' => $entry->card ? route('studio.cards.analytics', ['id' => $entry->card->id]) : route('studio.cards.index'), ], ]; } private function reminders(int $cardsAvailable, int $entryCount, Collection $activeChallenges, int $featuredEntries, int $winnerEntries): array { $items = []; if ($cardsAvailable === 0) { $items[] = [ 'title' => 'Create a card to join challenges', 'body' => 'Challenge participation starts from published or ready-to-share cards inside Studio.', 'href' => route('studio.cards.create'), 'cta' => 'Create card', ]; } if ($cardsAvailable > 0 && $entryCount === 0 && $activeChallenges->where('status', NovaCardChallenge::STATUS_ACTIVE)->isNotEmpty()) { $items[] = [ 'title' => 'You have active challenge windows open', 'body' => 'Submit an existing card to the current prompt lineup before the next window closes.', 'href' => route('studio.cards.index'), 'cta' => 'Open cards', ]; } if ($featuredEntries > 0) { $items[] = [ 'title' => 'Featured challenge entries are live', 'body' => 'Review promoted submissions and keep those cards ready for profile, editorial, or follow-up pushes.', 'href' => route('studio.featured'), 'cta' => 'Manage featured', ]; } if ($winnerEntries > 0) { $items[] = [ 'title' => 'Winning challenge work deserves a spotlight', 'body' => 'Use featured content and profile curation to extend the reach of cards that already placed well.', 'href' => route('studio.profile'), 'cta' => 'Open profile', ]; } if ($activeChallenges->isNotEmpty()) { $items[] = [ 'title' => 'Public challenge archive stays one click away', 'body' => 'Use the public challenge directory to review prompts, reference past winners, and see how new runs are framed.', 'href' => route('cards.challenges'), 'cta' => 'Browse challenges', ]; } return collect($items)->take(4)->values()->all(); } }