*/ public array $availableCommunities = []; public ?string $communityLoadError = null; public ?int $newLanguageId = null; public string $newDescription = ''; public ?int $editingChannelId = null; public string $editDisplayName = ''; public ?int $editLanguageId = null; public string $editDescription = ''; public function toggle(int $channelId): void { $channel = PlatformChannel::findOrFail($channelId); $channel->is_active = ! $channel->is_active; $channel->save(); } public function openCreateModal(): void { $this->reset(['newCommunityId', 'newPlatformInstanceId', 'newLanguageId', 'newDescription', 'availableCommunities', 'communityLoadError']); $this->resetErrorBag(); $this->showCreateModal = true; } public function updatedNewPlatformInstanceId(?int $value): void { $this->reset(['newCommunityId', 'availableCommunities', 'communityLoadError']); if (! $value) { return; } $instance = PlatformInstance::find($value); if (! $instance) { return; } try { $this->availableCommunities = app(CommunityDirectory::class)->forInstance($instance); } catch (Exception $e) { $this->communityLoadError = 'Could not reach this instance to list its communities: '.$e->getMessage(); } } public function refreshCommunities(): void { $instance = $this->newPlatformInstanceId ? PlatformInstance::find($this->newPlatformInstanceId) : null; if (! $instance) { return; } app(CommunityDirectory::class)->forget($instance); $this->updatedNewPlatformInstanceId($this->newPlatformInstanceId); } public function closeCreateModal(): void { $this->showCreateModal = false; } public function createChannel(CreateChannelAction $action): void { $this->validate([ 'newCommunityId' => [ 'required', 'integer', Rule::in(collect($this->availableCommunities)->pluck('id')->all()), Rule::unique('platform_channels', 'channel_id') ->where('platform_instance_id', $this->newPlatformInstanceId), ], 'newPlatformInstanceId' => 'required|integer|exists:platform_instances,id', 'newLanguageId' => 'nullable|integer|exists:languages,id', ], [ 'newCommunityId.in' => 'Select a community from this instance.', 'newCommunityId.unique' => 'A channel for this community already exists.', ]); $name = collect($this->availableCommunities)->firstWhere('id', $this->newCommunityId)['name'] ?? null; try { $action->execute( $name, $this->newCommunityId, $this->newPlatformInstanceId, $this->newLanguageId, // Blade textarea binds an empty string when blank; the action expects null for "no description". $this->newDescription !== '' ? $this->newDescription : null, ); } catch (UniqueConstraintViolationException $e) { $this->addError('newCommunityId', 'A channel for this community already exists.'); return; } catch (RuntimeException $e) { $this->addError('newPlatformInstanceId', $e->getMessage()); return; } $this->closeCreateModal(); } public function openEditModal(int $channelId): void { $channel = PlatformChannel::findOrFail($channelId); $this->resetErrorBag(); $this->editingChannelId = $channelId; $this->editDisplayName = $channel->display_name; $this->editLanguageId = $channel->language_id; $this->editDescription = $channel->description ?? ''; } public function closeEditModal(): void { $this->editingChannelId = null; } // The community pairing (name, channel_id, platform_instance_id) is deliberately immutable: // it is the channel's remote identity, unique per instance, and re-pointing it would change // the meaning of every route already attached. public function updateChannel(): void { if ($this->editingChannelId === null) { return; } $this->validate([ 'editDisplayName' => 'required|string|max:255', 'editLanguageId' => 'nullable|integer|exists:languages,id', ]); PlatformChannel::findOrFail($this->editingChannelId)->update([ 'display_name' => $this->editDisplayName, 'language_id' => $this->editLanguageId, 'description' => $this->editDescription !== '' ? $this->editDescription : null, ]); $this->closeEditModal(); } public function openAccountModal(int $channelId): void { $this->managingChannelId = $channelId; } public function closeAccountModal(): void { $this->managingChannelId = null; } public function attachAccount(int $accountId): void { if (! $this->managingChannelId) { return; } $channel = PlatformChannel::findOrFail($this->managingChannelId); if (! $channel->platformAccounts()->where('platform_account_id', $accountId)->exists()) { $channel->platformAccounts()->attach($accountId, [ 'is_active' => true, 'priority' => 1, 'created_at' => now(), 'updated_at' => now(), ]); } } public function detachAccount(int $channelId, int $accountId): void { $channel = PlatformChannel::findOrFail($channelId); $channel->platformAccounts()->detach($accountId); } public function render(): View { $channels = PlatformChannel::with(['platformInstance', 'platformAccounts'])->orderBy('name')->get(); $allAccounts = PlatformAccount::where('is_active', true)->get(); $managingChannel = $this->managingChannelId ? PlatformChannel::with('platformAccounts')->find($this->managingChannelId) : null; $availableAccounts = $managingChannel ? $allAccounts->filter(fn ($account) => ! $managingChannel->platformAccounts->contains('id', $account->id)) : collect(); return view('livewire.channels', [ 'channels' => $channels, 'managingChannel' => $managingChannel, 'editingChannel' => $this->editingChannelId !== null ? PlatformChannel::with('platformInstance')->find($this->editingChannelId) : null, 'availableAccounts' => $availableAccounts, 'platformInstances' => PlatformInstance::where('is_active', true)->orderBy('name')->get(), 'languages' => Language::where('is_active', true)->orderBy('name')->get(), ])->layout('layouts.app'); } }