feat(profile): create function update profile picture

This commit is contained in:
arieeefajar 2025-03-04 19:35:55 +07:00
parent f02a867398
commit 27f3673c7f
7 changed files with 111 additions and 58 deletions

View File

@ -7,6 +7,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
class ProfileController extends Controller
@ -35,12 +36,17 @@ public function updateData(request $request)
'email.unique' => 'Email sudah terdaftar',
'email.max' => 'Email maksimal 255 karakter',
'email.string' => 'Email harus berupa string',
'avatar.image' => 'Foto profile harus berupa gambar',
'avatar.mimes' => 'Format foto profile tidak sesuai, harus jpeg, png, atau jpg',
'avatar.max' => 'Ukuran foto profile maksimal 2MB',
];
$validator = Validator::make($request->all(), [
'username' => 'required|string|max:12|unique:users,username,' . Auth::user()->id,
'name' => 'required|string|max:255|unique:users,name,' . Auth::user()->id,
'email' => 'required|string|email|max:255|unique:users,email,' . Auth::user()->id,
'avatar' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
], $customMessage);
if ($validator->fails()) {
@ -48,12 +54,22 @@ public function updateData(request $request)
return redirect()->back()->withInput();
}
$user = User::find(Auth::user()->id);
$user->username = $request->username;
$user->name = $request->name;
$user->email = $request->email;
try {
$user = User::findOrFail(Auth::id());
$user->username = $request->username;
$user->name = $request->name;
$user->email = $request->email;
if ($request->hasFile('avatar')) {
$path = $request->file('avatar')->store('avatars', 'public');
if (!empty($user->avatar) && Storage::disk('public')->exists($user->avatar)) {
Storage::disk('public')->delete($user->avatar);
}
$user->avatar = $path;
}
$user->save();
toast('Data berhasil diubah', 'success')->position('top-right')->autoclose(3000);
return redirect()->back();
@ -65,7 +81,6 @@ public function updateData(request $request)
public function updatePassword(request $request)
{
// dd($request->all());
$customMessage = [
'new_password.required' => 'Password wajib diisi',
'new_password.confirmed' => 'Konfirmasi password tidak cocok',

View File

@ -0,0 +1,60 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ProfileUpdateRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\View\View;
class ProfileController extends Controller
{
/**
* Display the user's profile form.
*/
public function edit(Request $request): View
{
return view('profile.edit', [
'user' => $request->user(),
]);
}
/**
* Update the user's profile information.
*/
public function update(ProfileUpdateRequest $request): RedirectResponse
{
$request->user()->fill($request->validated());
if ($request->user()->isDirty('email')) {
$request->user()->email_verified_at = null;
}
$request->user()->save();
return Redirect::route('profile.edit')->with('status', 'profile-updated');
}
/**
* Delete the user's account.
*/
public function destroy(Request $request): RedirectResponse
{
$request->validateWithBag('userDeletion', [
'password' => ['required', 'current_password'],
]);
$user = $request->user();
Auth::logout();
$user->delete();
$request->session()->invalidate();
$request->session()->regenerateToken();
return Redirect::to('/');
}
}

View File

@ -23,6 +23,7 @@ class User extends Authenticatable
'email',
'password',
'role',
'avatar'
];
/**

View File

@ -22,6 +22,7 @@ public function up(): void
$table->enum('role', ['admin', 'user'])->default('user');
$table->string('activation_code')->nullable();
$table->boolean('is_active')->default(false);
$table->string('avatar')->nullable();
$table->timestamps();
});
}

View File

@ -1,40 +1,14 @@
document
.querySelector("#profile-img-file-input")
.addEventListener("change", function () {
var o = document.querySelector(".user-profile-image"),
e = document.querySelector(".profile-img-file-input").files[0],
i = new FileReader();
i.addEventListener(
"load",
function () {
o.src = i.result;
},
!1
),
e && i.readAsDataURL(e);
});
var count = 2;
function new_link() {
count++;
var o = document.createElement("div"),
e =
'<div class="row"><div class="col-lg-12"><div class="mb-3"><label for="jobTitle1" class="form-label">Job Title</label><input type="text" class="form-control" id="jobTitle1" placeholder="Job title"></div></div><div class="col-lg-6"><div class="mb-3"><label for="companyName" class="form-label">Company Name</label><input type="text" class="form-control" id="companyName" placeholder="Company name"></div></div><div class="col-lg-6"><div class="mb-3"><label for="choices-single-default3" class="form-label">Experience Years</label><div class="row"><div class="col-lg-5"><select class="form-control" data-trigger name="choices-single-default3"> <option value="">Select years</option><option value="Choice 1">2001</option><option value="Choice 2">2002</option><option value="Choice 3">2003</option><option value="Choice 4">2004</option><option value="Choice 5">2005</option><option value="Choice 6">2006</option><option value="Choice 7">2007</option><option value="Choice 8">2008</option><option value="Choice 9">2009</option><option value="Choice 10">2010</option><option value="Choice 11">2011</option><option value="Choice 12">2012</option><option value="Choice 13">2013</option><option value="Choice 14">2014</option><option value="Choice 15">2015</option><option value="Choice 16">2016</option><option value="Choice 17">2017</option><option value="Choice 18">2018</option><option value="Choice 19">2019</option><option value="Choice 20">2020</option><option value="Choice 21">2021</option><option value="Choice 22">2022</option></select></div><div class="col-auto align-self-center">to</div><div class="col-lg-5"><select class="form-control" data-trigger name="choices-single-default2"><option value="">Select years</option><option value="Choice 1">2001</option><option value="Choice 2">2002</option><option value="Choice 3">2003</option><option value="Choice 4">2004</option><option value="Choice 5">2005</option><option value="Choice 6">2006</option><option value="Choice 7">2007</option><option value="Choice 8">2008</option><option value="Choice 9">2009</option><option value="Choice 10">2010</option><option value="Choice 11">2011</option><option value="Choice 12">2012</option><option value="Choice 13">2013</option><option value="Choice 14">2014</option><option value="Choice 15">2015</option><option value="Choice 16">2016</option><option value="Choice 17">2017</option><option value="Choice 18">2018</option><option value="Choice 19">2019</option><option value="Choice 20">2020</option><option value="Choice 21">2021</option><option value="Choice 22">2022</option></select></div></div></div></div><div class="col-lg-12"><div class="mb-3"><label for="jobDescription" class="form-label">Job Description</label><textarea class="form-control" id="jobDescription" rows="3" placeholder="Enter description"></textarea></div></div><div class="hstack gap-2 justify-content-end"><a class="btn btn-success" href="javascript:deleteEl(' +
(o.id = count) +
')">Delete</a></div></div>';
(o.innerHTML = document.getElementById("newForm").innerHTML + e),
document.getElementById("newlink").appendChild(o);
var t = document.querySelectorAll("[data-trigger]");
for (i = 0; i < t.length; ++i) {
var l = t[i];
new Choices(l, {
placeholderValue: "This is a placeholder set in the config",
searchPlaceholderValue: "This is a search placeholder",
searchEnabled: !1,
});
function previewImage(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function () {
var previewImg = document.getElementById("preview-img");
previewImg.src = reader.result;
};
if (input.files && input.files[0]) {
reader.readAsDataURL(input.files[0]);
}
}
function deleteEl(o) {
d = document;
o = d.getElementById(o);
d.getElementById("newlink").removeChild(o);
}

View File

@ -16,20 +16,12 @@
<div class="card-body p-4">
<div class="text-center">
<div class="profile-user position-relative d-inline-block mx-auto mb-4">
<img src="assets/images/users/avatar-1.jpg"
<img src="{{ $user->avatar ? asset('storage/' . $user->avatar) : asset('assets/images/users/user-dummy-img.jpg') }}"
class="rounded-circle avatar-xl img-thumbnail user-profile-image"
alt="user-profile-image">
<div class="avatar-xs p-0 rounded-circle profile-photo-edit">
<input id="profile-img-file-input" type="file" class="profile-img-file-input">
<label for="profile-img-file-input" class="profile-photo-edit avatar-xs">
<span class="avatar-title rounded-circle bg-light text-body">
<i class="ri-camera-fill"></i>
</span>
</label>
</div>
alt="user-profile-image" id="preview-img">
</div>
<h5 class="fs-16 mb-1">Anna Adame</h5>
<p class="text-muted mb-0">Lead Designer / Developer</p>
<h5 class="fs-16 mb-1">{{ $user->name }}</h5>
<p class="text-muted mb-0">{{ $user->role }}</p>
</div>
</div>
</div>
@ -58,7 +50,7 @@ class="rounded-circle avatar-xl img-thumbnail user-profile-image"
<div class="tab-content">
<div class="tab-pane active" id="personalDetails" role="tabpanel">
<form action="{{ route('profile.update_data') }}" class="needs-validation" novalidate
id="personalDetailsForm" method="POST">
id="personalDetailsForm" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="row">
@ -98,6 +90,15 @@ class="rounded-circle avatar-xl img-thumbnail user-profile-image"
</div>
</div>
<!--end col-->
<div class="col-lg-6">
<div class="mb-3">
<label for="avatarInput" class="form-label">Foto Profile</label>
<input type="file" class="form-control" id="avatar" name="avatar"
accept="image/jpeg,image/png,image/jpg"
onchange="previewImage(event)">
</div>
</div>
<!--end col-->
<div class="col-lg-12">
<div class="hstack gap-2 justify-content-end">
<button type="submit" class="btn btn-success">Ubah</button>

View File

@ -168,7 +168,8 @@ class="btn btn-icon btn-topbar btn-ghost-secondary rounded-circle light-dark-mod
<button type="button" class="btn" id="page-header-user-dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="d-flex align-items-center">
<img class="rounded-circle header-profile-user" src="assets/images/users/avatar-1.jpg"
<img class="rounded-circle header-profile-user"
src="{{ Auth::user()->avatar ? asset('storage/' . Auth::user()->avatar) : asset('assets/images/users/user-dummy-img.jpg') }}"
alt="Header Avatar">
<span class="text-start ms-xl-2">
<span