diff --git a/app/Http/Controllers/Configuracao/PaginaFavoritaController.php b/app/Http/Controllers/Configuracao/PaginaFavoritaController.php new file mode 100644 index 00000000..efc85a01 --- /dev/null +++ b/app/Http/Controllers/Configuracao/PaginaFavoritaController.php @@ -0,0 +1,94 @@ +middleware('permission:config_pagina_favorita', ['only' => ['index', 'update', 'destroy', 'updateOrder', 'edit']]); + } + + /** + * Display a listing of the resource. + */ + public function index() + { + $user = Auth::user(); + $favoritas = PaginaFavorita::where('user_id', $user->id) + ->orderBy('order') + ->get(); + + return view('configuracao.pagina-favorita.index', [ + 'favoritas' => $favoritas, + 'colors' => PaginaFavorita::AVAILABLE_COLORS, + ]); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(PaginaFavorita $paginaFavorita) + { + $this->authorize('update', $paginaFavorita); + + return view('configuracao.pagina-favorita.edit', [ + 'favorita' => $paginaFavorita, + 'colors' => PaginaFavorita::AVAILABLE_COLORS, + ]); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, PaginaFavorita $paginaFavorita) + { + $this->authorize('update', $paginaFavorita); + + $validated = $request->validate([ + 'text' => 'required|string|max:255', + 'color' => 'required|in:'.implode(',', array_keys(PaginaFavorita::AVAILABLE_COLORS)), + ]); + + $paginaFavorita->update($validated); + + return redirect()->route('configuracao.pagina-favorita.index') + ->with('success', 'Página favorita atualizada com sucesso!'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(PaginaFavorita $paginaFavorita) + { + $this->authorize('delete', $paginaFavorita); + + $paginaFavorita->delete(); + + return redirect()->route('configuracao.pagina-favorita.index') + ->with('success', 'Página favorita removida com sucesso!'); + } + + /** + * Update the order of favorites via AJAX. + */ + public function updateOrder(Request $request) + { + $user = Auth::user(); + $order = $request->input('order', []); + + foreach ($order as $index => $id) { + PaginaFavorita::where('id', $id) + ->where('user_id', $user->id) + ->update(['order' => $index]); + } + + return response()->json(['success' => true]); + } +} diff --git a/app/Models/OsLab/PaginaFavorita.php b/app/Models/OsLab/PaginaFavorita.php index df441329..14c138c9 100644 --- a/app/Models/OsLab/PaginaFavorita.php +++ b/app/Models/OsLab/PaginaFavorita.php @@ -8,4 +8,34 @@ class PaginaFavorita extends Model { use HasFactory; + + protected $table = 'pagina_favoritas'; + + protected $fillable = [ + 'user_id', + 'route', + 'text', + 'icon', + 'color', + 'order', + ]; + + protected $casts = [ + 'order' => 'integer', + ]; + + public const AVAILABLE_COLORS = [ + 'btn-primary' => 'Azul (Padrão)', + 'btn-secondary' => 'Cinza', + 'btn-success' => 'Verde', + 'btn-danger' => 'Vermelho', + 'btn-warning' => 'Amarelo', + 'btn-info' => 'Azul Claro', + 'btn-oslab' => 'OSLab', + ]; + + public function user() + { + return $this->belongsTo(\App\Models\User::class); + } } diff --git a/app/Policies/PaginaFavoritaPolicy.php b/app/Policies/PaginaFavoritaPolicy.php new file mode 100644 index 00000000..7a22c675 --- /dev/null +++ b/app/Policies/PaginaFavoritaPolicy.php @@ -0,0 +1,65 @@ +id === $paginaFavorita->user_id; + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return true; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, PaginaFavorita $paginaFavorita): bool + { + return $user->id === $paginaFavorita->user_id; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, PaginaFavorita $paginaFavorita): bool + { + return $user->id === $paginaFavorita->user_id; + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, PaginaFavorita $paginaFavorita): bool + { + return $user->id === $paginaFavorita->user_id; + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, PaginaFavorita $paginaFavorita): bool + { + return $user->id === $paginaFavorita->user_id; + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 54756cd1..08af54a3 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -3,6 +3,8 @@ namespace App\Providers; // use Illuminate\Support\Facades\Gate; +use App\Models\OsLab\PaginaFavorita; +use App\Policies\PaginaFavoritaPolicy; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider @@ -13,7 +15,7 @@ class AuthServiceProvider extends ServiceProvider * @var array */ protected $policies = [ - // + PaginaFavorita::class => PaginaFavoritaPolicy::class, ]; /** diff --git a/app/Services/OsLab/FavoriteMenuService.php b/app/Services/OsLab/FavoriteMenuService.php index 7217944c..d086345b 100644 --- a/app/Services/OsLab/FavoriteMenuService.php +++ b/app/Services/OsLab/FavoriteMenuService.php @@ -67,6 +67,8 @@ public function favoriteRoute($routeName) $paginaFavorita->route = $routeName; $paginaFavorita->icon = $icon; $paginaFavorita->text = $text; + $paginaFavorita->color = 'btn-primary'; + $paginaFavorita->order = PaginaFavorita::where('user_id', $userId)->max('order') + 1; $paginaFavorita->save(); } @@ -92,7 +94,7 @@ public function getUserFavoriteData() { $userId = Auth::id(); - return PaginaFavorita::where('user_id', $userId)->get(); + return PaginaFavorita::where('user_id', $userId)->orderBy('order')->get(); } /** diff --git a/config/adminlte.php b/config/adminlte.php index 9e81f4f4..e51ba281 100644 --- a/config/adminlte.php +++ b/config/adminlte.php @@ -520,6 +520,7 @@ 'config_wiki_fabricante', 'config_wiki_modelo', 'config_sistema', 'config_emitente', + 'config_pagina_favorita', ], 'submenu' => [ @@ -646,6 +647,13 @@ 'active' => ['configuracoes/emitente*'], 'can' => 'config_emitente', ], + [ + 'text' => 'Páginas Favoritas', + 'icon' => 'fas fa-star', + 'route' => 'configuracao.pagina-favorita.index', + 'active' => ['configuracoes/pagina-favorita*'], + 'can' => 'config_pagina_favorita', + ], [ 'text' => 'Backup', 'icon' => 'fa-solid fa-server', diff --git a/config/breadcrumbs.php b/config/breadcrumbs.php index 67fa04d9..5c91af24 100644 --- a/config/breadcrumbs.php +++ b/config/breadcrumbs.php @@ -49,13 +49,13 @@ */ // When route-bound breadcrumbs are used but the current route doesn't have a name (UnnamedRouteException) - 'unnamed-route-exception' => true, + 'unnamed-route-exception' => false, // When route-bound breadcrumbs are used and the matching breadcrumb doesn't exist (InvalidBreadcrumbException) - 'missing-route-bound-breadcrumb-exception' => true, + 'missing-route-bound-breadcrumb-exception' => false, // When a named breadcrumb is used but doesn't exist (InvalidBreadcrumbException) - 'invalid-named-breadcrumb-exception' => true, + 'invalid-named-breadcrumb-exception' => false, /* |-------------------------------------------------------------------------- diff --git a/database/migrations/2024_08_14_094153_create_pagina_favoritas_table.php b/database/migrations/2024_08_14_094153_create_pagina_favoritas_table.php index 2ae99194..17b57648 100644 --- a/database/migrations/2024_08_14_094153_create_pagina_favoritas_table.php +++ b/database/migrations/2024_08_14_094153_create_pagina_favoritas_table.php @@ -12,6 +12,7 @@ public function up(): void { Schema::create('pagina_favoritas', function (Blueprint $table) { + $table->id(); $table->unsignedBigInteger('user_id'); $table->string('route')->index(); $table->string('text')->nullable(); diff --git a/database/migrations/2024_08_14_094154_add_color_and_order_to_pagina_favoritas_table.php b/database/migrations/2024_08_14_094154_add_color_and_order_to_pagina_favoritas_table.php new file mode 100644 index 00000000..bd10a881 --- /dev/null +++ b/database/migrations/2024_08_14_094154_add_color_and_order_to_pagina_favoritas_table.php @@ -0,0 +1,29 @@ +string('color')->default('btn-primary')->after('icon'); + $table->unsignedInteger('order')->default(0)->after('color'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('pagina_favoritas', function (Blueprint $table) { + $table->dropColumn(['color', 'order']); + }); + } +}; diff --git a/database/migrations/2026_05_16_000001_add_id_to_pagina_favoritas_table.php b/database/migrations/2026_05_16_000001_add_id_to_pagina_favoritas_table.php new file mode 100644 index 00000000..d175cbcf --- /dev/null +++ b/database/migrations/2026_05_16_000001_add_id_to_pagina_favoritas_table.php @@ -0,0 +1,41 @@ +getDriverName(); + + if ($driver === 'mysql') { + DB::statement('ALTER TABLE pagina_favoritas ADD COLUMN id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST'); + } elseif ($driver === 'pgsql') { + DB::statement('ALTER TABLE pagina_favoritas ADD COLUMN id BIGSERIAL PRIMARY KEY'); + } else { + Schema::table('pagina_favoritas', function (Blueprint $table) { + $table->bigIncrements('id')->first(); + }); + } + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + if (Schema::hasColumn('pagina_favoritas', 'id')) { + Schema::table('pagina_favoritas', function (Blueprint $table) { + $table->dropColumn('id'); + }); + } + } +}; diff --git a/database/seeders/DefaultsConfigPermissionsSistema.php b/database/seeders/DefaultsConfigPermissionsSistema.php index a0fb37e2..cfd68bbf 100644 --- a/database/seeders/DefaultsConfigPermissionsSistema.php +++ b/database/seeders/DefaultsConfigPermissionsSistema.php @@ -26,6 +26,12 @@ public function run(): void 'guard_name' => 'web', 'group_id' => 11, ], + [ + 'description' => 'Acesso às páginas favoritas', + 'name' => 'config_pagina_favorita', + 'guard_name' => 'web', + 'group_id' => 11, + ], ]; diff --git a/resources/views/configuracao/pagina-favorita/edit.blade.php b/resources/views/configuracao/pagina-favorita/edit.blade.php new file mode 100644 index 00000000..ae586410 --- /dev/null +++ b/resources/views/configuracao/pagina-favorita/edit.blade.php @@ -0,0 +1,114 @@ +@extends('adminlte::page') + +@section('title', 'Editar Página Favorita') + +@section('content_header') +
+
+

Editar Página Favorita

+
+
+ {!! html()->a(route('configuracao.pagina-favorita.index'), 'Voltar') + ->class('btn btn-sm btn-secondary') !!} +
+
+@stop + +@section('content') +
+
+
+
+

Informações da Página Favorita

+
+ + {!! html()->form('put', route('configuracao.pagina-favorita.update', ['pagina_favorita' => $favorita->id]))->open() !!} + @csrf +
+
+ + {!! html()->text('text', old('text', $favorita->text)) + ->class('form-control' . ($errors->has('text') ? ' is-invalid' : '')) + ->id('text') + ->required() !!} + @error('text') + {{ $message }} + @enderror +
+ +
+ + {!! html()->select('color', $colors, old('color', $favorita->color)) + ->class('form-control' . ($errors->has('color') ? ' is-invalid' : '')) + ->id('color') + ->required() !!} + @error('color') + {{ $message }} + @enderror +
+ +
+ +
+ {!! html()->button($favorita->text) + ->type('button') + ->id('preview-button') + ->class('btn ' . $favorita->color) !!} +
+
+ +
+ +
+ Rota: {{ $favorita->route }}
+ Ícone: {{ $favorita->icon }} +
+
+
+ + + {!! html()->form()->close() !!} +
+
+ +
+
+
+

Cores Disponíveis

+
+
+ @foreach ($colors as $colorClass => $colorLabel) +
+ {!! html()->button($colorLabel) + ->type('button') + ->class('btn btn-sm ' . $colorClass) !!} +
+ @endforeach +
+
+
+
+@stop + +@section('js') + +@stop diff --git a/resources/views/configuracao/pagina-favorita/index.blade.php b/resources/views/configuracao/pagina-favorita/index.blade.php new file mode 100644 index 00000000..e6d30ec1 --- /dev/null +++ b/resources/views/configuracao/pagina-favorita/index.blade.php @@ -0,0 +1,157 @@ +@extends('adminlte::page') + +@section('title', 'Gerenciar Páginas Favoritas') + +@section('content_header') +
+
+

Páginas Favoritas

+
+
+@stop + +@section('content') +
+
+
+
+

Gerencie suas páginas favoritas

+
+
+ @if ($favoritas->isEmpty()) +
+ Nenhuma página favorita cadastrada ainda. +
+ @else +
+ Dica: Você pode reorganizar as páginas favorites clicando e arrastando. + +
+ +
+ @foreach ($favoritas as $favorita) +
+
+
+ +
+
+ {{ $favorita->text }} +
+ Rota: {{ $favorita->route }} +
+
+
+ @can('config_pagina_favorita') +
+ + + + +
+ @endcan +
+ @endforeach +
+ @endif +
+
+
+
+ + + +@stop + +@section('css') + +@stop + +@section('js') + + +@stop diff --git a/resources/views/livewire/home/show-user-favorites.blade.php b/resources/views/livewire/home/show-user-favorites.blade.php index cc9dbd6d..16815646 100644 --- a/resources/views/livewire/home/show-user-favorites.blade.php +++ b/resources/views/livewire/home/show-user-favorites.blade.php @@ -6,7 +6,7 @@ {{-- @dump($item) --}}
- diff --git a/routes/web.php b/routes/web.php index f59ed921..cc4e4f9f 100644 --- a/routes/web.php +++ b/routes/web.php @@ -7,6 +7,7 @@ use App\Http\Controllers\Configuracao\Financeiro\CentroCustoController; use App\Http\Controllers\Configuracao\Financeiro\FormaPagamentoController; use App\Http\Controllers\Configuracao\Garantia\GarantiaController; +use App\Http\Controllers\Configuracao\PaginaFavoritaController; use App\Http\Controllers\Configuracao\Parametro\CategoriaController; use App\Http\Controllers\Configuracao\Parametro\StatusController; use App\Http\Controllers\Configuracao\Sistema\SistemaConfigController; @@ -200,6 +201,10 @@ Route::get('backup', [BackupController::class, 'index'])->name('backup.index'); Route::post('backup/download', [BackupController::class, 'download'])->name('backup.download'); Route::post('backup/destroy', [BackupController::class, 'destroy'])->name('backup.delete'); + // Páginas Favoritas + Route::resource('pagina-favorita', PaginaFavoritaController::class) + ->parameters(['pagina-favorita' => 'pagina_favorita']); + Route::post('pagina-favorita/update-order', [PaginaFavoritaController::class, 'updateOrder'])->name('pagina-favorita.update-order'); }); Route::get('favorite/{routeName}', [FavoriteController::class, 'favoriteToggle'])->name('favorite.toggle');