Feat: integrate reusable confirmation logic across components
- Applied `Confirmation` trait to multiple Livewire components for unified confirmation handling. - Replaced inline confirmation modals with `requireConfirmation` method for streamlined interaction. - Updated button styles and added reusable confirmation prompts for delete/detach actions. - Enhanced `AppRoleService` and `ConnectionProviderService` to support deletion with confirmation.
This commit is contained in:
parent
5eca6d3602
commit
42737a6a2f
@ -63,9 +63,23 @@ private function assignAppPermissionsRole(Role $role, array $appIds): void
|
||||
}, $appIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach an app from a role;
|
||||
*
|
||||
* @param array<int> $appIds Apps to be detached.
|
||||
*/
|
||||
public function detachApps(array $appIds): void
|
||||
{
|
||||
AppRole::query()
|
||||
->whereIn('app_id', $appIds)
|
||||
->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an app-role assignment.
|
||||
*
|
||||
* @param int $id The ID of the pivot table record.
|
||||
*
|
||||
* @throws InvalidArgumentException when id is invalid.
|
||||
* @throws Throwable when an error occurs during the deletion.
|
||||
*/
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
use App\Data\ConnectedApp\{ConnectAppRequest, ConnectedAppData};
|
||||
use App\Data\Ui\ConnectedApps\ConnectedAppData as UiConnectedAppData;
|
||||
use App\Enums\ConnectedAppPermissonEnum;
|
||||
use App\Models\ConnectedApp;
|
||||
use App\Models\{AppRole, ConnectedApp};
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use InvalidArgumentException;
|
||||
@ -69,6 +69,7 @@ public function delete(int $id): void
|
||||
DB::transaction(
|
||||
function () use ($id): void {
|
||||
$app = ConnectedApp::query()->findOrFail($id);
|
||||
AppRole::query()->where('app_id', $app->id)->delete();
|
||||
$app->delete();
|
||||
}
|
||||
);
|
||||
|
||||
@ -16,6 +16,10 @@
|
||||
|
||||
class ConnectionProviderService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AppRoleService $appRoleService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return Collection<int, ConnectionProvider>
|
||||
*/
|
||||
@ -85,6 +89,7 @@ function () use ($slug): void {
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$this->appRoleService->detachApps(array_column($deletedApps, 'id'));
|
||||
// Note: This performs a mass soft-delete query.
|
||||
// Model events for ConnectedApp will NOT fire.
|
||||
$provider->connectedApps()->delete();
|
||||
|
||||
@ -137,3 +137,7 @@ .mary-table-pagination {
|
||||
}
|
||||
}
|
||||
|
||||
/*set background color for table header*/
|
||||
thead {
|
||||
@apply bg-gray-50
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Concerns\Confirmation;
|
||||
use App\Concerns\HandlesOperations;
|
||||
use App\Livewire\Forms\CreateRoleForm;
|
||||
use App\Services\AppRoleService;
|
||||
@ -15,7 +16,7 @@
|
||||
new
|
||||
#[Title('Roles and Apps')]
|
||||
class extends Component {
|
||||
use HandlesOperations;
|
||||
use HandlesOperations, Confirmation;
|
||||
|
||||
protected AppRoleService $appRoleService;
|
||||
public bool $showCreateModal = false;
|
||||
@ -67,6 +68,10 @@ public function clearApps(): void
|
||||
$this->form->appIds = [];
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
dd('hi');
|
||||
}
|
||||
|
||||
public function openCreateModal(): void
|
||||
{
|
||||
@ -152,8 +157,8 @@ class="btn-sm btn-circle btn-soft"
|
||||
/>
|
||||
<x-mary-button
|
||||
icon="lucide.trash"
|
||||
wire:click="delete({{ $row->id }})"
|
||||
spinner="delete({{ $row->id }})"
|
||||
wire:click="requireConfirmation('delete', {{ $row->id }})"
|
||||
spinner="requireConfirmation('delete', {{ $row->id }})"
|
||||
variant="danger"
|
||||
class="btn-sm btn-circle btn-error btn-soft"
|
||||
/>
|
||||
@ -181,17 +186,32 @@ class="btn-sm btn-circle btn-error btn-soft"
|
||||
clear-action="clearApps"
|
||||
label="Apps"
|
||||
/>
|
||||
<x-mary-input
|
||||
label="Duration"
|
||||
wire:model="form.duration"
|
||||
type="number"
|
||||
<div x-data="{ isUnlimited: @entangle('assignForm.isUnlimited') }"
|
||||
class="flex gap-2 items-baseline-last">
|
||||
|
||||
<div class="flex-1 transition-opacity duration-200"
|
||||
x-bind:class="isUnlimited ? 'opacity-50 pointer-events-none' : ''">
|
||||
<x-mary-datepicker
|
||||
label="Date"
|
||||
wire:model="form.validUpto"
|
||||
icon="lucide.calendar"
|
||||
x-bind:disabled="isUnlimited"
|
||||
x-bind:readonly="isUnlimited"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<x-mary-toggle
|
||||
class="toggle-secondary"
|
||||
label="Unlimited"
|
||||
x-model="isUnlimited"
|
||||
/>
|
||||
</div>
|
||||
<x-slot:actions>
|
||||
<x-mary-button @click="$wire.showCreateModal = false" class="btn-ghost">
|
||||
Cancel
|
||||
</x-mary-button>
|
||||
<x-mary-button type="submit" icon="lucide.save" spinner="save">
|
||||
Save Role
|
||||
<x-mary-button type="submit" class="btn-primary" icon="lucide.save" spinner="save">
|
||||
Save
|
||||
</x-mary-button>
|
||||
</x-slot:actions>
|
||||
</x-mary-form>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Concerns\HandlesOperations;
|
||||
use App\Concerns\{Confirmation, HandlesOperations};
|
||||
use App\Data\Role\{AssignAppsToRoleData, AssignUsersToRoleData, RoleAppData};
|
||||
use App\Data\Ui\TableHeader;
|
||||
use App\Livewire\Forms\AssignAppToRoleForm;
|
||||
@ -19,12 +19,11 @@
|
||||
#[Layout('layouts.app.sidebar')]
|
||||
#[Title('Role Details')]
|
||||
class extends Component {
|
||||
use HandlesOperations;
|
||||
use HandlesOperations, Confirmation;
|
||||
|
||||
public int $roleId = 0;
|
||||
|
||||
public string $roleName = '';
|
||||
|
||||
public bool $showAddAppModal = false;
|
||||
|
||||
// UI State for Editing
|
||||
@ -194,11 +193,11 @@ public function updateApp(): void
|
||||
);
|
||||
}
|
||||
|
||||
public function detachApp(int $appId): void
|
||||
public function detachApp(int $id): void
|
||||
{
|
||||
$this->attempt(
|
||||
action: function () use ($appId): void {
|
||||
$this->appRoleService->detach($appId);
|
||||
action: function () use ($id): void {
|
||||
$this->appRoleService->detach($id);
|
||||
unset($this->apps);
|
||||
},
|
||||
successMessage: 'App removed from role.',
|
||||
@ -305,8 +304,8 @@ class="btn-sm btn-soft btn-circle"
|
||||
/>
|
||||
<x-mary-button
|
||||
icon="lucide.trash"
|
||||
wire:click="detachApp({{ $row['id'] }})"
|
||||
spinner="detachApp({{ $row['id'] }})"
|
||||
wire:click="requireConfirmation('detachApp', {{ $row['id'] }})"
|
||||
spinner="requireConfirmation('detachApp', {{ $row['id'] }})"
|
||||
class="btn-sm btn-error btn-soft btn-circle"
|
||||
/>
|
||||
</div>
|
||||
@ -321,7 +320,8 @@ class="btn-sm btn-error btn-soft btn-circle"
|
||||
|
||||
<x-shared.card title="Users" icon="lucide-users-round" class="pb-2 w-full h-min">
|
||||
<x-slot:actions>
|
||||
<x-mary-button wire:click="openAddUserModal" icon="lucide.plus" class="btn-sm">
|
||||
<x-mary-button wire:click="openAddUserModal" spinner="openAddUserModal" icon="lucide.plus"
|
||||
class="btn-sm">
|
||||
Add User
|
||||
</x-mary-button>
|
||||
</x-slot:actions>
|
||||
@ -338,8 +338,8 @@ class="btn-sm btn-error btn-soft btn-circle"
|
||||
@scope('actions', $row)
|
||||
<x-mary-button
|
||||
icon="lucide.trash"
|
||||
wire:click="detachUser({{ $row['id'] }})"
|
||||
spinner="detachUser({{ $row['id'] }})"
|
||||
wire:click="requireConfirmation('detachUser', {{ $row['id'] }})"
|
||||
spinner="requireConfirmation('detachUser', {{ $row['id'] }})"
|
||||
variant="danger"
|
||||
class="btn-sm btn-error btn-soft btn-circle"
|
||||
/>
|
||||
|
||||
@ -1,24 +1,21 @@
|
||||
<?php
|
||||
|
||||
use App\Concerns\HandlesOperations;
|
||||
use App\Concerns\{Confirmation, HandlesOperations};
|
||||
use App\Data\Ui\TableHeader;
|
||||
use App\Models\User;
|
||||
use App\Services\UserService;
|
||||
use App\Services\{UserService, RoleService};
|
||||
use Livewire\Attributes\{Computed, Layout, Title};
|
||||
use Livewire\Component;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
use Spatie\LaravelData\PaginatedDataCollection;
|
||||
use App\Data\Role\RoleData;
|
||||
use App\Data\Role\RoleAppData;
|
||||
use Spatie\LaravelData\{DataCollection, PaginatedDataCollection};
|
||||
use App\Data\Role\{RoleData, RoleAppData};
|
||||
use App\Livewire\Forms\AssignRolesForm;
|
||||
use App\Services\RoleService;
|
||||
use App\Data\Permissions\DeactivatedPermissionData;
|
||||
|
||||
new
|
||||
#[Title('Users')]
|
||||
class extends Component {
|
||||
use HandlesOperations;
|
||||
use HandlesOperations, Confirmation;
|
||||
|
||||
protected UserService $userService;
|
||||
protected RoleService $roleService;
|
||||
@ -253,8 +250,8 @@ class="btn-sm btn-circle btn-soft"
|
||||
/>
|
||||
<x-mary-button
|
||||
icon="lucide.trash"
|
||||
wire:click="delete({{ $row->id }})"
|
||||
spinner="delete({{ $row->id }})"
|
||||
wire:click="requireConfirmation('delete', {{ $row->id }});"
|
||||
spinner="requireConfirmation('delete', {{ $row->id }});"
|
||||
variant="danger"
|
||||
:tooltip="__('Delete user')"
|
||||
class="btn-sm btn-circle btn-error btn-soft"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Concerns\Confirmation;
|
||||
use App\Concerns\HandlesOperations;
|
||||
use App\Data\Ui\ConnectedApps\ConnectedAppData;
|
||||
use App\Data\Ui\TableHeader;
|
||||
@ -15,7 +16,7 @@
|
||||
new
|
||||
#[Title('Connected Apps')]
|
||||
class extends Component {
|
||||
use WithPagination, HandlesOperations;
|
||||
use WithPagination, HandlesOperations, Confirmation;
|
||||
|
||||
protected ConnectedAppService $service;
|
||||
|
||||
@ -87,10 +88,11 @@ public function delete(int $appId): void
|
||||
@scope('actions', $row)
|
||||
<div class="flex">
|
||||
<x-mary-button icon="lucide.edit" wire:click="edit({{$row->id}})" spinner="edit({{$row->id}})"
|
||||
class="mr-2 btn-sm text-gray-500"/>
|
||||
<x-mary-button icon="lucide.trash" wire:click="delete({{$row->id}})" spinner="delete({{$row->id}})"
|
||||
class="mr-2 btn-sm btn-circle text-gray-500"/>
|
||||
<x-mary-button icon="lucide.trash" wire:click="requireConfirmation('delete', {{$row->id}})"
|
||||
spinner="requireConfirmation('delete', {{$row->id}})"
|
||||
variant="danger"
|
||||
class="btn-sm btn-error btn-soft"/>
|
||||
class="btn-sm btn-circle btn-error btn-soft"/>
|
||||
</div>
|
||||
@endscope
|
||||
</x-mary-table>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Concerns\Confirmation;
|
||||
use App\Concerns\HandlesOperations;
|
||||
use App\Data\Ui\TableHeader;
|
||||
use App\Services\ConnectionProviderService;
|
||||
@ -10,14 +11,13 @@
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
new class extends Component {
|
||||
use WithPagination, HandlesOperations;
|
||||
use WithPagination, HandlesOperations, Confirmation;
|
||||
|
||||
protected ConnectionProviderService $service;
|
||||
|
||||
#[DataCollectionOf(TableHeader::class)]
|
||||
public DataCollection $headers;
|
||||
|
||||
public bool $cnfModal = false;
|
||||
public string $selectedProvider = '';
|
||||
|
||||
public function boot(ConnectionProviderService $service): void
|
||||
@ -50,10 +50,10 @@ public function edit(string $providerSlug): void
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
$this->cnfModal = false;
|
||||
$this->attempt(
|
||||
action: function () {
|
||||
$this->service->delete($this->selectedProvider);
|
||||
$this->selectedProvider = '';
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -61,13 +61,7 @@ public function delete(): void
|
||||
public function showModal(string $providerSlug): void
|
||||
{
|
||||
$this->selectedProvider = $providerSlug;
|
||||
$this->cnfModal = true;
|
||||
}
|
||||
|
||||
public function cancelModal(): void
|
||||
{
|
||||
$this->selectedProvider = '';
|
||||
$this->cnfModal = false;
|
||||
$this->requireConfirmation('delete', description: 'This will delete all the connected apps of this provider.');
|
||||
}
|
||||
};
|
||||
?>
|
||||
@ -83,24 +77,13 @@ public function cancelModal(): void
|
||||
@scope('actions', $row)
|
||||
<div class="flex">
|
||||
<x-mary-button icon="lucide.edit" wire:click="edit('{{$row->slug}}')" spinner="edit('{{$row->slug}}')"
|
||||
class="mr-2 btn-sm text-gray-500"/>
|
||||
class="mr-2 btn-sm btn-circle text-gray-500"/>
|
||||
<x-mary-button icon="lucide.trash" wire:click="showModal('{{$row->slug}}')"
|
||||
spinner="showModal('{{$row->slug}}')"
|
||||
variant="danger"
|
||||
class="btn-sm btn-error btn-soft"/>
|
||||
class="btn-sm btn-error btn-circle btn-soft"/>
|
||||
</div>
|
||||
@endscope
|
||||
</x-mary-table>
|
||||
</x-shared.card>
|
||||
<x-mary-modal wire:model="cnfModal" title="Delete Confirmation" persistent separator>
|
||||
<x-mary-alert title="This will delete all the connected apps of this provider."
|
||||
icon="o-exclamation-triangle"
|
||||
class="alert-warning"
|
||||
/>
|
||||
<x-slot:actions>
|
||||
<x-mary-button label="Cancel" wire:click="cancelModal"/>
|
||||
<x-mary-button label="Proceed" wire:click="delete" spinner="delete" class="btn-error"/>
|
||||
</x-slot:actions>
|
||||
</x-mary-modal>
|
||||
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user