user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); $posts = $workspace->posts() ->with(['postPlatforms.socialAccount', 'user']) ->latest('scheduled_at') ->paginate(20); return Inertia::render('posts/Index', [ 'workspace' => $workspace, 'posts' => $posts, ]); } public function calendar(Request $request): Response|RedirectResponse { $workspace = $request->user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); $tz = $workspace->timezone; $weekStart = $request->input('week') ? Carbon::parse($request->input('week'), $tz)->startOfWeek() : Carbon::now($tz)->startOfWeek(); $weekEnd = $weekStart->copy()->endOfWeek(); // Convert to UTC for database query $weekStartUtc = $weekStart->copy()->utc(); $weekEndUtc = $weekEnd->copy()->utc(); $posts = $workspace->posts() ->with(['postPlatforms.socialAccount']) ->whereBetween('scheduled_at', [$weekStartUtc, $weekEndUtc]) ->orderBy('scheduled_at') ->get() ->groupBy(fn ($post) => $post->scheduled_at?->setTimezone($tz)->format('Y-m-d')); return Inertia::render('posts/Calendar', [ 'workspace' => $workspace, 'posts' => $posts, 'currentWeekStart' => $weekStart->format('Y-m-d'), ]); } public function create(Request $request): RedirectResponse { $workspace = $request->user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); $socialAccounts = $workspace->socialAccounts; if ($socialAccounts->isEmpty()) { session()->flash('flash.banner', 'Connect at least one social network before creating a post.'); session()->flash('flash.bannerStyle', 'danger'); return redirect()->route('accounts'); } // Create a draft post - default to today if no date provided $date = $request->input('date') ?: Carbon::now($workspace->timezone)->format('Y-m-d'); $scheduledAt = Carbon::parse($date, $workspace->timezone) ->setTime(9, 0) ->utc(); $post = $workspace->posts()->create([ 'user_id' => $request->user()->id, 'status' => PostStatus::Draft, 'scheduled_at' => $scheduledAt, ]); // Create post_platforms for each connected account foreach ($socialAccounts as $account) { $post->postPlatforms()->create([ 'social_account_id' => $account->id, 'platform' => $account->platform->value, 'content' => '', 'status' => 'pending', ]); } return redirect()->route('posts.edit', $post); } public function store(StorePostRequest $request): RedirectResponse { $workspace = $request->user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); $post = $workspace->posts()->create([ 'user_id' => $request->user()->id, 'status' => $request->input('status', PostStatus::Draft), 'scheduled_at' => $request->input('scheduled_at'), ]); foreach ($request->input('platforms', []) as $platformData) { $postPlatform = $post->postPlatforms()->create([ 'social_account_id' => $platformData['social_account_id'], 'platform' => $platformData['platform'], 'content' => $platformData['content'], 'status' => 'pending', ]); if (! empty($platformData['media_ids'])) { $postPlatform->media()->whereIn('id', $platformData['media_ids'])->update([ 'post_platform_id' => $postPlatform->id, ]); } } $route = $request->input('status') === PostStatus::Scheduled->value ? 'calendar' : 'posts.index'; session()->flash('flash.banner', 'Post created successfully!'); session()->flash('flash.bannerStyle', 'success'); return redirect()->route($route); } public function show(Request $request, Post $post): Response|RedirectResponse { $workspace = $request->user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); if ($post->workspace_id !== $workspace->id) { abort(404); } $post->load(['postPlatforms.socialAccount', 'postPlatforms.media', 'user']); return Inertia::render('posts/Show', [ 'workspace' => $workspace, 'post' => $post, ]); } public function edit(Request $request, Post $post): Response|RedirectResponse { $workspace = $request->user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); if ($post->workspace_id !== $workspace->id) { abort(404); } if ($post->status === PostStatus::Published) { session()->flash('flash.banner', 'Published posts cannot be edited.'); session()->flash('flash.bannerStyle', 'danger'); return redirect()->route('posts.show', $post); } $post->load(['postPlatforms.socialAccount', 'postPlatforms.media']); $socialAccounts = $workspace->socialAccounts; $platformConfigs = $socialAccounts->mapWithKeys(function ($account) { $platform = $account->platform; return [ $account->id => [ 'maxContentLength' => $platform->maxContentLength(), 'maxImages' => $platform->maxImages(), 'allowedMediaTypes' => array_map(fn ($type) => $type->value, $platform->allowedMediaTypes()), 'supportsTextOnly' => $platform->supportsTextOnly(), ], ]; }); return Inertia::render('posts/Edit', [ 'workspace' => $workspace, 'post' => $post, 'socialAccounts' => $socialAccounts, 'platformConfigs' => $platformConfigs, ]); } public function update(UpdatePostRequest $request, Post $post): RedirectResponse { $workspace = $request->user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); if ($post->workspace_id !== $workspace->id) { abort(404); } if ($post->status === PostStatus::Published) { session()->flash('flash.banner', 'Published posts cannot be edited.'); session()->flash('flash.bannerStyle', 'danger'); return back(); } $scheduledAt = $post->scheduled_at; if ($request->has('scheduled_at') && $request->input('scheduled_at')) { $scheduledAt = Carbon::parse($request->input('scheduled_at'), $workspace->timezone)->utc(); } $status = $request->input('status', $post->status); $post->update([ 'status' => $status === 'publishing' ? PostStatus::Publishing : $status, 'scheduled_at' => $scheduledAt, ]); // Get selected platform IDs $selectedPlatformIds = collect($request->input('platforms', []))->pluck('id')->toArray(); // Update all platforms - disable those not selected, update content for selected ones $post->postPlatforms()->update(['enabled' => false]); foreach ($request->input('platforms', []) as $platformData) { $post->postPlatforms() ->where('id', $platformData['id']) ->update([ 'enabled' => true, 'content' => $platformData['content'], ]); } // Dispatch publish job if publishing now if ($status === 'publishing') { PublishPost::dispatch($post); session()->flash('flash.banner', 'Post is being published!'); session()->flash('flash.bannerStyle', 'success'); return redirect()->route('posts.show', $post); } session()->flash('flash.banner', 'Post updated successfully!'); session()->flash('flash.bannerStyle', 'success'); return redirect()->route('posts.show', $post); } public function destroy(Request $request, Post $post): RedirectResponse { $workspace = $request->user()->currentWorkspace; if (! $workspace) { return redirect()->route('workspaces.create'); } $this->authorize('view', $workspace); if ($post->workspace_id !== $workspace->id) { abort(404); } $post->delete(); session()->flash('flash.banner', 'Post deleted successfully!'); session()->flash('flash.bannerStyle', 'success'); return redirect()->route('calendar'); } }