*/ public function getSignals(): array { if (! EarlyGrowth::activityLayerEnabled()) { return []; } $ttl = (int) config('early_growth.cache_ttl.activity', 1800); return Cache::remember('egs.activity_signals', $ttl, fn (): array => $this->buildSignals()); } // โ”€โ”€โ”€ Signal builders โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ private function buildSignals(): array { $signals = []; // ยง8: "X artworks published recently" $recentCount = $this->recentArtworkCount(7); if ($recentCount > 0) { $signals[] = [ 'icon' => '๐ŸŽจ', 'text' => "{$recentCount} artwork" . ($recentCount !== 1 ? 's' : '') . ' published this week', 'type' => 'uploads', ]; } // ยง8: "X new creators joined this month" $newCreators = $this->newCreatorsThisMonth(); if ($newCreators > 0) { $signals[] = [ 'icon' => '๐ŸŒŸ', 'text' => "{$newCreators} new creator" . ($newCreators !== 1 ? 's' : '') . ' joined this month', 'type' => 'creators', ]; } // ยง8: "Trending this week" $trendingCount = $this->recentArtworkCount(7); if ($trendingCount > 0) { $signals[] = [ 'icon' => '๐Ÿ”ฅ', 'text' => 'Trending this week', 'type' => 'trending', ]; } // ยง8: "Rising in Wallpapers" (first content type with recent uploads) $risingType = $this->getRisingContentType(); if ($risingType !== null) { $signals[] = [ 'icon' => '๐Ÿ“ˆ', 'text' => "Rising in {$risingType}", 'type' => 'rising', ]; } return array_values($signals); } /** * Count approved public artworks published in the last N days. */ private function recentArtworkCount(int $days): int { try { return Artwork::query() ->where('is_public', true) ->where('is_approved', true) ->whereNull('deleted_at') ->where('published_at', '>=', now()->subDays($days)) ->count(); } catch (\Throwable) { return 0; } } /** * Count users who registered (email_verified_at set) this calendar month. */ private function newCreatorsThisMonth(): int { try { return User::query() ->whereNotNull('email_verified_at') ->where('email_verified_at', '>=', now()->startOfMonth()) ->count(); } catch (\Throwable) { return 0; } } /** * Returns the name of the content type with the most uploads in the last 30 days, * or null if the content_types table isn't available. */ private function getRisingContentType(): ?string { try { $row = DB::table('artworks') ->join('content_types', 'content_types.id', '=', 'artworks.content_type_id') ->where('artworks.is_public', true) ->where('artworks.is_approved', true) ->whereNull('artworks.deleted_at') ->where('artworks.published_at', '>=', now()->subDays(30)) ->selectRaw('content_types.name, COUNT(*) as cnt') ->groupBy('content_types.id', 'content_types.name') ->orderByDesc('cnt') ->first(); return $row ? (string) $row->name : null; } catch (\Throwable) { return null; } } }