update sistem analisis sentimen
This commit is contained in:
parent
67156e700a
commit
638ae703c0
|
|
@ -9,7 +9,6 @@
|
|||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class RegisteredUserController extends Controller
|
||||
|
|
@ -30,9 +29,40 @@ public function create(): View
|
|||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:255'
|
||||
],
|
||||
|
||||
'email' => [
|
||||
'required',
|
||||
'string',
|
||||
'lowercase',
|
||||
'email',
|
||||
'max:255',
|
||||
'unique:users'
|
||||
],
|
||||
|
||||
'password' => [
|
||||
'required',
|
||||
'confirmed',
|
||||
'string',
|
||||
'min:8',
|
||||
'regex:/[a-z]/',
|
||||
'regex:/[A-Z]/',
|
||||
'regex:/[0-9]/',
|
||||
],
|
||||
|
||||
], [
|
||||
|
||||
'password.min' => 'Password wajib minimal 8 karakter.',
|
||||
|
||||
'password.regex' => 'Password harus mengandung huruf besar, huruf kecil, dan angka.',
|
||||
|
||||
'password.confirmed' => 'Konfirmasi password tidak sesuai.',
|
||||
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
|
|
@ -47,4 +77,4 @@ public function store(Request $request): RedirectResponse
|
|||
|
||||
return redirect(route('dashboard', absolute: false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$search = $request->search;
|
||||
|
||||
$users = User::when($search, function ($query) use ($search) {
|
||||
|
||||
$query->where('name', 'like', "%{$search}%")
|
||||
->orWhere('email', 'like', "%{$search}%");
|
||||
|
||||
})->paginate(5);
|
||||
|
||||
return view('kelolauser.index', compact('users'));
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| UPDATE USER
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required',
|
||||
'email' => 'required|email',
|
||||
'role' => 'required',
|
||||
]);
|
||||
|
||||
$user = User::findOrFail($id);
|
||||
|
||||
$user->update([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'role' => $request->role,
|
||||
]);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success', 'Pengguna berhasil diperbarui.');
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| RESET PASSWORD
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public function updatePassword(Request $request, int $id)
|
||||
{
|
||||
$request->validate([
|
||||
'password' => [
|
||||
'required',
|
||||
'confirmed',
|
||||
'min:8',
|
||||
'regex:/[a-z]/',
|
||||
'regex:/[A-Z]/',
|
||||
'regex:/[0-9]/',
|
||||
],
|
||||
], [
|
||||
|
||||
'password.min' =>
|
||||
'Password minimal 8 karakter.',
|
||||
|
||||
'password.regex' =>
|
||||
'Password harus mengandung huruf besar, huruf kecil, dan angka.',
|
||||
]);
|
||||
|
||||
$user = User::findOrFail($id);
|
||||
|
||||
$user->update([
|
||||
'password' => Hash::make($request->password)
|
||||
]);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success', 'Password berhasil direset.');
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DELETE USER
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public function destroy(int $id)
|
||||
{
|
||||
User::findOrFail($id)->delete();
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success', 'Pengguna berhasil dihapus.');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email|unique:users,email',
|
||||
'role' => 'required|in:admin,staff',
|
||||
'password' => 'required|min:8|confirmed',
|
||||
]);
|
||||
|
||||
User::create([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'role' => $request->role,
|
||||
'password' => bcrypt($request->password),
|
||||
]);
|
||||
|
||||
return redirect()->route('kelola-pengguna.index')
|
||||
->with('success', 'Pengguna berhasil ditambahkan.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth; // ← tambah ini
|
||||
|
||||
class RoleMiddleware
|
||||
{
|
||||
public function handle(Request $request, Closure $next, string $role)
|
||||
{
|
||||
if (!Auth::check() || Auth::user()->role !== $role) // ← ganti auth() ke Auth::
|
||||
{
|
||||
abort(403, 'Akses ditolak.');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,42 +2,26 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
'role', // ← tambah ini
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
|
|
@ -45,4 +29,15 @@ protected function casts(): array
|
|||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// ← tambah 2 method ini di bawah casts()
|
||||
public function isAdmin(): bool
|
||||
{
|
||||
return $this->role === 'admin';
|
||||
}
|
||||
|
||||
public function isStaff(): bool
|
||||
{
|
||||
return $this->role === 'staff';
|
||||
}
|
||||
}
|
||||
|
|
@ -10,9 +10,11 @@
|
|||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
//
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->alias([
|
||||
'role' => \App\Http\Middleware\RoleMiddleware::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
})->create();
|
||||
})->create();
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->enum('role', ['admin', 'staff'])->default('staff')->after('email');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('role');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "TugasAkhirFarah-main",
|
||||
"name": "SistemAnalisisSentimen",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
|
@ -1418,6 +1418,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.9.0",
|
||||
"caniuse-lite": "^1.0.30001759",
|
||||
|
|
@ -2690,6 +2691,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
|
|
@ -3114,6 +3116,7 @@
|
|||
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
|
|
@ -3234,6 +3237,7 @@
|
|||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -3322,6 +3326,7 @@
|
|||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
|
@ -3426,6 +3431,7 @@
|
|||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,25 +1,559 @@
|
|||
<x-guest-layout>
|
||||
<div class="mb-4 text-sm text-gray-600">
|
||||
{{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Lupa Password - SENTARA</title>
|
||||
|
||||
@vite(['resources/css/app.css','resources/js/app.js'])
|
||||
|
||||
<style>
|
||||
body{
|
||||
background:#f5f7fb;
|
||||
font-family:'Poppins', sans-serif;
|
||||
}
|
||||
|
||||
.main-wrapper{
|
||||
min-height:100vh;
|
||||
padding:40px 20px;
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
/* BACKGROUND */
|
||||
.circle-top{
|
||||
position:absolute;
|
||||
top:-120px;
|
||||
right:-120px;
|
||||
width:350px;
|
||||
height:350px;
|
||||
background:#edf3ff;
|
||||
border-radius:50%;
|
||||
z-index:0;
|
||||
}
|
||||
|
||||
.circle-bottom{
|
||||
position:absolute;
|
||||
bottom:-150px;
|
||||
left:-150px;
|
||||
width:320px;
|
||||
height:320px;
|
||||
background:#edf3ff;
|
||||
border-radius:50%;
|
||||
z-index:0;
|
||||
}
|
||||
|
||||
.content{
|
||||
position:relative;
|
||||
z-index:2;
|
||||
width:100%;
|
||||
max-width:950px;
|
||||
}
|
||||
|
||||
/* CARD */
|
||||
.card-box{
|
||||
background:#fff;
|
||||
border-radius:26px;
|
||||
padding:50px;
|
||||
box-shadow:0 10px 35px rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
/* ICON */
|
||||
.icon-wrapper{
|
||||
width:110px;
|
||||
height:110px;
|
||||
background:#edf3ff;
|
||||
border-radius:50%;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
margin:0 auto 25px;
|
||||
}
|
||||
|
||||
/* TITLE */
|
||||
.title{
|
||||
text-align:center;
|
||||
font-size:54px;
|
||||
font-weight:700;
|
||||
color:#0d1b52;
|
||||
line-height:1.2;
|
||||
}
|
||||
|
||||
.subtitle{
|
||||
text-align:center;
|
||||
font-size:22px;
|
||||
color:#475569;
|
||||
margin-top:18px;
|
||||
line-height:1.7;
|
||||
}
|
||||
|
||||
.subtitle span{
|
||||
color:#2563eb;
|
||||
font-weight:700;
|
||||
}
|
||||
|
||||
/* ALERT */
|
||||
.info-box{
|
||||
margin-top:35px;
|
||||
background:#f4f8ff;
|
||||
border:1px solid #dbeafe;
|
||||
border-radius:18px;
|
||||
padding:22px 24px;
|
||||
display:flex;
|
||||
align-items:flex-start;
|
||||
gap:16px;
|
||||
}
|
||||
|
||||
.info-box p{
|
||||
color:#334155;
|
||||
font-size:18px;
|
||||
line-height:1.6;
|
||||
}
|
||||
|
||||
/* SECTION */
|
||||
.section-title{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:12px;
|
||||
margin-top:45px;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.section-title h2{
|
||||
font-size:34px;
|
||||
font-weight:700;
|
||||
color:#0d1b52;
|
||||
}
|
||||
|
||||
/* STEP */
|
||||
.step{
|
||||
display:flex;
|
||||
gap:20px;
|
||||
margin-bottom:28px;
|
||||
}
|
||||
|
||||
.step-number{
|
||||
min-width:52px;
|
||||
height:52px;
|
||||
background:#2563eb;
|
||||
color:#fff;
|
||||
border-radius:50%;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
font-weight:700;
|
||||
font-size:22px;
|
||||
}
|
||||
|
||||
.step-content h3{
|
||||
font-size:28px;
|
||||
font-weight:700;
|
||||
color:#0f172a;
|
||||
margin-bottom:6px;
|
||||
}
|
||||
|
||||
.step-content p{
|
||||
color:#475569;
|
||||
font-size:20px;
|
||||
line-height:1.7;
|
||||
}
|
||||
|
||||
/* CONTACT */
|
||||
.contact-box{
|
||||
margin-top:40px;
|
||||
background:#f8fbff;
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius:22px;
|
||||
padding:32px;
|
||||
}
|
||||
|
||||
.contact-header{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:18px;
|
||||
margin-bottom:18px;
|
||||
}
|
||||
|
||||
.contact-icon{
|
||||
width:70px;
|
||||
height:70px;
|
||||
background:#edf3ff;
|
||||
border-radius:50%;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
.contact-header h3{
|
||||
font-size:30px;
|
||||
font-weight:700;
|
||||
color:#2563eb;
|
||||
}
|
||||
|
||||
.contact-header p{
|
||||
font-size:18px;
|
||||
color:#475569;
|
||||
margin-top:4px;
|
||||
}
|
||||
|
||||
.contact-list{
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
gap:24px;
|
||||
align-items:center;
|
||||
margin-top:18px;
|
||||
padding-left:88px;
|
||||
}
|
||||
|
||||
.contact-item{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:12px;
|
||||
font-size:22px;
|
||||
font-weight:600;
|
||||
color:#0f172a;
|
||||
}
|
||||
|
||||
/* FOOTER */
|
||||
.footer{
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
margin-top:28px;
|
||||
color:#64748b;
|
||||
font-size:18px;
|
||||
padding:0 8px;
|
||||
}
|
||||
|
||||
/* MOBILE */
|
||||
@media(max-width:768px){
|
||||
|
||||
.main-wrapper{
|
||||
padding:20px 14px;
|
||||
}
|
||||
|
||||
.card-box{
|
||||
padding:28px 22px;
|
||||
border-radius:22px;
|
||||
}
|
||||
|
||||
.icon-wrapper{
|
||||
width:90px;
|
||||
height:90px;
|
||||
}
|
||||
|
||||
.title{
|
||||
font-size:36px;
|
||||
}
|
||||
|
||||
.subtitle{
|
||||
font-size:17px;
|
||||
line-height:1.7;
|
||||
}
|
||||
|
||||
.info-box{
|
||||
padding:18px;
|
||||
}
|
||||
|
||||
.info-box p{
|
||||
font-size:15px;
|
||||
}
|
||||
|
||||
.section-title h2{
|
||||
font-size:25px;
|
||||
}
|
||||
|
||||
.step{
|
||||
gap:14px;
|
||||
}
|
||||
|
||||
.step-number{
|
||||
min-width:42px;
|
||||
height:42px;
|
||||
font-size:18px;
|
||||
}
|
||||
|
||||
.step-content h3{
|
||||
font-size:21px;
|
||||
}
|
||||
|
||||
.step-content p{
|
||||
font-size:15px;
|
||||
}
|
||||
|
||||
.contact-box{
|
||||
padding:22px;
|
||||
}
|
||||
|
||||
.contact-header{
|
||||
align-items:flex-start;
|
||||
}
|
||||
|
||||
.contact-header h3{
|
||||
font-size:24px;
|
||||
}
|
||||
|
||||
.contact-header p{
|
||||
font-size:15px;
|
||||
}
|
||||
|
||||
.contact-list{
|
||||
padding-left:0;
|
||||
flex-direction:column;
|
||||
align-items:flex-start;
|
||||
gap:18px;
|
||||
}
|
||||
|
||||
.contact-item{
|
||||
font-size:16px;
|
||||
word-break:break-word;
|
||||
}
|
||||
|
||||
.footer{
|
||||
flex-direction:column;
|
||||
gap:10px;
|
||||
text-align:center;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="main-wrapper">
|
||||
|
||||
<div class="circle-top"></div>
|
||||
<div class="circle-bottom"></div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<!-- CARD -->
|
||||
<div class="card-box">
|
||||
|
||||
<!-- ICON -->
|
||||
<div class="icon-wrapper">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="55"
|
||||
height="55"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="#2563eb"
|
||||
stroke-width="2">
|
||||
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16 11V7a4 4 0 10-8 0v4m-2 0h12a2 2 0 012 2v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5a2 2 0 012-2z"/>
|
||||
|
||||
<circle cx="18.5" cy="18.5" r="3.5" stroke="#2563eb"/>
|
||||
<path d="M18.5 17v3M17 18.5h3" stroke="#2563eb"/>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- TITLE -->
|
||||
<h1 class="title">
|
||||
Lupa Password?
|
||||
</h1>
|
||||
|
||||
<p class="subtitle">
|
||||
Untuk keamanan akun, pengaturan ulang password hanya dapat dilakukan
|
||||
<br>
|
||||
<span>oleh Administrator.</span>
|
||||
</p>
|
||||
|
||||
<!-- INFO -->
|
||||
<div class="info-box">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="34"
|
||||
height="34"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="#2563eb"
|
||||
stroke-width="2">
|
||||
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<path d="M12 16v-4"/>
|
||||
<path d="M12 8h.01"/>
|
||||
|
||||
</svg>
|
||||
|
||||
<p>
|
||||
Silakan hubungi Administrator sistem untuk memperbarui password akun Anda.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SECTION TITLE -->
|
||||
<div class="section-title">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="40"
|
||||
height="40"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="#2563eb"
|
||||
stroke-width="2">
|
||||
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17 20h5V4H2v16h5"/>
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M9 20h6"/>
|
||||
<circle cx="12" cy="8" r="3"/>
|
||||
<path d="M7 16c1.333-2 3-3 5-3s3.667 1 5 3"/>
|
||||
|
||||
</svg>
|
||||
|
||||
<h2>Cara Memperbarui Password</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- STEP -->
|
||||
<div class="step">
|
||||
|
||||
<div class="step-number">1</div>
|
||||
|
||||
<div class="step-content">
|
||||
<h3>Hubungi Administrator</h3>
|
||||
<p>
|
||||
Sampaikan kepada Administrator bahwa Anda lupa password akun SENTARA.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
|
||||
<div class="step-number">2</div>
|
||||
|
||||
<div class="step-content">
|
||||
<h3>Verifikasi Identitas</h3>
|
||||
<p>
|
||||
Administrator akan memverifikasi identitas Anda sebagai pengguna sistem.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
|
||||
<div class="step-number">3</div>
|
||||
|
||||
<div class="step-content">
|
||||
<h3>Password Baru</h3>
|
||||
<p>
|
||||
Administrator akan membuat password baru dan memberikannya kepada Anda.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- CONTACT -->
|
||||
<div class="contact-box">
|
||||
|
||||
<div class="contact-header">
|
||||
|
||||
<div class="contact-icon">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="38"
|
||||
height="38"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="#2563eb"
|
||||
stroke-width="2">
|
||||
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M18 10c0 3.866-3.582 7-8 7a8.841 8.841 0 01-4-.917L2 17l1.083-3.25A6.963 6.963 0 012 10c0-3.866 3.582-7 8-7s8 3.134 8 7z"/>
|
||||
|
||||
<path d="M15 8h.01"/>
|
||||
<path d="M9 8h.01"/>
|
||||
<path d="M8 12c1 1 2 1.5 4 1.5s3-.5 4-1.5"/>
|
||||
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Kontak Administrator</h3>
|
||||
<p>
|
||||
Silakan hubungi administrator melalui kontak resmi berikut:
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="contact-list">
|
||||
|
||||
<!-- PHONE -->
|
||||
<div class="contact-item">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="26"
|
||||
height="26"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="#2563eb"
|
||||
stroke-width="2">
|
||||
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M3 5a2 2 0 012-2h2.28a2 2 0 011.94 1.515l.57 2.28a2 2 0 01-.45 1.91l-1.27 1.27a16 16 0 006.59 6.59l1.27-1.27a2 2 0 011.91-.45l2.28.57A2 2 0 0121 16.72V19a2 2 0 01-2 2h-1C9.163 21 3 14.837 3 7V5z"/>
|
||||
|
||||
</svg>
|
||||
|
||||
0881-0267-1527
|
||||
|
||||
</div>
|
||||
|
||||
<!-- EMAIL -->
|
||||
<div class="contact-item">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="26"
|
||||
height="26"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="#2563eb"
|
||||
stroke-width="2">
|
||||
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M4 4h16v16H4z"/>
|
||||
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M22 6l-10 7L2 6"/>
|
||||
|
||||
</svg>
|
||||
|
||||
e31231226@student.polije.ac.id
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<div class="footer">
|
||||
<div>© 2025 SENTARA. All rights reserved.</div>
|
||||
<div>Dinas Pariwisata Jember</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Session Status -->
|
||||
<x-auth-session-status class="mb-4" :status="session('status')" />
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('password.email') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Email Address -->
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<x-primary-button>
|
||||
{{ __('Email Password Reset Link') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-guest-layout>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
@extends('layouts.sentara')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="space-y-6">
|
||||
|
||||
{{-- ALERT SUCCESS --}}
|
||||
@if(session('success'))
|
||||
<div class="bg-green-50 border border-green-200 text-green-700 px-5 py-4 rounded-2xl">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ALERT ERROR --}}
|
||||
@if(session('error'))
|
||||
<div class="bg-red-50 border border-red-200 text-red-700 px-5 py-4 rounded-2xl">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
|
||||
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-slate-800">Kelola Pengguna</h1>
|
||||
<p class="text-slate-500 mt-1">Kelola akun pengguna sistem SENTARA.</p>
|
||||
</div>
|
||||
|
||||
<!-- BUTTON TAMBAH -->
|
||||
<button
|
||||
onclick="openTambahModal()"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-5 py-3 rounded-2xl text-sm font-semibold shadow transition">
|
||||
+ Tambah Pengguna
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- CARD -->
|
||||
<div class="bg-white rounded-3xl shadow-sm border border-slate-100 p-5">
|
||||
|
||||
<!-- TABLE -->
|
||||
<div class="overflow-x-auto mt-6">
|
||||
|
||||
<table class="w-full text-sm min-w-[900px]">
|
||||
|
||||
<thead>
|
||||
<tr class="text-slate-500 border-b">
|
||||
<th class="py-4 text-left">No</th>
|
||||
<th class="py-4 text-left">Nama</th>
|
||||
<th class="py-4 text-left">Email</th>
|
||||
<th class="py-4 text-left">Role</th>
|
||||
<th class="py-4 text-left">Status</th>
|
||||
<th class="py-4 text-left">Terakhir Aktif</th>
|
||||
<th class="py-4 text-center">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-slate-700">
|
||||
|
||||
@forelse ($users as $user)
|
||||
|
||||
<tr class="border-b hover:bg-slate-50 transition">
|
||||
|
||||
<td class="py-4">{{ $loop->iteration }}</td>
|
||||
|
||||
<td class="py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-xs font-bold text-slate-600">
|
||||
{{ strtoupper(substr($user->name, 0, 2)) }}
|
||||
</div>
|
||||
<span class="font-medium">{{ $user->name }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="py-4">{{ $user->email }}</td>
|
||||
|
||||
<td class="py-4">
|
||||
@if($user->role == 'admin')
|
||||
<span class="bg-purple-100 text-purple-700 px-3 py-1 rounded-full text-xs font-semibold">Admin</span>
|
||||
@else
|
||||
<span class="bg-blue-100 text-blue-700 px-3 py-1 rounded-full text-xs font-semibold">Staff</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="py-4">
|
||||
<span class="bg-green-100 text-green-700 px-3 py-1 rounded-full text-xs font-semibold">Aktif</span>
|
||||
</td>
|
||||
|
||||
<td class="py-4">{{ $user->updated_at->format('d M Y, H:i') }}</td>
|
||||
|
||||
<td class="py-4">
|
||||
<div class="flex justify-center gap-2">
|
||||
|
||||
<button
|
||||
onclick="openEditModal('{{ $user->id }}', '{{ addslashes($user->name) }}', '{{ $user->email }}', '{{ $user->role }}')"
|
||||
class="w-11 h-11 rounded-2xl border border-blue-200 text-blue-600 hover:bg-blue-50 flex items-center justify-center transition"
|
||||
title="Edit Pengguna">✏️</button>
|
||||
|
||||
<button
|
||||
onclick="openPasswordModal('{{ $user->id }}')"
|
||||
class="w-11 h-11 rounded-2xl border border-amber-200 text-amber-500 hover:bg-amber-50 flex items-center justify-center transition"
|
||||
title="Reset Password">🔒</button>
|
||||
|
||||
<button
|
||||
onclick="openDeleteModal('{{ $user->id }}', '{{ $user->role }}')"
|
||||
class="w-11 h-11 rounded-2xl border border-red-200 text-red-500 hover:bg-red-50 flex items-center justify-center transition"
|
||||
title="Hapus Pengguna">🗑️</button>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
@empty
|
||||
|
||||
<tr>
|
||||
<td colspan="7" class="py-10 text-center text-slate-400">
|
||||
Data pengguna belum tersedia.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@endforelse
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- PAGINATION -->
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mt-6">
|
||||
<p class="text-sm text-slate-500">
|
||||
Menampilkan {{ $users->firstItem() ?? 0 }} - {{ $users->lastItem() ?? 0 }}
|
||||
dari {{ $users->total() }} pengguna
|
||||
</p>
|
||||
{{ $users->links() }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================= MODAL TAMBAH PENGGUNA ================= -->
|
||||
<div id="tambahModal"
|
||||
class="hidden fixed inset-0 bg-black/40 z-50 flex items-center justify-center px-4">
|
||||
|
||||
<div class="bg-white rounded-3xl p-6 shadow-2xl w-full" style="max-width: 480px;">
|
||||
|
||||
<div class="flex items-start justify-between mb-5">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-slate-800">Tambah Pengguna</h2>
|
||||
<p class="text-slate-500 text-sm mt-1">Buat akun pengguna baru untuk sistem SENTARA.</p>
|
||||
</div>
|
||||
<button onclick="closeTambahModal()"
|
||||
class="text-slate-400 hover:text-slate-700 text-2xl leading-none ml-4 flex-shrink-0">×</button>
|
||||
</div>
|
||||
|
||||
{{-- SESUDAH --}}
|
||||
<form method="POST" action="/kelola-pengguna" id="tambahForm">
|
||||
|
||||
@csrf
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Nama Pengguna</label>
|
||||
<input type="text" name="name" placeholder="Masukkan nama lengkap"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Email</label>
|
||||
<input type="email" name="email" placeholder="contoh@email.com"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Role Pengguna</label>
|
||||
<select name="role"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none">
|
||||
<option value="staff">Staff</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Password</label>
|
||||
<input type="password" name="password" placeholder="Minimal 8 karakter"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Konfirmasi Password</label>
|
||||
<input type="password" name="password_confirmation" placeholder="Ulangi password"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" required>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button type="button" onclick="closeTambahModal()"
|
||||
class="flex-1 py-3 rounded-2xl border border-slate-200 text-slate-600 text-sm font-medium hover:bg-slate-100 transition">
|
||||
Batal
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="flex-1 py-3 rounded-2xl bg-blue-600 hover:bg-blue-700 text-white text-sm font-semibold transition">
|
||||
Tambah
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================= MODAL EDIT ================= -->
|
||||
<div id="editModal"
|
||||
class="hidden fixed inset-0 bg-black/40 z-50 flex items-center justify-center px-4">
|
||||
|
||||
<div class="bg-white rounded-3xl p-6 shadow-2xl w-full" style="max-width: 480px;">
|
||||
|
||||
<div class="flex items-start justify-between mb-5">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-slate-800">Edit Pengguna</h2>
|
||||
<p class="text-slate-500 text-sm mt-1">Perbarui informasi akun pengguna SENTARA.</p>
|
||||
</div>
|
||||
<button onclick="closeEditModal()"
|
||||
class="text-slate-400 hover:text-slate-700 text-2xl leading-none ml-4 flex-shrink-0">×</button>
|
||||
</div>
|
||||
|
||||
<form method="POST" id="editForm">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Nama Pengguna</label>
|
||||
<input type="text" name="name" id="editName"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none">
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Email</label>
|
||||
<input type="email" name="email" id="editEmail"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none">
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Role Pengguna</label>
|
||||
<select name="role" id="editRole"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none">
|
||||
<option value="admin">Admin</option>
|
||||
<option value="staff">Staff</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button type="button" onclick="closeEditModal()"
|
||||
class="flex-1 py-3 rounded-2xl border border-slate-200 text-slate-600 text-sm font-medium hover:bg-slate-100 transition">
|
||||
Batal
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="flex-1 py-3 rounded-2xl bg-blue-600 hover:bg-blue-700 text-white text-sm font-semibold transition">
|
||||
Simpan
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================= MODAL RESET PASSWORD ================= -->
|
||||
<div id="passwordModal"
|
||||
class="hidden fixed inset-0 bg-black/40 z-50 flex items-center justify-center px-4">
|
||||
|
||||
<div class="bg-white rounded-3xl p-6 shadow-2xl w-full" style="max-width: 480px;">
|
||||
|
||||
<div class="flex items-start justify-between mb-5">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-slate-800">Reset Password</h2>
|
||||
<p class="text-slate-500 text-sm mt-1">Buat password baru pengguna.</p>
|
||||
</div>
|
||||
<button onclick="closePasswordModal()"
|
||||
class="text-slate-400 hover:text-slate-700 text-2xl leading-none ml-4 flex-shrink-0">×</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-5 bg-amber-50 border border-amber-200 rounded-2xl p-4">
|
||||
<p class="text-sm text-amber-700 leading-relaxed">
|
||||
Password minimal 8 karakter dan harus kombinasi huruf besar, huruf kecil, dan angka.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form method="POST" id="passwordForm">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Password Baru</label>
|
||||
<input type="password" name="password"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-amber-400 focus:outline-none">
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<label class="block text-sm font-semibold text-slate-700 mb-2">Konfirmasi Password</label>
|
||||
<input type="password" name="password_confirmation"
|
||||
class="w-full rounded-2xl border border-slate-200 px-4 py-3 text-sm focus:ring-2 focus:ring-amber-400 focus:outline-none">
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button type="button" onclick="closePasswordModal()"
|
||||
class="flex-1 py-3 rounded-2xl border border-slate-200 text-slate-600 text-sm font-medium hover:bg-slate-100 transition">
|
||||
Batal
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="flex-1 py-3 rounded-2xl bg-amber-500 hover:bg-amber-600 text-white text-sm font-semibold transition">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================= MODAL DELETE ================= -->
|
||||
<div id="deleteModal"
|
||||
class="hidden fixed inset-0 bg-black/40 z-50 flex items-center justify-center px-4">
|
||||
|
||||
<div class="bg-white rounded-3xl p-6 shadow-2xl w-full text-center" style="max-width: 400px;">
|
||||
|
||||
<div class="w-16 h-16 mx-auto rounded-full bg-red-100 flex items-center justify-center text-3xl mb-4">🗑️</div>
|
||||
<h2 class="text-2xl font-bold text-slate-800">Hapus Pengguna?</h2>
|
||||
<p class="text-slate-500 text-sm mt-2 leading-relaxed">
|
||||
Data pengguna akan dihapus permanen dan tidak dapat dikembalikan.
|
||||
</p>
|
||||
|
||||
<form method="POST" id="deleteForm" class="mt-6">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<div class="flex gap-3">
|
||||
<button type="button" onclick="closeDeleteModal()"
|
||||
class="flex-1 py-3 rounded-2xl border border-slate-200 text-slate-600 text-sm font-medium hover:bg-slate-100 transition">
|
||||
Batal
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="flex-1 py-3 rounded-2xl bg-red-500 hover:bg-red-600 text-white text-sm font-semibold transition">
|
||||
Hapus
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================= MODAL ADMIN TIDAK BISA DIHAPUS ================= -->
|
||||
<div id="adminAlertModal"
|
||||
class="hidden fixed inset-0 bg-black/40 z-50 flex items-center justify-center px-4">
|
||||
|
||||
<div class="bg-white rounded-3xl p-6 shadow-2xl w-full text-center" style="max-width: 400px;">
|
||||
|
||||
<div class="w-16 h-16 mx-auto rounded-full bg-amber-100 flex items-center justify-center text-3xl mb-4">⚠️</div>
|
||||
<h2 class="text-2xl font-bold text-slate-800">Akses Ditolak</h2>
|
||||
<p class="text-slate-500 text-sm mt-2 leading-relaxed">
|
||||
Akun administrator tidak dapat dihapus demi menjaga keamanan sistem.
|
||||
</p>
|
||||
|
||||
<button onclick="closeAdminAlertModal()"
|
||||
class="w-full mt-6 py-3 rounded-2xl bg-blue-600 hover:bg-blue-700 text-white text-sm font-semibold transition">
|
||||
Mengerti
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ================= SCRIPT ================= -->
|
||||
<script>
|
||||
|
||||
/* ---- TAMBAH ---- */
|
||||
function openTambahModal() {
|
||||
document.getElementById('tambahModal').classList.remove('hidden');
|
||||
document.getElementById('tambahForm').reset();
|
||||
}
|
||||
function closeTambahModal() {
|
||||
document.getElementById('tambahModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
/* ---- EDIT ---- */
|
||||
function openEditModal(id, name, email, role) {
|
||||
document.getElementById('editModal').classList.remove('hidden');
|
||||
document.getElementById('editName').value = name;
|
||||
document.getElementById('editEmail').value = email;
|
||||
document.getElementById('editRole').value = role;
|
||||
document.getElementById('editForm').action = '/kelola-pengguna/' + id;
|
||||
}
|
||||
function closeEditModal() {
|
||||
document.getElementById('editModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
/* ---- RESET PASSWORD ---- */
|
||||
function openPasswordModal(id) {
|
||||
document.getElementById('passwordModal').classList.remove('hidden');
|
||||
document.getElementById('passwordForm').action =
|
||||
'/kelola-pengguna/' + id + '/reset-password';
|
||||
}
|
||||
function closePasswordModal() {
|
||||
document.getElementById('passwordModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
/* ---- DELETE ---- */
|
||||
function openDeleteModal(id, role) {
|
||||
if (role === 'admin') {
|
||||
document.getElementById('adminAlertModal').classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
document.getElementById('deleteModal').classList.remove('hidden');
|
||||
document.getElementById('deleteForm').action = '/kelola-pengguna/' + id;
|
||||
}
|
||||
function closeDeleteModal() {
|
||||
document.getElementById('deleteModal').classList.add('hidden');
|
||||
}
|
||||
function closeAdminAlertModal() {
|
||||
document.getElementById('adminAlertModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
|
|
@ -86,11 +86,27 @@ class="block hover:text-gray-300">
|
|||
</header>
|
||||
@endisset
|
||||
|
||||
|
||||
<!-- Page Content -->
|
||||
<main class="p-6">
|
||||
@yield('content')
|
||||
</main>
|
||||
<main class="p-6">
|
||||
|
||||
{{-- ALERT SUCCESS --}}
|
||||
@if(session('success'))
|
||||
<div class="mb-4 bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-2xl">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ALERT ERROR --}}
|
||||
@if(session('error'))
|
||||
<div class="mb-4 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-2xl">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@yield('content')
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@
|
|||
|
||||
@vite(['resources/css/app.css','resources/js/app.js'])
|
||||
|
||||
<!-- FEATHER ICON -->
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-100">
|
||||
<body class="bg-gray-100 overflow-x-hidden">
|
||||
|
||||
<div class="min-h-screen">
|
||||
<div class="min-h-screen flex">
|
||||
|
||||
<!-- SIDEBAR -->
|
||||
<aside id="sidebar"
|
||||
|
|
@ -25,7 +27,8 @@ class="fixed top-0 left-0 h-full w-64
|
|||
<!-- LOGO -->
|
||||
<div class="flex justify-center mt-6 mb-8">
|
||||
<img src="{{ asset('images/tulisan-sentara.png') }}"
|
||||
class="w-44">
|
||||
class="w-44"
|
||||
alt="Logo SENTARA">
|
||||
</div>
|
||||
|
||||
<!-- MENU -->
|
||||
|
|
@ -39,7 +42,9 @@ class="flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-blue-800 transition
|
|||
<i data-feather="grid" class="w-5 h-5"></i>
|
||||
</div>
|
||||
|
||||
<span class="text-[15px]">Dashboard Sentimen</span>
|
||||
<span class="text-[15px] leading-5">
|
||||
Dashboard Sentimen
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- DATA ULASAN -->
|
||||
|
|
@ -50,7 +55,9 @@ class="flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-blue-800 transition
|
|||
<i data-feather="file-text" class="w-5 h-5"></i>
|
||||
</div>
|
||||
|
||||
<span class="text-[15px]">Data Ulasan</span>
|
||||
<span class="text-[15px] leading-5">
|
||||
Data Ulasan
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- RIWAYAT -->
|
||||
|
|
@ -61,54 +68,103 @@ class="flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-blue-800 transition
|
|||
<i data-feather="clock" class="w-5 h-5"></i>
|
||||
</div>
|
||||
|
||||
<span class="text-[15px]">Riwayat Analisis</span>
|
||||
<span class="text-[15px] leading-5">
|
||||
Riwayat Analisis
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- KHUSUS ADMIN -->
|
||||
@if(auth()->user()->role == 'admin')
|
||||
|
||||
<a href="{{ route('kelola-pengguna.index') }}"
|
||||
class="flex items-center gap-4 px-4 py-3 rounded-xl hover:bg-blue-800 transition">
|
||||
|
||||
<div class="w-10 h-10 flex items-center justify-center bg-blue-800 rounded-lg">
|
||||
<i data-feather="users" class="w-5 h-5"></i>
|
||||
</div>
|
||||
|
||||
<span class="text-[15px] leading-5">
|
||||
Kelola Pengguna
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@endif
|
||||
|
||||
</nav>
|
||||
|
||||
<!-- USER SECTION -->
|
||||
<!-- USER -->
|
||||
<div class="px-6 pb-6">
|
||||
|
||||
<div class="relative">
|
||||
|
||||
<!-- USER BUTTON -->
|
||||
<button onclick="toggleUserMenu()"
|
||||
class="w-full flex items-center gap-3 bg-blue-800 hover:bg-blue-900 px-4 py-3 rounded-xl transition">
|
||||
class="w-full flex items-center gap-3
|
||||
bg-blue-800 hover:bg-blue-900
|
||||
px-4 py-3 rounded-2xl transition">
|
||||
|
||||
<!-- ICON -->
|
||||
<div class="w-11 h-11 rounded-full bg-blue-700
|
||||
flex items-center justify-center">
|
||||
|
||||
<i data-feather="user"
|
||||
class="w-5 h-5"></i>
|
||||
|
||||
<div class="w-10 h-10 flex items-center justify-center bg-blue-700 rounded-full">
|
||||
<i data-feather="user" class="w-5 h-5"></i>
|
||||
</div>
|
||||
|
||||
<div class="text-left">
|
||||
<p class="text-sm font-semibold">
|
||||
<!-- TEXT -->
|
||||
<div class="text-left flex-1">
|
||||
|
||||
<p class="text-sm font-semibold capitalize">
|
||||
{{ auth()->user()->name }}
|
||||
</p>
|
||||
<p class="text-xs text-blue-200">Staff</p>
|
||||
|
||||
<p class="text-xs text-blue-200 capitalize">
|
||||
{{ auth()->user()->role }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ARROW -->
|
||||
<i data-feather="chevron-up"
|
||||
class="w-4 h-4 text-blue-200"></i>
|
||||
|
||||
</button>
|
||||
|
||||
<!-- DROPDOWN -->
|
||||
<div id="userMenu"
|
||||
class="hidden absolute bottom-16 left-0 w-full
|
||||
bg-white text-gray-700 rounded-xl shadow-lg overflow-hidden">
|
||||
bg-white text-gray-700 rounded-2xl shadow-2xl overflow-hidden">
|
||||
|
||||
<!-- PROFILE -->
|
||||
<a href="{{ route('profile') }}"
|
||||
class="flex items-center gap-3 px-4 py-3 text-sm hover:bg-gray-100">
|
||||
<i data-feather="user" class="w-4 h-4"></i>
|
||||
class="flex items-center gap-3 px-4 py-4 text-sm hover:bg-gray-100 transition">
|
||||
|
||||
<i data-feather="user"
|
||||
class="w-4 h-4"></i>
|
||||
|
||||
Profile
|
||||
|
||||
</a>
|
||||
|
||||
<!-- LOGOUT -->
|
||||
<form id="logoutForm" method="POST" action="{{ route('logout') }}">
|
||||
@csrf
|
||||
<button type="button"
|
||||
onclick="confirmLogout()"
|
||||
class="w-full flex items-center gap-3 px-4 py-3 text-sm hover:bg-gray-100">
|
||||
<i data-feather="log-out" class="w-4 h-4"></i>
|
||||
Logout
|
||||
</button>
|
||||
</form>
|
||||
<form id="logoutForm"
|
||||
method="POST"
|
||||
action="{{ route('logout') }}">
|
||||
|
||||
@csrf
|
||||
|
||||
<button type="submit"
|
||||
class="w-full flex items-center gap-3 px-4 py-4 text-sm hover:bg-gray-100 transition text-left">
|
||||
|
||||
<i data-feather="log-out"
|
||||
class="w-4 h-4"></i>
|
||||
|
||||
Logout
|
||||
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -119,11 +175,14 @@ class="w-full flex items-center gap-3 px-4 py-3 text-sm hover:bg-gray-100">
|
|||
</aside>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="flex-1 p-4 md:p-6 md:ml-64 ml-0">
|
||||
<div class="flex-1 p-4 md:p-6 md:ml-64">
|
||||
|
||||
<!-- MOBILE BUTTON -->
|
||||
<button onclick="toggleSidebar()"
|
||||
class="md:hidden mb-4 bg-blue-600 text-white px-4 py-2 rounded-lg shadow">
|
||||
|
||||
☰
|
||||
|
||||
</button>
|
||||
|
||||
@yield('content')
|
||||
|
|
@ -134,28 +193,44 @@ class="md:hidden mb-4 bg-blue-600 text-white px-4 py-2 rounded-lg shadow">
|
|||
|
||||
<!-- MODAL LOGOUT -->
|
||||
<div id="logoutModal"
|
||||
class="hidden fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50">
|
||||
class="hidden fixed inset-0 bg-black/40 flex items-center justify-center z-50 px-4">
|
||||
|
||||
<div class="bg-white rounded-xl p-6 w-80 text-center shadow-lg">
|
||||
<div class="bg-white rounded-2xl p-6 w-96 text-center shadow-2xl">
|
||||
|
||||
<h3 class="text-lg font-semibold mb-2">
|
||||
<!-- ICON -->
|
||||
<div class="w-16 h-16 rounded-full
|
||||
flex items-center justify-center mx-auto mb-5">
|
||||
|
||||
<i data-feather="log-out"
|
||||
class="w-7 h-7 text-red-500"></i>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- TITLE -->
|
||||
<h3 class="text-xl font-bold text-gray-800 mb-2">
|
||||
Konfirmasi Logout
|
||||
</h3>
|
||||
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
Apakah Anda ingin keluar?
|
||||
<!-- TEXT -->
|
||||
<p class="text-sm text-gray-500 mb-6">
|
||||
Apakah Anda ingin keluar dari sistem?
|
||||
</p>
|
||||
|
||||
<!-- BUTTON -->
|
||||
<div class="flex justify-center gap-3">
|
||||
|
||||
<button onclick="closeModal()"
|
||||
class="px-4 py-2 bg-gray-200 rounded-lg">
|
||||
class="px-5 py-2 rounded-xl bg-gray-200 hover:bg-gray-300 transition">
|
||||
|
||||
Tidak
|
||||
|
||||
</button>
|
||||
|
||||
<button onclick="submitLogout()"
|
||||
class="px-4 py-2 bg-red-500 text-white rounded-lg">
|
||||
class="px-5 py-2 rounded-xl bg-red-500 hover:bg-red-600 text-white transition">
|
||||
|
||||
Ya
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
|
@ -166,28 +241,48 @@ class="px-4 py-2 bg-red-500 text-white rounded-lg">
|
|||
|
||||
<!-- SCRIPT -->
|
||||
<script>
|
||||
|
||||
function toggleSidebar() {
|
||||
document.getElementById('sidebar').classList.toggle('-translate-x-full');
|
||||
document.getElementById('sidebar')
|
||||
.classList.toggle('-translate-x-full');
|
||||
}
|
||||
|
||||
function toggleUserMenu() {
|
||||
document.getElementById('userMenu').classList.toggle('hidden');
|
||||
document.getElementById('userMenu')
|
||||
.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function confirmLogout(){
|
||||
document.getElementById('logoutModal').classList.remove('hidden');
|
||||
function confirmLogout() {
|
||||
document.getElementById('logoutModal')
|
||||
.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function closeModal(){
|
||||
document.getElementById('logoutModal').classList.add('hidden');
|
||||
function closeModal() {
|
||||
document.getElementById('logoutModal')
|
||||
.classList.add('hidden');
|
||||
}
|
||||
|
||||
function submitLogout(){
|
||||
function submitLogout() {
|
||||
document.getElementById('logoutForm').submit();
|
||||
}
|
||||
|
||||
/* CLOSE DROPDOWN KETIKA KLIK LUAR */
|
||||
window.addEventListener('click', function(e){
|
||||
|
||||
const button = e.target.closest('button');
|
||||
const menu = document.getElementById('userMenu');
|
||||
|
||||
if(!e.target.closest('#userMenu') &&
|
||||
!e.target.closest('[onclick="toggleUserMenu()"]')) {
|
||||
|
||||
menu.classList.add('hidden');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
feather.replace();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -6,14 +6,20 @@
|
|||
|
||||
<!-- HEADER -->
|
||||
<div class="flex items-center gap-4 mb-6">
|
||||
|
||||
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-gray-800">Profile Saya</h1>
|
||||
<h1 class="text-3xl font-bold text-gray-800">
|
||||
Profile Saya
|
||||
</h1>
|
||||
|
||||
<p class="text-gray-500 text-sm">
|
||||
Informasi akun pengguna <span class="text-blue-600 font-medium">SENTARA</span>
|
||||
Informasi akun pengguna
|
||||
<span class="text-blue-600 font-medium">
|
||||
SENTARA
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- PROFILE CARD -->
|
||||
|
|
@ -21,30 +27,53 @@
|
|||
|
||||
<div class="absolute right-0 bottom-0 w-64 h-64 bg-blue-100 opacity-30 rounded-full"></div>
|
||||
|
||||
<!-- FOTO -->
|
||||
<div class="w-24 h-24 rounded-full bg-gradient-to-r from-blue-500 to-blue-700
|
||||
flex items-center justify-center text-white text-3xl font-bold shadow-md">
|
||||
|
||||
{{ strtoupper(substr(Auth::user()->name, 0, 1)) }}
|
||||
|
||||
</div>
|
||||
|
||||
<!-- INFO -->
|
||||
<div>
|
||||
|
||||
<!-- NAMA -->
|
||||
<h2 class="text-2xl font-semibold text-gray-800">
|
||||
{{ Auth::user()->name }}
|
||||
</h2>
|
||||
|
||||
<p class="text-gray-500 mt-1">
|
||||
Staff - Dinas Pariwisata Jember
|
||||
<!-- ROLE -->
|
||||
<p class="text-gray-500 mt-1 capitalize">
|
||||
{{ Auth::user()->role }} - Dinas Pariwisata Jember
|
||||
</p>
|
||||
|
||||
<span class="inline-block mt-3 text-xs bg-blue-100 text-blue-600 px-3 py-1 rounded-full font-medium">
|
||||
STAFF
|
||||
<!-- BADGE ROLE -->
|
||||
<span class="
|
||||
inline-block mt-3 text-xs px-3 py-1 rounded-full font-medium uppercase
|
||||
|
||||
@if(Auth::user()->role == 'admin')
|
||||
bg-purple-100 text-purple-700
|
||||
@else
|
||||
bg-blue-100 text-blue-600
|
||||
@endif
|
||||
">
|
||||
|
||||
{{ Auth::user()->role }}
|
||||
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- INFORMASI AKUN -->
|
||||
<div class="mb-4 flex items-center gap-2 text-blue-600 font-semibold">
|
||||
<span class="text-xl">📋</span> Informasi Akun
|
||||
|
||||
<span class="text-xl">📋</span>
|
||||
|
||||
Informasi Akun
|
||||
|
||||
</div>
|
||||
|
||||
<!-- GRID -->
|
||||
|
|
@ -52,48 +81,101 @@
|
|||
|
||||
<!-- NAMA -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 text-center hover:shadow-md transition">
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-blue-100 rounded-full flex items-center justify-center text-blue-600">
|
||||
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-blue-100 rounded-full
|
||||
flex items-center justify-center text-blue-600">
|
||||
|
||||
👤
|
||||
|
||||
</div>
|
||||
<p class="text-gray-400 text-sm">Nama Lengkap</p>
|
||||
|
||||
<p class="text-gray-400 text-sm">
|
||||
Nama Lengkap
|
||||
</p>
|
||||
|
||||
<p class="font-semibold text-gray-800 mt-1">
|
||||
{{ Auth::user()->name }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- EMAIL -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 text-center hover:shadow-md transition">
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-blue-100 rounded-full flex items-center justify-center text-blue-600">
|
||||
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-blue-100 rounded-full
|
||||
flex items-center justify-center text-blue-600">
|
||||
|
||||
✉️
|
||||
|
||||
</div>
|
||||
<p class="text-gray-400 text-sm">Email</p>
|
||||
|
||||
<p class="text-gray-400 text-sm">
|
||||
Email
|
||||
</p>
|
||||
|
||||
<p class="font-semibold text-gray-800 mt-1">
|
||||
{{ Auth::user()->email }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ROLE (FIX ICON) -->
|
||||
<!-- ROLE -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 text-center hover:shadow-md transition">
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-blue-100 rounded-full flex items-center justify-center text-blue-600">
|
||||
<!-- ICON GROUP -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M17 20h5v-1a4 4 0 00-3-3.87M9 20H4v-1a4 4 0 013-3.87m10-2.13a4 4 0 10-8 0m8 0a4 4 0 01-8 0"/>
|
||||
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-blue-100 rounded-full
|
||||
flex items-center justify-center text-blue-600">
|
||||
|
||||
<!-- ICON -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-5 h-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor">
|
||||
|
||||
<path stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
|
||||
d="M17 20h5v-1a4 4 0 00-3-3.87
|
||||
M9 20H4v-1a4 4 0 013-3.87
|
||||
m10-2.13a4 4 0 10-8 0
|
||||
m8 0a4 4 0 01-8 0"/>
|
||||
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
<p class="text-gray-400 text-sm">Role</p>
|
||||
<p class="font-semibold text-gray-800 mt-1">Staff</p>
|
||||
|
||||
<p class="text-gray-400 text-sm">
|
||||
Role
|
||||
</p>
|
||||
|
||||
<p class="font-semibold text-gray-800 mt-1 capitalize">
|
||||
{{ Auth::user()->role }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- STATUS -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 text-center hover:shadow-md transition">
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-green-100 rounded-full flex items-center justify-center text-green-600">
|
||||
|
||||
<div class="w-12 h-12 mx-auto mb-3 bg-green-100 rounded-full
|
||||
flex items-center justify-center text-green-600">
|
||||
|
||||
✔
|
||||
|
||||
</div>
|
||||
<p class="text-gray-400 text-sm">Status Akun</p>
|
||||
<span class="inline-block mt-1 text-sm bg-green-100 text-green-600 px-3 py-1 rounded-full">
|
||||
|
||||
<p class="text-gray-400 text-sm">
|
||||
Status Akun
|
||||
</p>
|
||||
|
||||
<span class="inline-block mt-1 text-sm bg-green-100
|
||||
text-green-600 px-3 py-1 rounded-full">
|
||||
|
||||
Aktif
|
||||
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -102,22 +184,37 @@
|
|||
<div class="bg-white rounded-xl shadow-sm p-6 flex items-center justify-between">
|
||||
|
||||
<div>
|
||||
|
||||
<div class="flex items-center gap-2 text-blue-600 font-semibold mb-2">
|
||||
<span class="text-xl">ℹ</span> Informasi Sistem
|
||||
|
||||
<span class="text-xl">ℹ</span>
|
||||
|
||||
Informasi Sistem
|
||||
|
||||
</div>
|
||||
|
||||
<p class="text-gray-500 text-sm max-w-xl">
|
||||
|
||||
Akun ini digunakan untuk mengakses sistem SENTARA
|
||||
(Sistem Analisis Sentimen Ulasan Dinas Pariwisata Jember).
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<div class="flex justify-between text-sm text-gray-400 mt-6">
|
||||
<span>© 2025 SENTARA. All rights reserved.</span>
|
||||
<span>Dinas Pariwisata Jember</span>
|
||||
|
||||
<span>
|
||||
© 2025 SENTARA. All rights reserved.
|
||||
</span>
|
||||
|
||||
<span>
|
||||
Dinas Pariwisata Jember
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
115
routes/web.php
115
routes/web.php
|
|
@ -6,6 +6,8 @@
|
|||
use App\Http\Controllers\UlasanController;
|
||||
use App\Http\Controllers\AnalisisController;
|
||||
use App\Http\Controllers\RekomendasiController;
|
||||
use App\Http\Controllers\UserController;
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
@ -13,7 +15,6 @@
|
|||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// hanya SATU route '/'
|
||||
Route::get('/', function () {
|
||||
return redirect('/login');
|
||||
});
|
||||
|
|
@ -26,48 +27,114 @@
|
|||
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
|
||||
// ✅ DASHBOARD
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DASHBOARD
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Route::get('/dashboard', [DashboardController::class, 'index'])
|
||||
->name('dashboard');
|
||||
|
||||
// ✅ PROFILE (ini yang kamu tanya)
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| PROFILE
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Route::get('/profile', function () {
|
||||
return view('profile.index');
|
||||
})->name('profile');
|
||||
|
||||
// kalau mau aktifkan update:
|
||||
// Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||
// Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| KELOLA PENGGUNA
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Route::get('/kelola-pengguna',
|
||||
[UserController::class, 'index']
|
||||
)->name('kelola-pengguna.index');
|
||||
|
||||
// ✅ TAMBAHAN BARU — route untuk simpan pengguna baru
|
||||
Route::post('/kelola-pengguna',
|
||||
[UserController::class, 'store']
|
||||
)->name('kelola-pengguna.store');
|
||||
|
||||
Route::get('/kelola-pengguna/{id}/edit',
|
||||
[UserController::class, 'edit']
|
||||
)->name('kelola-pengguna.edit');
|
||||
|
||||
Route::put('/kelola-pengguna/{id}',
|
||||
[UserController::class, 'update']
|
||||
)->name('kelola-pengguna.update');
|
||||
|
||||
Route::get('/kelola-pengguna/{id}/reset-password',
|
||||
[UserController::class, 'resetPassword']
|
||||
)->name('kelola-pengguna.reset-password');
|
||||
|
||||
Route::put('/kelola-pengguna/{id}/reset-password',
|
||||
[UserController::class, 'updatePassword']
|
||||
)->name('kelola-pengguna.update-password');
|
||||
|
||||
Route::delete('/kelola-pengguna/{id}',
|
||||
[UserController::class, 'destroy']
|
||||
)->name('kelola-pengguna.destroy');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DATA ULASAN
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// ✅ DATA ULASAN
|
||||
Route::get('/ulasan', [UlasanController::class, 'index'])
|
||||
->name('ulasan.index');
|
||||
|
||||
Route::get('/riwayat', [UlasanController::class, 'riwayat'])
|
||||
->name('riwayat.index');
|
||||
|
||||
Route::post('/riwayat/import', [UlasanController::class, 'importRiwayat'])
|
||||
->name('riwayat.import');
|
||||
Route::post('/riwayat/import',
|
||||
[UlasanController::class, 'importRiwayat']
|
||||
)->name('riwayat.import');
|
||||
|
||||
Route::post('/ulasan/ambil', [UlasanController::class, 'ambilData'])
|
||||
->name('ulasan.ambil');
|
||||
Route::post('/ulasan/ambil',
|
||||
[UlasanController::class, 'ambilData']
|
||||
)->name('ulasan.ambil');
|
||||
|
||||
Route::delete('/ulasan/periode/kosongkan', [UlasanController::class, 'kosongkanPeriode'])
|
||||
->name('ulasan.kosongkan-periode');
|
||||
Route::delete('/ulasan/periode/kosongkan',
|
||||
[UlasanController::class, 'kosongkanPeriode']
|
||||
)->name('ulasan.kosongkan-periode');
|
||||
|
||||
// ✅ PROSES ANALISIS
|
||||
Route::post('/proses-analisis', [UlasanController::class, 'analisisData'])
|
||||
->name('proses.analisis');
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| PROSES ANALISIS
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// ✅ HASIL ANALISIS
|
||||
Route::get('/analisis', [AnalisisController::class, 'index'])
|
||||
->name('analisis.index');
|
||||
Route::post('/proses-analisis',
|
||||
[UlasanController::class, 'analisisData']
|
||||
)->name('proses.analisis');
|
||||
|
||||
// ✅ REKOMENDASI
|
||||
Route::get('/rekomendasi', function() {
|
||||
return redirect('/dashboard?tab=rekomendasi');
|
||||
})->name('rekomendasi.index');
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HASIL ANALISIS
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Route::get('/analisis',
|
||||
[AnalisisController::class, 'index']
|
||||
)->name('analisis.index');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| REKOMENDASI
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Route::get('/rekomendasi', function () {
|
||||
return redirect('/dashboard?tab=rekomendasi');
|
||||
})->name('rekomendasi.index');
|
||||
|
||||
});
|
||||
|
||||
require __DIR__.'/auth.php';
|
||||
require __DIR__.'/auth.php';
|
||||
|
|
@ -65,7 +65,8 @@ def read_laravel_env():
|
|||
|
||||
|
||||
def env_value(env, key, default=""):
|
||||
value = os.getenv(key, env.get(key, default))
|
||||
# .env file dibaca DULUAN, baru fallback ke os.getenv, lalu default
|
||||
value = env.get(key) or os.getenv(key) or default
|
||||
if value in {None, "", "null", "None"}:
|
||||
return default
|
||||
return value
|
||||
|
|
@ -734,13 +735,12 @@ def main():
|
|||
scraper = scraper_config()
|
||||
destinations = selected_destinations(args.wisata)
|
||||
conn = pymysql.connect(
|
||||
host=config["host"],
|
||||
port=config["port"],
|
||||
user=config["user"],
|
||||
password=config["password"],
|
||||
database=config["database"],
|
||||
charset="utf8mb4",
|
||||
)
|
||||
host='localhost',
|
||||
port=3306,
|
||||
user='root',
|
||||
password='', # isi password kalau ada
|
||||
database='sistem_analisis',
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
|
|
@ -767,4 +767,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
Loading…
Reference in New Issue