diff --git a/resources/views/clients/index.blade.php b/resources/views/clients/index.blade.php
index 6292d9e..1c8e076 100644
--- a/resources/views/clients/index.blade.php
+++ b/resources/views/clients/index.blade.php
@@ -5,5 +5,8 @@
+
+
+
diff --git a/resources/views/components/⚡add-client-contact.blade.php b/resources/views/components/⚡add-client-contact.blade.php
new file mode 100644
index 0000000..bcbdb26
--- /dev/null
+++ b/resources/views/components/⚡add-client-contact.blade.php
@@ -0,0 +1,188 @@
+clientId = $clientId;
+ $this->client = Client::findOrFail($clientId);
+ $this->contactId = null;
+ $this->isPrimary = !$this->client->contacts()->exists();
+
+ $this->resetValidation();
+ Flux::modal('add-contact')->show();
+ }
+
+ #[Computed]
+ public function availableContacts()
+ {
+ if (!$this->client) {
+ return collect();
+ }
+
+ $existingContactIds = $this->client->contacts()->pluck('contacts.id');
+
+ return Contact::whereNotIn('id', $existingContactIds)
+ ->orderBy('last_name')
+ ->orderBy('first_name')
+ ->get();
+ }
+
+ public function openCreateModal(): void
+ {
+ $this->first_name = '';
+ $this->last_name = '';
+ $this->email = '';
+ $this->phone = '';
+ $this->newContactIsPrimary = !$this->client->contacts()->exists();
+
+ $this->resetValidation();
+ Flux::modal('add-contact')->close();
+ Flux::modal('create-client-contact')->show();
+ }
+
+ public function backToSelect(): void
+ {
+ Flux::modal('create-client-contact')->close();
+ Flux::modal('add-contact')->show();
+ }
+
+ public function attachContact(): void
+ {
+ if (!$this->contactId) {
+ return;
+ }
+
+ if ($this->isPrimary) {
+ $this->client->contacts()->updateExistingPivot(
+ $this->client->contacts()->wherePivot('is_primary', true)->pluck('contacts.id'),
+ ['is_primary' => false]
+ );
+ }
+
+ $this->client->contacts()->attach($this->contactId, ['is_primary' => $this->isPrimary]);
+
+ $this->reset(['clientId', 'client', 'contactId', 'isPrimary']);
+ Flux::modal('add-contact')->close();
+ $this->dispatch('client-updated');
+ }
+
+ public function createAndAttach(): void
+ {
+ $this->validate([
+ 'first_name' => 'required|string|max:255',
+ 'last_name' => 'required|string|max:255',
+ 'email' => 'required|email|max:255|unique:contacts,email',
+ 'phone' => 'nullable|string|max:20',
+ ]);
+
+ $contact = Contact::create([
+ 'first_name' => $this->first_name,
+ 'last_name' => $this->last_name,
+ 'email' => $this->email,
+ 'phone' => $this->phone ?: null,
+ ]);
+
+ if ($this->newContactIsPrimary) {
+ $this->client->contacts()->updateExistingPivot(
+ $this->client->contacts()->wherePivot('is_primary', true)->pluck('contacts.id'),
+ ['is_primary' => false]
+ );
+ }
+
+ $this->client->contacts()->attach($contact->id, ['is_primary' => $this->newContactIsPrimary]);
+
+ $this->reset(['clientId', 'client', 'contactId', 'isPrimary', 'first_name', 'last_name', 'email', 'phone', 'newContactIsPrimary']);
+ Flux::modal('create-client-contact')->close();
+ $this->dispatch('client-updated');
+ $this->dispatch('contact-created');
+ }
+
+ #[Computed]
+ public function clientHasContacts(): bool
+ {
+ return $this->client?->contacts()->exists() ?? false;
+ }
+};
+?>
+
+
+
+
+
Add Contact to {{ $client?->name }}
+
+
+ @foreach($this->availableContacts as $contact)
+
+ {{ $contact->full_name }} ({{ $contact->email }})
+
+ @endforeach
+
+
+
+ Create New Contact
+
+
+ @if($this->clientHasContacts)
+
+ @endif
+
+
+
+
+ Add Contact
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/views/components/⚡client-list.blade.php b/resources/views/components/⚡client-list.blade.php
index 9604b2c..08eac85 100644
--- a/resources/views/components/⚡client-list.blade.php
+++ b/resources/views/components/⚡client-list.blade.php
@@ -1,5 +1,6 @@
status = $client->status === ClientStatus::ACTIVE
+ ? ClientStatus::INACTIVE
+ : ClientStatus::ACTIVE;
+ $client->save();
+ }
+
#[On('client-created')]
#[On('client-updated')]
public function refresh(): void
@@ -75,8 +84,8 @@ new class extends Component {
@if($client->primary_contact)
-
{{ $client->primary_contact?->full_name }}
+
@endif
@foreach($client->secondaryContacts as $contact)
@@ -102,14 +111,35 @@ new class extends Component {
wire:click="$dispatch('edit-client', { clientId: {{ $client->id }} })"
icon="pencil">Edit Client
+ @if($client->status === ClientStatus::ACTIVE)
+ Make Inactive
+
+ @else
+ Make Active
+
+ @endif
Add Contact
- Remove Contact
-
+ @if($client->contacts()->count() > 0)
+ Remove Contact
+
+ @endif
+ @if($client->contacts()->count() > 1)
+ Set Primary Contact
+
+ @endif
diff --git a/resources/views/components/⚡remove-client-contact.blade.php b/resources/views/components/⚡remove-client-contact.blade.php
new file mode 100644
index 0000000..f781c7a
--- /dev/null
+++ b/resources/views/components/⚡remove-client-contact.blade.php
@@ -0,0 +1,181 @@
+clientId = $clientId;
+ $this->client = Client::findOrFail($clientId);
+ $this->contactId = null;
+ $this->newPrimaryId = null;
+
+ $this->resetValidation();
+ Flux::modal('remove-contact')->show();
+ }
+
+ #[Computed]
+ public function clientContacts()
+ {
+ if (!$this->client) {
+ return collect();
+ }
+
+ return $this->client->contacts()
+ ->orderBy('last_name')
+ ->orderBy('first_name')
+ ->get();
+ }
+
+ #[Computed]
+ public function selectedContact(): ?Contact
+ {
+ if (!$this->contactId) {
+ return null;
+ }
+
+ return Contact::find($this->contactId);
+ }
+
+ #[Computed]
+ public function isRemovingPrimary(): bool
+ {
+ if (!$this->contactId || !$this->client) {
+ return false;
+ }
+
+ return $this->client->contacts()
+ ->wherePivot('is_primary', true)
+ ->where('contacts.id', $this->contactId)
+ ->exists();
+ }
+
+ #[Computed]
+ public function otherContacts()
+ {
+ if (!$this->client || !$this->contactId) {
+ return collect();
+ }
+
+ return $this->client->contacts()
+ ->where('contacts.id', '!=', $this->contactId)
+ ->orderBy('last_name')
+ ->orderBy('first_name')
+ ->get();
+ }
+
+ #[Computed]
+ public function needsNewPrimarySelection(): bool
+ {
+ return $this->isRemovingPrimary && $this->otherContacts->count() > 1;
+ }
+
+ public function removeContact(): void
+ {
+ if (!$this->contactId) {
+ return;
+ }
+
+ $otherContacts = $this->otherContacts;
+
+ // Detach the selected contact
+ $this->client->contacts()->detach($this->contactId);
+
+ // Handle primary contact assignment
+ if ($otherContacts->count() === 1) {
+ // Only one remaining - make them primary
+ $this->client->contacts()->updateExistingPivot(
+ $otherContacts->first()->id,
+ ['is_primary' => true]
+ );
+ } elseif ($otherContacts->count() > 1 && $this->isRemovingPrimary) {
+ // Multiple remaining and removing primary - use selected new primary
+ if ($this->newPrimaryId) {
+ // Clear any existing primary
+ $this->client->contacts()->wherePivot('is_primary', true)
+ ->each(fn ($contact) => $this->client->contacts()->updateExistingPivot(
+ $contact->id,
+ ['is_primary' => false]
+ ));
+
+ // Set new primary
+ $this->client->contacts()->updateExistingPivot(
+ $this->newPrimaryId,
+ ['is_primary' => true]
+ );
+ }
+ }
+
+ $this->reset(['clientId', 'client', 'contactId', 'newPrimaryId']);
+ Flux::modal('remove-contact')->close();
+ $this->dispatch('client-updated');
+ }
+
+ #[Computed]
+ public function canSubmit(): bool
+ {
+ if (!$this->contactId) {
+ return false;
+ }
+
+ if ($this->needsNewPrimarySelection && !$this->newPrimaryId) {
+ return false;
+ }
+
+ return true;
+ }
+};
+?>
+
+
+
+
+
Remove Contact from {{ $client?->name }}
+
+ @if($this->clientContacts->isEmpty())
+
This client has no contacts.
+ @else
+
+ @foreach($this->clientContacts as $contact)
+
+ {{ $contact->full_name }}
+ @if($contact->pivot->is_primary) (Primary) @endif
+
+ @endforeach
+
+
+ @if($this->needsNewPrimarySelection)
+
+ @foreach($this->otherContacts as $contact)
+
+ @endforeach
+
+ @endif
+
+
+
+
+ Remove Contact
+
+
+ @endif
+
+
+
\ No newline at end of file
diff --git a/resources/views/components/⚡set-primary-contact.blade.php b/resources/views/components/⚡set-primary-contact.blade.php
new file mode 100644
index 0000000..2be740a
--- /dev/null
+++ b/resources/views/components/⚡set-primary-contact.blade.php
@@ -0,0 +1,84 @@
+clientId = $clientId;
+ $this->client = Client::findOrFail($clientId);
+ $this->primaryId = $this->client->contacts()
+ ->wherePivot('is_primary', true)
+ ->first()?->id;
+
+ Flux::modal('set-primary-contact')->show();
+ }
+
+ #[Computed]
+ public function clientContacts()
+ {
+ if (!$this->client) {
+ return collect();
+ }
+
+ return $this->client->contacts()
+ ->orderBy('last_name')
+ ->orderBy('first_name')
+ ->get();
+ }
+
+ public function save(): void
+ {
+ if (!$this->primaryId) {
+ return;
+ }
+
+ // Clear existing primary
+ $this->client->contacts()->wherePivot('is_primary', true)
+ ->each(fn ($contact) => $this->client->contacts()->updateExistingPivot(
+ $contact->id,
+ ['is_primary' => false]
+ ));
+
+ // Set new primary
+ $this->client->contacts()->updateExistingPivot(
+ $this->primaryId,
+ ['is_primary' => true]
+ );
+
+ $this->reset(['clientId', 'client', 'primaryId']);
+ Flux::modal('set-primary-contact')->close();
+ $this->dispatch('client-updated');
+ }
+};
+?>
+
+
+
+
+
Set Primary Contact for {{ $client?->name }}
+
+
+ @foreach($this->clientContacts as $contact)
+
+ @endforeach
+
+
+
+
+
+ Save
+
+
+
+
+
\ No newline at end of file