user(); $groups = Group::query() ->with(['owner.profile', 'members']) ->where(function ($query) use ($user): void { $query->where('owner_user_id', $user->id) ->orWhereHas('members', function ($memberQuery) use ($user): void { $memberQuery->where('user_id', $user->id) ->where('status', Group::STATUS_ACTIVE); }); }) ->orderBy('name') ->get() ->map(fn (Group $group): array => $this->groups->mapGroupCard($group, $user)) ->values() ->all(); return Inertia::render('Studio/StudioGroupsIndex', [ 'title' => 'Groups', 'description' => 'Create collective publishing identities, manage memberships, and switch into shared artwork and collection workflows.', 'groups' => $groups, 'pendingInvites' => $this->memberships->pendingInvitationsForUser($user), 'endpoints' => [ 'create' => route('studio.groups.create'), ], ]); } public function create(): Response { $this->authorize('create', Group::class); return Inertia::render('Studio/StudioGroupCreate', [ 'title' => 'Create Group', 'description' => 'Set up a shared publishing identity for collaborative uploads and collections.', 'visibilityOptions' => [ ['value' => Group::VISIBILITY_PUBLIC, 'label' => 'Public'], ['value' => Group::VISIBILITY_UNLISTED, 'label' => 'Unlisted'], ['value' => Group::VISIBILITY_PRIVATE, 'label' => 'Private'], ], 'membershipPolicyOptions' => [ ['value' => Group::MEMBERSHIP_INVITE_ONLY, 'label' => 'Invite only'], ], 'endpoints' => [ 'store' => route('studio.groups.store'), ], ]); } public function store(StoreGroupRequest $request): RedirectResponse { $this->authorize('create', Group::class); $group = $this->groups->createGroup($request->user(), $request->validated()); return redirect()->route('studio.groups.show', ['group' => $group]); } public function show(Request $request, Group $group): Response { $this->authorize('viewStudio', $group); $viewer = $request->user(); return Inertia::render('Studio/StudioGroupDashboard', [ 'title' => $group->name, 'description' => $group->headline ?: 'Shared publishing overview for this group.', 'studioGroup' => $this->groups->mapGroupDetail($group, $viewer), 'dashboard' => $this->groups->studioDashboardSummary($group), 'draftsPendingAction' => $this->groups->studioArtworkPreviewItems($group, 'drafts', 4), 'recentArtworks' => $this->groups->studioArtworkPreviewItems($group, 'published', 6), 'recentCollections' => $this->groups->studioCollectionPreviewItems($group, 4), 'members' => $this->memberships->mapMembers($group, $viewer), 'recentPosts' => $this->groups->recentPostCards($group, 3), 'recentProjects' => $this->groups->recentProjectCards($group, $viewer, 3), 'recentReleases' => $this->groups->recentReleaseCards($group, $viewer, 3), 'recentChallenges' => $this->groups->recentChallengeCards($group, $viewer, 3), 'recentEvents' => $this->groups->recentEventCards($group, $viewer, 3), 'recentActivity' => $this->groups->studioActivityFeed($group, $viewer, 8), 'recruitment' => $this->groups->recruitmentPayload($group), 'reputationSummary' => $this->reputation->summary($group), 'trustSignals' => $this->reputation->trustSignals($group), 'pendingJoinRequests' => $group->canReviewJoinRequests($viewer) ? $this->joinRequests->mapRequests($group, $viewer, ['bucket' => 'pending', 'per_page' => 4])['items'] : [], 'reviewQueuePreview' => $this->artworkReviews->listing($group, $viewer, ['bucket' => 'submitted', 'per_page' => 4])['items'], 'recentHistory' => $this->groups->recentHistory($group, 6), ]); } public function artworks(Request $request, Group $group): Response { $this->authorize('viewStudio', $group); return Inertia::render('Studio/StudioGroupArtworks', [ 'title' => $group->name . ' Artworks', 'description' => 'Browse every artwork published through this shared identity.', 'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()), 'listing' => $this->groups->studioArtworkListing($group, $request->only(['bucket', 'q', 'page', 'per_page'])), 'uploadUrl' => route('upload', ['group' => $group->slug]), ]); } public function collections(Request $request, Group $group): Response { $this->authorize('viewStudio', $group); return Inertia::render('Studio/StudioGroupCollections', [ 'title' => $group->name . ' Collections', 'description' => 'Manage collections published under this group identity.', 'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()), 'listing' => $this->groups->studioCollectionListing($group, $request->only(['bucket', 'q', 'page', 'per_page'])), 'createUrl' => route('settings.collections.create', ['group' => $group->slug]), ]); } public function members(Request $request, Group $group): Response { $this->authorize('viewStudio', $group); $viewer = $request->user(); $canManageMembers = $group->canManageMembers($viewer); return Inertia::render('Studio/StudioGroupMembers', [ 'title' => $group->name . ' Members', 'description' => 'Invite, remove, and promote the people who can publish and curate under this group.', 'studioGroup' => $this->groups->mapGroupDetail($group, $viewer), 'members' => $this->memberships->mapMembers($group, $viewer), 'canManageMembers' => $canManageMembers, 'permissionOverrideOptions' => array_map(static fn (string $permission): array => [ 'value' => $permission, 'label' => str_replace('_', ' ', $permission), ], Group::allowedPermissionOverrides()), 'endpoints' => $canManageMembers ? [ 'invite' => route('studio.groups.members.store', ['group' => $group]), 'invitations' => route('studio.groups.invitations', ['group' => $group]), 'updatePattern' => route('studio.groups.members.update', ['group' => $group, 'member' => '__MEMBER__']), 'permissionsPattern' => route('studio.groups.members.permissions.update', ['group' => $group, 'member' => '__MEMBER__']), 'transferPattern' => route('studio.groups.members.transfer', ['group' => $group, 'member' => '__MEMBER__']), 'deletePattern' => route('studio.groups.members.destroy', ['group' => $group, 'member' => '__MEMBER__']), ] : null, ]); } public function invitations(Request $request, Group $group): Response { $this->authorize('manageMembers', $group); return Inertia::render('Studio/StudioGroupInvitations', [ 'title' => $group->name . ' Invitations', 'description' => 'Manage outstanding invites, resend collaboration roles, and review recent invite history for this group.', 'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()), 'members' => $this->memberships->mapMembers($group, $request->user()), 'invitations' => $this->memberships->mapInvitations($group, $request->user()), 'endpoints' => [ 'invite' => route('studio.groups.members.store', ['group' => $group]), 'deletePattern' => route('studio.groups.invitations.destroy', ['group' => $group, 'invitation' => '__INVITATION__']), ], ]); } public function settings(Request $request, Group $group): Response { $this->authorize('update', $group); return Inertia::render('Studio/StudioGroupSettings', [ 'title' => $group->name . ' Settings', 'description' => 'Update the public presentation and collaboration defaults for this group.', 'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()), 'featuredArtworkOptions' => $this->groups->studioFeaturedArtworkOptions($group), 'visibilityOptions' => [ ['value' => Group::VISIBILITY_PUBLIC, 'label' => 'Public'], ['value' => Group::VISIBILITY_UNLISTED, 'label' => 'Unlisted'], ['value' => Group::VISIBILITY_PRIVATE, 'label' => 'Private'], ], 'membershipPolicyOptions' => [ ['value' => Group::MEMBERSHIP_INVITE_ONLY, 'label' => 'Invite only'], ], 'endpoints' => [ 'update' => route('studio.groups.update', ['group' => $group]), 'archive' => route('studio.groups.archive', ['group' => $group]), ], ]); } public function update(UpdateGroupRequest $request, Group $group): RedirectResponse { $this->authorize('update', $group); $group = $this->groups->updateGroup($group, $request->validated(), $request->user()); return redirect()->route('studio.groups.settings', ['group' => $group]); } public function archive(Request $request, Group $group): RedirectResponse { $this->authorize('archive', $group); $group = $this->groups->archiveGroup($group, $request->user()); return redirect()->route('studio.groups.settings', ['group' => $group]); } }