diff --git a/app/Http/Controllers/Admin/Setting/AccountController.php b/app/Http/Controllers/Admin/Setting/AccountController.php
new file mode 100644
index 0000000..2e98eeb
--- /dev/null
+++ b/app/Http/Controllers/Admin/Setting/AccountController.php
@@ -0,0 +1,78 @@
+ 'Profil',
+ 'profile' => User::with(['attachment', 'biography', 'role'])->findOrFail(Auth::id()),
+ ]);
+ }
+
+ public function updateProfile(User $user, UserRequest $request): RedirectResponse
+ {
+ $validatedData = $request->validated();
+
+ DB::transaction(function () use ($validatedData, $user) {
+ $user->update($validatedData);
+
+ $biographyData = collect($validatedData)
+ ->except([
+ 'email',
+ 'username',
+ 'avatar',
+ ])
+ ->toArray();
+ $user->biography()->update($biographyData);
+ if (isset($validatedData['avatar'])) {
+ $this->uploadAttachment($validatedData['avatar'], 'users', User::class, $user->id);
+ }
+ });
+
+ notify()->success('Data berhasil diubah', 'Berhasil');
+
+ return back();
+ }
+
+ public function updatePassword(User $user, PasswordRequest $request): RedirectResponse
+ {
+ $validatedData = $request->validated();
+ if (! Hash::check($validatedData['current_password'], $user->password)) {
+ notify()->error('Kata sandi yang Anda masukkan salah', 'Gagal');
+
+ return back();
+ } elseif ($validatedData['new_password'] == $validatedData['repeat_new_password']) {
+ Auth::logoutOtherDevices($validatedData['current_password']);
+ $user->update([
+ 'password' => Hash::make($validatedData['new_password']),
+ ]);
+
+ Auth::logout();
+
+ request()->session()->invalidate();
+
+ request()->session()->regenerateToken();
+ notify()->success('Kata sandi Anda telah berhasil diperbarui. Silakan masuk kembali untuk melanjutkan', 'Berhasil');
+
+ return redirect()->route('login');
+ }
+
+ notify()->error('Kata sandi baru yang Anda masukkan tidak sesuai dengan konfirmasi', 'Gagal');
+ }
+}
diff --git a/app/Http/Controllers/Admin/Setting/ApplicationController.php b/app/Http/Controllers/Admin/Setting/ApplicationController.php
index 5c719e4..70bc4b2 100644
--- a/app/Http/Controllers/Admin/Setting/ApplicationController.php
+++ b/app/Http/Controllers/Admin/Setting/ApplicationController.php
@@ -5,14 +5,11 @@
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Setting\ApplicationRequest;
use App\Models\Setting;
-use App\Traits\UploadAttachment;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
class ApplicationController extends Controller
{
- use UploadAttachment;
-
public function index(): View
{
return view('pages.admin.setting.application', [
diff --git a/app/Http/Requests/Admin/Master/UserRequest.php b/app/Http/Requests/Admin/Master/UserRequest.php
index 316c91f..c7db97d 100644
--- a/app/Http/Requests/Admin/Master/UserRequest.php
+++ b/app/Http/Requests/Admin/Master/UserRequest.php
@@ -28,25 +28,33 @@ public function rules(): array
{
$userId = $this->user->id ?? null;
$isEdit = $this->isMethod('put');
+ $isUserUrl = $this->is('dashboard/master/users/*');
- return [
+ $rules = [
'full_name' => ['required', 'string', 'max:255'],
'username' => ['required', 'string', 'min:5', 'max:15', Rule::unique('users', 'username')->ignore($userId)],
'email' => ['required', 'email', 'max:255', Rule::unique('users', 'email')->ignore($userId)],
'contact_number' => ['required', 'string', 'regex:/^\+?[0-9]{10,15}$/'],
'pob' => ['required', 'string', 'max:75'],
'dob' => ['required', 'date', 'before:today'],
- 'entry_date' => ['required', 'date'],
- 'base_salary' => ['required', 'numeric', 'min:0', 'max:9999999999.99'],
- 'sop' => ['nullable', 'string', 'max:65535'],
'address' => ['required', 'string', 'max:65535'],
'avatar' => $isEdit
? ['nullable', 'image', 'mimes:jpeg,png,jpg,gif,svg', 'max:2048']
: ['required', 'image', 'mimes:jpeg,png,jpg,gif,svg', 'max:2048'],
'gender' => ['required', Rule::in(['1', '2'])],
- 'barbershop' => ['required', Rule::exists('barbershop', 'id')],
- 'role' => ['required', Rule::exists('roles', 'id')],
];
+
+ if ($isUserUrl) {
+ $rules = array_merge($rules, [
+ 'entry_date' => ['required', 'date'],
+ 'base_salary' => ['required', 'numeric', 'min:0', 'max:9999999999.99'],
+ 'sop' => ['nullable', 'string', 'max:65535'],
+ 'barbershop' => ['required', Rule::exists('barbershop', 'id')],
+ 'role' => ['required', Rule::exists('roles', 'id')],
+ ]);
+ }
+
+ return $rules;
}
protected function failedValidation(Validator $validator): void
diff --git a/app/Http/Requests/Admin/Setting/PasswordRequest.php b/app/Http/Requests/Admin/Setting/PasswordRequest.php
new file mode 100644
index 0000000..9ed6864
--- /dev/null
+++ b/app/Http/Requests/Admin/Setting/PasswordRequest.php
@@ -0,0 +1,42 @@
+ ['required', 'current_password'],
+ 'new_password' => [
+ 'required',
+ 'different:current_password',
+ Password::min(8)
+ ->letters()
+ ->mixedCase()
+ ->numbers()
+ ->symbols()
+ ->uncompromised(),
+ ],
+ 'repeat_new_password' => ['required', 'same:new_password'],
+ ];
+ }
+
+ protected function failedValidation(Validator $validator): void
+ {
+ $this->handleValidationFailure($validator);
+ }
+}
diff --git a/public/assets/admin/css/icon-password.css b/public/assets/admin/css/icon-password.css
new file mode 100644
index 0000000..81fa76b
--- /dev/null
+++ b/public/assets/admin/css/icon-password.css
@@ -0,0 +1,21 @@
+.password-wrapper {
+ position: relative;
+ display: flex;
+ align-items: center;
+}
+
+.password-wrapper input {
+ padding-right: 40px;
+}
+
+.password-wrapper .toggle-password {
+ position: absolute;
+ right: 10px;
+ cursor: pointer;
+ color: #6c757d;
+ font-size: 0.85rem;
+}
+
+.password-wrapper .toggle-password:hover {
+ color: #495057;
+}
diff --git a/public/assets/admin/css/weak-password.css b/public/assets/admin/css/weak-password.css
new file mode 100644
index 0000000..1537ca4
--- /dev/null
+++ b/public/assets/admin/css/weak-password.css
@@ -0,0 +1,26 @@
+#newpass-message {
+ display: none;
+}
+
+#newpass-message p {
+ font-size: 12px;
+}
+
+.valid {
+ color: green;
+}
+
+.valid:before {
+ content: "✔";
+ font-family: Verdana, Tahoma, "DejaVu Sans", sans-serif;
+
+}
+
+.invalid {
+ color: red;
+}
+
+.invalid:before {
+ content: "✖";
+ font-family: Verdana, Tahoma, "DejaVu Sans", sans-serif;
+}
diff --git a/public/assets/css/custom.css b/public/assets/css/custom.css
index 2f79286..0eab23a 100644
--- a/public/assets/css/custom.css
+++ b/public/assets/css/custom.css
@@ -4,6 +4,12 @@ .profile-media img {
height: 35px;
object-fit: cover;
}
+.profile-media-md img {
+ border-radius: 100%;
+ width: 100px;
+ height: 100px;
+ object-fit: cover;
+}
.mode-active i {
fill: #fff !important;
diff --git a/public/assets/js/forms/toggle-password-icon.js b/public/assets/js/forms/toggle-password-icon.js
new file mode 100644
index 0000000..e584b49
--- /dev/null
+++ b/public/assets/js/forms/toggle-password-icon.js
@@ -0,0 +1,29 @@
+$(document).ready(function () {
+ feather.replace();
+
+ $(".password-wrapper").each(function () {
+ const $wrapper = $(this);
+ const $passwordInput = $wrapper.find('input[type="password"]');
+
+ const $passwordIcon = $('
{{ Auth::user()->role->name }}
@@ -33,7 +34,7 @@