563 lines
26 KiB
PHP
563 lines
26 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Studio;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\ContentType;
|
|
use App\Services\Studio\CreatorStudioAnalyticsService;
|
|
use App\Services\Studio\CreatorStudioAssetService;
|
|
use App\Services\Studio\CreatorStudioCalendarService;
|
|
use App\Services\Studio\CreatorStudioCommentService;
|
|
use App\Services\Studio\CreatorStudioContentService;
|
|
use App\Services\Studio\CreatorStudioFollowersService;
|
|
use App\Services\Studio\CreatorStudioGrowthService;
|
|
use App\Services\Studio\CreatorStudioActivityService;
|
|
use App\Services\Studio\CreatorStudioInboxService;
|
|
use App\Services\Studio\CreatorStudioOverviewService;
|
|
use App\Services\Studio\CreatorStudioPreferenceService;
|
|
use App\Services\Studio\CreatorStudioChallengeService;
|
|
use App\Services\Studio\CreatorStudioSearchService;
|
|
use App\Services\Studio\CreatorStudioScheduledService;
|
|
use App\Support\CoverUrl;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Inertia\Inertia;
|
|
use Inertia\Response;
|
|
|
|
/**
|
|
* Serves Studio Inertia pages for authenticated creators.
|
|
*/
|
|
final class StudioController extends Controller
|
|
{
|
|
public function __construct(
|
|
private readonly CreatorStudioOverviewService $overview,
|
|
private readonly CreatorStudioContentService $content,
|
|
private readonly CreatorStudioAnalyticsService $analytics,
|
|
private readonly CreatorStudioFollowersService $followers,
|
|
private readonly CreatorStudioCommentService $comments,
|
|
private readonly CreatorStudioAssetService $assets,
|
|
private readonly CreatorStudioPreferenceService $preferences,
|
|
private readonly CreatorStudioScheduledService $scheduled,
|
|
private readonly CreatorStudioActivityService $activity,
|
|
private readonly CreatorStudioCalendarService $calendar,
|
|
private readonly CreatorStudioInboxService $inbox,
|
|
private readonly CreatorStudioSearchService $search,
|
|
private readonly CreatorStudioChallengeService $challenges,
|
|
private readonly CreatorStudioGrowthService $growth,
|
|
) {}
|
|
|
|
/**
|
|
* Studio Overview Dashboard (/studio)
|
|
*/
|
|
public function index(Request $request): Response|RedirectResponse
|
|
{
|
|
$user = $request->user();
|
|
$prefs = $this->preferences->forUser($user);
|
|
|
|
if (! $request->boolean('overview') && $prefs['default_landing_page'] !== 'overview') {
|
|
return redirect()->route($this->landingPageRoute($prefs['default_landing_page']), $request->query(), 302);
|
|
}
|
|
|
|
return Inertia::render('Studio/StudioDashboard', [
|
|
'overview' => $this->overview->build($user),
|
|
'analytics' => $this->analytics->overview($user, $prefs['analytics_range_days']),
|
|
]);
|
|
}
|
|
|
|
public function content(Request $request): Response
|
|
{
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
$listing = $this->content->list($request->user(), $request->only(['module', 'bucket', 'q', 'sort', 'page', 'per_page', 'category', 'tag', 'visibility', 'activity_state', 'stale']));
|
|
$listing['default_view'] = $prefs['default_content_view'];
|
|
|
|
return Inertia::render('Studio/StudioContentIndex', [
|
|
'title' => 'Content',
|
|
'description' => 'Manage every artwork, card, collection, and story from one queue.',
|
|
'listing' => $listing,
|
|
'quickCreate' => $this->content->quickCreate(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Artwork Manager (/studio/artworks)
|
|
*/
|
|
public function artworks(Request $request): Response
|
|
{
|
|
$provider = $this->content->provider('artworks');
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
$listing = $this->content->list($request->user(), $request->only(['q', 'sort', 'bucket', 'page', 'per_page', 'category', 'tag']), null, 'artworks');
|
|
$listing['default_view'] = $prefs['default_content_view'];
|
|
|
|
return Inertia::render('Studio/StudioArtworks', [
|
|
'title' => 'Artworks',
|
|
'description' => 'Upload, manage, and review long-form visual work from the shared Creator Studio workflow.',
|
|
'summary' => $provider?->summary($request->user()),
|
|
'listing' => $listing,
|
|
'quickCreate' => $this->content->quickCreate(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Drafts (/studio/drafts)
|
|
*/
|
|
public function drafts(Request $request): Response
|
|
{
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
$listing = $this->content->list($request->user(), $request->only(['module', 'q', 'sort', 'page', 'per_page', 'stale']), 'drafts');
|
|
$listing['default_view'] = $prefs['default_content_view'];
|
|
|
|
return Inertia::render('Studio/StudioDrafts', [
|
|
'title' => 'Drafts',
|
|
'description' => 'Resume unfinished work across every creator module.',
|
|
'listing' => $listing,
|
|
'quickCreate' => $this->content->quickCreate(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Archived (/studio/archived)
|
|
*/
|
|
public function archived(Request $request): Response
|
|
{
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
$listing = $this->content->list($request->user(), $request->only(['module', 'q', 'sort', 'page', 'per_page']), 'archived');
|
|
$listing['default_view'] = $prefs['default_content_view'];
|
|
|
|
return Inertia::render('Studio/StudioArchived', [
|
|
'title' => 'Archived',
|
|
'description' => 'Review hidden, rejected, and archived content in one place.',
|
|
'listing' => $listing,
|
|
'quickCreate' => $this->content->quickCreate(),
|
|
]);
|
|
}
|
|
|
|
public function scheduled(Request $request): Response
|
|
{
|
|
$listing = $this->scheduled->list($request->user(), $request->only(['module', 'q', 'page', 'per_page', 'range', 'start_date', 'end_date']));
|
|
|
|
return Inertia::render('Studio/StudioScheduled', [
|
|
'title' => 'Scheduled',
|
|
'description' => 'Keep track of upcoming publishes across artworks, cards, collections, and stories.',
|
|
'listing' => $listing,
|
|
'endpoints' => [
|
|
'publishNowPattern' => route('api.studio.schedule.publishNow', ['module' => '__MODULE__', 'id' => '__ID__']),
|
|
'unschedulePattern' => route('api.studio.schedule.unschedule', ['module' => '__MODULE__', 'id' => '__ID__']),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function calendar(Request $request): Response
|
|
{
|
|
return Inertia::render('Studio/StudioCalendar', [
|
|
'title' => 'Calendar',
|
|
'description' => 'Plan publishing cadence, spot overloaded days, and move quickly between scheduled work and the unscheduled queue.',
|
|
'calendar' => $this->calendar->build($request->user(), $request->only(['view', 'module', 'status', 'q', 'focus_date'])),
|
|
'endpoints' => [
|
|
'publishNowPattern' => route('api.studio.schedule.publishNow', ['module' => '__MODULE__', 'id' => '__ID__']),
|
|
'unschedulePattern' => route('api.studio.schedule.unschedule', ['module' => '__MODULE__', 'id' => '__ID__']),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function collections(Request $request): Response
|
|
{
|
|
$provider = $this->content->provider('collections');
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
$listing = $this->content->list($request->user(), $request->only(['q', 'sort', 'page', 'per_page', 'visibility']), null, 'collections');
|
|
$listing['default_view'] = $prefs['default_content_view'];
|
|
|
|
return Inertia::render('Studio/StudioCollections', [
|
|
'title' => 'Collections',
|
|
'description' => 'Curate sets, track collection performance, and keep editorial surfaces organised.',
|
|
'summary' => $provider?->summary($request->user()),
|
|
'listing' => $listing,
|
|
'quickCreate' => $this->content->quickCreate(),
|
|
'dashboardUrl' => route('settings.collections.dashboard'),
|
|
]);
|
|
}
|
|
|
|
public function stories(Request $request): Response
|
|
{
|
|
$provider = $this->content->provider('stories');
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
$listing = $this->content->list($request->user(), $request->only(['q', 'sort', 'page', 'per_page', 'activity_state']), null, 'stories');
|
|
$listing['default_view'] = $prefs['default_content_view'];
|
|
|
|
return Inertia::render('Studio/StudioStories', [
|
|
'title' => 'Stories',
|
|
'description' => 'Track drafts, jump into the editor, and monitor story reach from Studio.',
|
|
'summary' => $provider?->summary($request->user()),
|
|
'listing' => $listing,
|
|
'quickCreate' => $this->content->quickCreate(),
|
|
'dashboardUrl' => route('creator.stories.index'),
|
|
]);
|
|
}
|
|
|
|
public function assets(Request $request): Response
|
|
{
|
|
return Inertia::render('Studio/StudioAssets', [
|
|
'title' => 'Assets',
|
|
'description' => 'A reusable creator asset library for card backgrounds, story covers, collection covers, artwork previews, and profile branding.',
|
|
'assets' => $this->assets->library($request->user(), $request->only(['type', 'source', 'sort', 'q', 'page', 'per_page'])),
|
|
]);
|
|
}
|
|
|
|
public function comments(Request $request): Response
|
|
{
|
|
$listing = $this->comments->list($request->user(), $request->only(['module', 'q', 'page', 'per_page']));
|
|
|
|
return Inertia::render('Studio/StudioComments', [
|
|
'title' => 'Comments',
|
|
'description' => 'View context, reply in place, remove unsafe comments, and report issues across all of your content.',
|
|
'listing' => $listing,
|
|
'endpoints' => [
|
|
'replyPattern' => route('api.studio.comments.reply', ['module' => '__MODULE__', 'commentId' => '__COMMENT__']),
|
|
'moderatePattern' => route('api.studio.comments.moderate', ['module' => '__MODULE__', 'commentId' => '__COMMENT__']),
|
|
'reportPattern' => route('api.studio.comments.report', ['module' => '__MODULE__', 'commentId' => '__COMMENT__']),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function followers(Request $request): Response
|
|
{
|
|
return Inertia::render('Studio/StudioFollowers', [
|
|
'title' => 'Followers',
|
|
'description' => 'See who is following your work, who follows back, and which supporters are most established.',
|
|
'listing' => $this->followers->list($request->user(), $request->only(['q', 'sort', 'relationship', 'page'])),
|
|
]);
|
|
}
|
|
|
|
public function activity(Request $request): Response
|
|
{
|
|
return Inertia::render('Studio/StudioActivity', [
|
|
'title' => 'Activity',
|
|
'description' => 'One creator-facing inbox for notifications, comments, and follower activity.',
|
|
'listing' => $this->activity->list($request->user(), $request->only(['type', 'module', 'q', 'page', 'per_page'])),
|
|
'endpoints' => [
|
|
'markAllRead' => route('api.studio.activity.readAll'),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function inbox(Request $request): Response
|
|
{
|
|
return Inertia::render('Studio/StudioInbox', [
|
|
'title' => 'Inbox',
|
|
'description' => 'A creator-first response surface for comments, notifications, followers, reminders, and what needs attention now.',
|
|
'inbox' => $this->inbox->build($request->user(), $request->only(['type', 'module', 'q', 'page', 'per_page', 'read_state', 'priority'])),
|
|
'endpoints' => [
|
|
'markAllRead' => route('api.studio.activity.readAll'),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function search(Request $request): Response
|
|
{
|
|
return Inertia::render('Studio/StudioSearch', [
|
|
'title' => 'Search',
|
|
'description' => 'Search across content, comments, inbox signals, and reusable assets without leaving Creator Studio.',
|
|
'search' => $this->search->build($request->user(), $request->only(['q', 'module', 'type'])),
|
|
'quickCreate' => $this->content->quickCreate(),
|
|
]);
|
|
}
|
|
|
|
public function challenges(Request $request): Response
|
|
{
|
|
$data = $this->challenges->build($request->user());
|
|
|
|
return Inertia::render('Studio/StudioChallenges', [
|
|
'title' => 'Challenges',
|
|
'description' => 'Track active Nova Cards challenge runs, review your submissions, and keep challenge-ready cards close to hand.',
|
|
'summary' => $data['summary'],
|
|
'spotlight' => $data['spotlight'],
|
|
'activeChallenges' => $data['active_challenges'],
|
|
'recentEntries' => $data['recent_entries'],
|
|
'cardLeaders' => $data['card_leaders'],
|
|
'reminders' => $data['reminders'],
|
|
]);
|
|
}
|
|
|
|
public function growth(Request $request): Response
|
|
{
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
$rangeDays = in_array((int) $request->query('range_days', 0), [7, 14, 30, 60, 90], true)
|
|
? (int) $request->query('range_days')
|
|
: $prefs['analytics_range_days'];
|
|
$data = $this->growth->build($request->user(), $rangeDays);
|
|
|
|
return Inertia::render('Studio/StudioGrowth', [
|
|
'title' => 'Growth',
|
|
'description' => 'A creator-readable view of profile readiness, publishing cadence, engagement momentum, and challenge participation.',
|
|
'summary' => $data['summary'],
|
|
'moduleFocus' => $data['module_focus'],
|
|
'checkpoints' => $data['checkpoints'],
|
|
'opportunities' => $data['opportunities'],
|
|
'milestones' => $data['milestones'],
|
|
'momentum' => $data['momentum'],
|
|
'topContent' => $data['top_content'],
|
|
'rangeDays' => $data['range_days'],
|
|
]);
|
|
}
|
|
|
|
public function profile(Request $request): Response
|
|
{
|
|
$user = $request->user()->loadMissing(['profile', 'statistics']);
|
|
$prefs = $this->preferences->forUser($user);
|
|
$socialLinks = DB::table('user_social_links')
|
|
->where('user_id', $user->id)
|
|
->orderBy('platform')
|
|
->get(['platform', 'url'])
|
|
->map(fn ($row): array => [
|
|
'platform' => (string) $row->platform,
|
|
'url' => (string) $row->url,
|
|
])
|
|
->values()
|
|
->all();
|
|
|
|
return Inertia::render('Studio/StudioProfile', [
|
|
'title' => 'Profile',
|
|
'description' => 'Keep your public creator presence aligned with the work you are publishing.',
|
|
'profile' => [
|
|
'name' => $user->name,
|
|
'username' => $user->username,
|
|
'bio' => $user->profile?->about,
|
|
'tagline' => $user->profile?->description,
|
|
'location' => $user->profile?->country,
|
|
'website' => $user->profile?->website,
|
|
'avatar_url' => $user->profile?->avatar_url,
|
|
'cover_url' => $user->cover_hash && $user->cover_ext ? CoverUrl::forUser($user->cover_hash, $user->cover_ext, time()) : null,
|
|
'cover_position' => (int) ($user->cover_position ?? 50),
|
|
'followers' => (int) ($user->statistics?->followers_count ?? 0),
|
|
'profile_url' => '/@' . strtolower((string) $user->username),
|
|
'social_links' => $socialLinks,
|
|
],
|
|
'moduleSummaries' => $this->content->moduleSummaries($user),
|
|
'featuredModules' => $prefs['featured_modules'],
|
|
'featuredContent' => $this->content->selectedItems($user, $prefs['featured_content']),
|
|
'endpoints' => [
|
|
'profile' => route('api.studio.preferences.profile'),
|
|
'avatarUpload' => route('avatar.upload'),
|
|
'coverUpload' => route('api.profile.cover.upload'),
|
|
'coverPosition' => route('api.profile.cover.position'),
|
|
'coverDelete' => route('api.profile.cover.destroy'),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function featured(Request $request): Response
|
|
{
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
|
|
return Inertia::render('Studio/StudioFeatured', [
|
|
'title' => 'Featured',
|
|
'description' => 'Choose the artwork, card, collection, and story that should represent each module on your public profile.',
|
|
'items' => $this->content->featuredCandidates($request->user(), 12),
|
|
'selected' => $prefs['featured_content'],
|
|
'featuredModules' => $prefs['featured_modules'],
|
|
'endpoints' => [
|
|
'save' => route('api.studio.preferences.featured'),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function settings(Request $request): Response
|
|
{
|
|
return Inertia::render('Studio/StudioSettings', [
|
|
'title' => 'Settings',
|
|
'description' => 'Keep system handoff links, legacy dashboards, and future Studio control surfaces organized in one place.',
|
|
'links' => [
|
|
['label' => 'Profile settings', 'url' => route('settings.profile'), 'icon' => 'fa-solid fa-user-gear'],
|
|
['label' => 'Collection dashboard', 'url' => route('settings.collections.dashboard'), 'icon' => 'fa-solid fa-layer-group'],
|
|
['label' => 'Story dashboard', 'url' => route('creator.stories.index'), 'icon' => 'fa-solid fa-feather-pointed'],
|
|
['label' => 'Followers', 'url' => route('dashboard.followers'), 'icon' => 'fa-solid fa-user-group'],
|
|
['label' => 'Received comments', 'url' => route('dashboard.comments.received'), 'icon' => 'fa-solid fa-comments'],
|
|
],
|
|
'sections' => [
|
|
[
|
|
'title' => 'Studio preferences moved into their own surface',
|
|
'body' => 'Use the dedicated Preferences page for layout, landing page, analytics window, widget order, and shortcut controls.',
|
|
'href' => route('studio.preferences'),
|
|
'cta' => 'Open preferences',
|
|
],
|
|
[
|
|
'title' => 'Future-ready control points',
|
|
'body' => 'Notification routing, automation defaults, and collaboration hooks can plug into this settings surface without overloading creator workflow pages.',
|
|
'href' => route('studio.growth'),
|
|
'cta' => 'Review growth',
|
|
],
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function preferences(Request $request): Response
|
|
{
|
|
$prefs = $this->preferences->forUser($request->user());
|
|
|
|
return Inertia::render('Studio/StudioPreferences', [
|
|
'title' => 'Preferences',
|
|
'description' => 'Control how Creator Studio opens, which widgets stay visible, and where your daily workflow starts.',
|
|
'preferences' => $prefs,
|
|
'links' => [
|
|
['label' => 'Profile settings', 'url' => route('settings.profile'), 'icon' => 'fa-solid fa-user-gear'],
|
|
['label' => 'Featured content', 'url' => route('studio.featured'), 'icon' => 'fa-solid fa-wand-magic-sparkles'],
|
|
['label' => 'Growth overview', 'url' => route('studio.growth'), 'icon' => 'fa-solid fa-chart-line'],
|
|
['label' => 'Studio settings', 'url' => route('studio.settings'), 'icon' => 'fa-solid fa-sliders'],
|
|
],
|
|
'endpoints' => [
|
|
'save' => route('api.studio.preferences.settings'),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Edit artwork (/studio/artworks/:id/edit)
|
|
*/
|
|
public function edit(Request $request, int $id): Response
|
|
{
|
|
$artwork = $request->user()->artworks()
|
|
->with(['stats', 'categories.contentType', 'tags', 'artworkAiAssist'])
|
|
->findOrFail($id);
|
|
|
|
$primaryCategory = $artwork->categories->first();
|
|
|
|
return Inertia::render('Studio/StudioArtworkEdit', [
|
|
'artwork' => [
|
|
'id' => $artwork->id,
|
|
'title' => $artwork->title,
|
|
'slug' => $artwork->slug,
|
|
'description' => $artwork->description,
|
|
'is_public' => (bool) $artwork->is_public,
|
|
'visibility' => $artwork->visibility ?: ((bool) $artwork->is_public ? 'public' : 'private'),
|
|
'is_approved' => (bool) $artwork->is_approved,
|
|
'publish_mode' => $artwork->artwork_status === 'scheduled' ? 'schedule' : 'now',
|
|
'publish_at' => $artwork->publish_at?->toIso8601String(),
|
|
'artwork_status' => $artwork->artwork_status,
|
|
'artwork_timezone' => $artwork->artwork_timezone,
|
|
'thumb_url' => $artwork->thumbUrl('md'),
|
|
'thumb_url_lg' => $artwork->thumbUrl('lg'),
|
|
'file_name' => $artwork->file_name,
|
|
'file_size' => $artwork->file_size,
|
|
'width' => $artwork->width,
|
|
'height' => $artwork->height,
|
|
'mime_type' => $artwork->mime_type,
|
|
'content_type_id' => $primaryCategory?->contentType?->id,
|
|
'category_id' => $primaryCategory?->id,
|
|
'parent_category_id' => $primaryCategory?->parent_id ? $primaryCategory->parent_id : $primaryCategory?->id,
|
|
'sub_category_id' => $primaryCategory?->parent_id ? $primaryCategory->id : null,
|
|
'categories' => $artwork->categories->map(fn ($c) => ['id' => $c->id, 'name' => $c->name, 'slug' => $c->slug])->values()->all(),
|
|
'tags' => $artwork->tags->map(fn ($t) => ['id' => $t->id, 'name' => $t->name, 'slug' => $t->slug])->values()->all(),
|
|
'ai_status' => $artwork->ai_status,
|
|
'title_source' => $artwork->title_source ?: 'manual',
|
|
'description_source' => $artwork->description_source ?: 'manual',
|
|
'tags_source' => $artwork->tags_source ?: 'manual',
|
|
'category_source' => $artwork->category_source ?: 'manual',
|
|
// Versioning
|
|
'version_count' => (int) ($artwork->version_count ?? 1),
|
|
'requires_reapproval' => (bool) $artwork->requires_reapproval,
|
|
],
|
|
'contentTypes' => $this->getCategories(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Analytics v1 (/studio/artworks/:id/analytics)
|
|
*/
|
|
public function analytics(Request $request, int $id): Response
|
|
{
|
|
$artwork = $request->user()->artworks()
|
|
->with(['stats', 'awardStat'])
|
|
->findOrFail($id);
|
|
|
|
$stats = $artwork->stats;
|
|
|
|
return Inertia::render('Studio/StudioArtworkAnalytics', [
|
|
'artwork' => [
|
|
'id' => $artwork->id,
|
|
'title' => $artwork->title,
|
|
'slug' => $artwork->slug,
|
|
'thumb_url' => $artwork->thumbUrl('md'),
|
|
],
|
|
'analytics' => [
|
|
'views' => (int) ($stats?->views ?? 0),
|
|
'favourites' => (int) ($stats?->favorites ?? 0),
|
|
'shares' => (int) ($stats?->shares_count ?? 0),
|
|
'comments' => (int) ($stats?->comments_count ?? 0),
|
|
'downloads' => (int) ($stats?->downloads ?? 0),
|
|
'ranking_score' => (float) ($stats?->ranking_score ?? 0),
|
|
'heat_score' => (float) ($stats?->heat_score ?? 0),
|
|
'engagement_velocity' => (float) ($stats?->engagement_velocity ?? 0),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Studio-wide Analytics (/studio/analytics)
|
|
*/
|
|
public function analyticsOverview(Request $request): Response
|
|
{
|
|
$user = $request->user();
|
|
$prefs = $this->preferences->forUser($user);
|
|
$rangeDays = in_array((int) $request->query('range_days', 0), [7, 14, 30, 60, 90], true)
|
|
? (int) $request->query('range_days')
|
|
: $prefs['analytics_range_days'];
|
|
$data = $this->analytics->overview($user, $rangeDays);
|
|
|
|
return Inertia::render('Studio/StudioAnalytics', [
|
|
'totals' => $data['totals'],
|
|
'topContent' => $data['top_content'],
|
|
'moduleBreakdown' => $data['module_breakdown'],
|
|
'viewsTrend' => $data['views_trend'],
|
|
'engagementTrend' => $data['engagement_trend'],
|
|
'publishingTimeline' => $data['publishing_timeline'],
|
|
'comparison' => $data['comparison'],
|
|
'insightBlocks' => $data['insight_blocks'],
|
|
'rangeDays' => $data['range_days'],
|
|
'recentComments' => $this->overview->recentComments($user, 8),
|
|
]);
|
|
}
|
|
|
|
private function getCategories(): array
|
|
{
|
|
return ContentType::with(['rootCategories.children'])->ordered()->get()->map(function ($ct) {
|
|
return [
|
|
'id' => $ct->id,
|
|
'name' => $ct->name,
|
|
'slug' => $ct->slug,
|
|
'categories' => $ct->rootCategories->map(function ($c) {
|
|
return [
|
|
'id' => $c->id,
|
|
'name' => $c->name,
|
|
'slug' => $c->slug,
|
|
'children' => $c->children->map(fn ($ch) => [
|
|
'id' => $ch->id,
|
|
'name' => $ch->name,
|
|
'slug' => $ch->slug,
|
|
])->values()->all(),
|
|
];
|
|
})->values()->all(),
|
|
];
|
|
})->values()->all();
|
|
}
|
|
|
|
private function landingPageRoute(string $page): string
|
|
{
|
|
return match ($page) {
|
|
'content' => 'studio.content',
|
|
'drafts' => 'studio.drafts',
|
|
'scheduled' => 'studio.scheduled',
|
|
'analytics' => 'studio.analytics',
|
|
'activity' => 'studio.activity',
|
|
'calendar' => 'studio.calendar',
|
|
'inbox' => 'studio.inbox',
|
|
'search' => 'studio.search',
|
|
'growth' => 'studio.growth',
|
|
'challenges' => 'studio.challenges',
|
|
'preferences' => 'studio.preferences',
|
|
default => 'studio.index',
|
|
};
|
|
}
|
|
}
|