content->providers()) ->flatMap(fn (CreatorStudioProvider $provider) => $provider->scheduledItems($user, $limit * 2)) ->sortBy(fn (array $item): int => $this->scheduledTimestamp($item)) ->take($limit) ->values() ->all(); } /** * @param array $filters */ public function list(User $user, array $filters = []): array { $module = $this->normalizeModule((string) ($filters['module'] ?? 'all')); $q = trim((string) ($filters['q'] ?? '')); $range = $this->normalizeRange((string) ($filters['range'] ?? 'upcoming')); $startDate = $this->normalizeDate((string) ($filters['start_date'] ?? '')); $endDate = $this->normalizeDate((string) ($filters['end_date'] ?? '')); $page = max(1, (int) ($filters['page'] ?? 1)); $perPage = min(max((int) ($filters['per_page'] ?? 24), 12), 48); $items = $module === 'all' ? collect($this->content->providers())->flatMap(fn (CreatorStudioProvider $provider) => $provider->scheduledItems($user, 120)) : ($this->content->provider($module)?->scheduledItems($user, 120) ?? collect()); if ($q !== '') { $needle = mb_strtolower($q); $items = $items->filter(function (array $item) use ($needle): bool { return collect([ $item['title'] ?? '', $item['subtitle'] ?? '', $item['module_label'] ?? '', ])->contains(fn ($value): bool => is_string($value) && str_contains(mb_strtolower($value), $needle)); }); } $items = $items->filter(function (array $item) use ($range, $startDate, $endDate): bool { $timestamp = $this->scheduledTimestamp($item); if ($timestamp === PHP_INT_MAX) { return false; } if ($range === 'today') { return $timestamp >= now()->startOfDay()->getTimestamp() && $timestamp <= now()->endOfDay()->getTimestamp(); } if ($range === 'week') { return $timestamp >= now()->startOfDay()->getTimestamp() && $timestamp <= now()->addDays(7)->endOfDay()->getTimestamp(); } if ($range === 'month') { return $timestamp >= now()->startOfDay()->getTimestamp() && $timestamp <= now()->addDays(30)->endOfDay()->getTimestamp(); } if ($startDate !== null && $timestamp < strtotime($startDate . ' 00:00:00')) { return false; } if ($endDate !== null && $timestamp > strtotime($endDate . ' 23:59:59')) { return false; } return true; }); $items = $items ->sortBy(fn (array $item): int => $this->scheduledTimestamp($item)) ->values(); $total = $items->count(); $lastPage = max(1, (int) ceil($total / $perPage)); $page = min($page, $lastPage); return [ 'items' => $items->forPage($page, $perPage)->values()->all(), 'meta' => [ 'current_page' => $page, 'last_page' => $lastPage, 'per_page' => $perPage, 'total' => $total, ], 'filters' => [ 'module' => $module, 'q' => $q, 'range' => $range, 'start_date' => $startDate, 'end_date' => $endDate, ], 'module_options' => array_merge([ ['value' => 'all', 'label' => 'All scheduled content'], ], collect($this->content->moduleSummaries($user))->map(fn (array $summary): array => [ 'value' => $summary['key'], 'label' => $summary['label'], ])->all()), 'range_options' => [ ['value' => 'upcoming', 'label' => 'All upcoming'], ['value' => 'today', 'label' => 'Today'], ['value' => 'week', 'label' => 'Next 7 days'], ['value' => 'month', 'label' => 'Next 30 days'], ['value' => 'custom', 'label' => 'Custom range'], ], 'summary' => $this->summary($user), 'agenda' => $this->agenda($user, 14), ]; } public function summary(User $user): array { $items = collect($this->upcoming($user, 200)); return [ 'total' => $items->count(), 'next_publish_at' => $items->first()['scheduled_at'] ?? null, 'by_module' => collect($this->content->moduleSummaries($user)) ->map(fn (array $summary): array => [ 'key' => $summary['key'], 'label' => $summary['label'], 'count' => $items->where('module', $summary['key'])->count(), 'icon' => $summary['icon'], ]) ->values() ->all(), ]; } public function agenda(User $user, int $days = 14): array { return collect($this->upcoming($user, 200)) ->filter(fn (array $item): bool => $this->scheduledTimestamp($item) <= now()->addDays($days)->getTimestamp()) ->groupBy(function (array $item): string { $value = (string) ($item['scheduled_at'] ?? $item['published_at'] ?? now()->toIso8601String()); return date('Y-m-d', strtotime($value)); }) ->map(fn ($group, string $date): array => [ 'date' => $date, 'label' => date('M j', strtotime($date)), 'count' => $group->count(), 'items' => $group->values()->all(), ]) ->values() ->all(); } private function normalizeModule(string $module): string { return in_array($module, ['all', 'artworks', 'cards', 'collections', 'stories'], true) ? $module : 'all'; } private function normalizeRange(string $range): string { return in_array($range, ['upcoming', 'today', 'week', 'month', 'custom'], true) ? $range : 'upcoming'; } private function normalizeDate(string $value): ?string { $value = trim($value); if ($value === '') { return null; } return preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) === 1 ? $value : null; } /** * @param array $item */ private function scheduledTimestamp(array $item): int { return strtotime((string) ($item['scheduled_at'] ?? $item['published_at'] ?? $item['updated_at'] ?? now()->toIso8601String())) ?: PHP_INT_MAX; } }