diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index c09159f..3580f1c 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -59,17 +59,13 @@ public function edit(User $user) return Inertia::render('admin/users/CreateOrEdit', [ 'user' => $user->load(['roles', 'permissions']), 'permissions' => Permission::select('name')->get(), - 'shouldHideOptions' => (Auth::id() === $user->id && !Auth::user()->can('manage users')), //hide options when showing own profile && don't have manage user permission. ]); } public function update(UpdateUserRequest $request, User $user) { - if ( - ($request->user()->id !== $user->id && - !$request->user()->can('manage users')) || $user->email === "check@example.com" - ) { - throw UnauthorizedException::forPermissions(['manage users']); + if ($user->email === 'check@example.com') { + abort(403, 'This demo user cannot be modified.'); } $validated = $request->validated(); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php new file mode 100644 index 0000000..33bafbf --- /dev/null +++ b/app/Http/Controllers/ProfileController.php @@ -0,0 +1,39 @@ + $request->user(), + ]); + } + + public function update(UpdateProfileRequest $request) + { + $user = $request->user(); + $validated = $request->validated(); + + if ($request->hasFile('file')) { + $path = $request->file('file')->store('users/profile-images'); + + if ($user->image_path) { + Storage::delete($user->image_path); + } + + $validated['image_path'] = $path; + } + + $user->update($validated); + + return redirect()->route('profile.edit') + ->with('success', 'Profile updated successfully.'); + } +} diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 36e3e02..1f8a9ce 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -40,6 +40,7 @@ public function share(Request $request): array 'name' => config('app.name'), 'auth' => [ 'user' => $request->user(), + 'can_access_admin' => $request->user()?->can('view admin') ?? false, ], 'flash' => [ 'success' => fn() => $request->session()->get('success'), diff --git a/app/Http/Requests/Profile/UpdateProfileRequest.php b/app/Http/Requests/Profile/UpdateProfileRequest.php new file mode 100644 index 0000000..3d6f805 --- /dev/null +++ b/app/Http/Requests/Profile/UpdateProfileRequest.php @@ -0,0 +1,46 @@ +user() !== null; + } + + protected function prepareForValidation(): void + { + if (! $this->filled('password')) { + $this->replace($this->except('password')); + } + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + $userId = $this->user()->id; + + return [ + 'name' => ['required', 'string', 'max:255'], + 'password' => ['sometimes', 'nullable', 'string', 'min:6'], + 'file' => ['sometimes', 'nullable', 'image', 'max:2048'], + 'about' => ['sometimes', 'nullable', 'string'], + 'title' => ['sometimes', 'nullable', 'string', 'max:255'], + 'institution' => ['sometimes', 'nullable', 'string', 'max:255'], + 'facebook' => ['sometimes', 'nullable', 'string', 'max:255'], + 'instagram' => ['sometimes', 'nullable', 'string', 'max:255'], + 'github' => ['sometimes', 'nullable', 'string', 'max:255'], + ]; + } +} diff --git a/app/Http/Requests/User/UpdateUserRequest.php b/app/Http/Requests/User/UpdateUserRequest.php index e211892..593a0cf 100644 --- a/app/Http/Requests/User/UpdateUserRequest.php +++ b/app/Http/Requests/User/UpdateUserRequest.php @@ -42,14 +42,11 @@ public function rules(): array 'facebook' => ['sometimes', 'nullable', 'string', 'max:255'], 'instagram' => ['sometimes', 'nullable', 'string', 'max:255'], 'github' => ['sometimes', 'nullable', 'string', 'max:255'], + 'role' => ['sometimes', 'string'], + 'permissions' => ['sometimes', 'array'], + 'permissions.*' => ['string', 'exists:permissions,name'], ]; - if ($this->user()->can('manage users')) { - $rules['role'] = ['sometimes', 'string']; - $rules['permissions'] = ['sometimes', 'array']; - $rules['permissions.*'] = ['string', 'exists:permissions,name']; - } - return $rules; } } diff --git a/resources/js/components/NavBar.vue b/resources/js/components/NavBar.vue index 0d7593c..034f0af 100644 --- a/resources/js/components/NavBar.vue +++ b/resources/js/components/NavBar.vue @@ -8,6 +8,7 @@ import { Moon, Sun, Monitor, + User, } from 'lucide-vue-next'; import { computed, ref, onMounted, onBeforeUnmount } from 'vue'; import { useDarkMode } from '@/lib/useDarkMode'; @@ -23,6 +24,7 @@ defineProps({ const { theme, toggle } = useDarkMode(); const user = computed(() => usePage().props.auth?.user); +const canAccessAdmin = computed(() => usePage().props.auth?.can_access_admin); const dropdownOpen = ref(false); const dropdownRef = ref(null); @@ -149,6 +151,16 @@ onBeforeUnmount(() => { + + Profile + + + -import { usePage } from '@inertiajs/vue3'; -import { - LayoutDashboard, - Users, - BookOpen, - Bell, - Book, - User, -} from 'lucide-vue-next'; +import { LayoutDashboard, Users, BookOpen, Bell, Book } from 'lucide-vue-next'; import { ref } from 'vue'; import DesktopSidebar from '@/components/admin/DesktopSidebar.vue'; import MobileSideBar from '@/components/admin/MobileSideBar.vue'; @@ -16,14 +8,12 @@ import NavBar from '@/components/NavBar.vue'; import ToastNotification from '@/components/ToastNotification.vue'; const isMobileSidebarOpen = ref(false); -const myId = usePage().props.auth.user.id; const navigation = [ { name: 'Dashboard', to: '/admin', icon: LayoutDashboard }, { name: 'Manage Contents', to: '/admin/subjects', icon: BookOpen }, { name: 'Manage Blogs', to: '/admin/blogs', icon: Book }, { name: 'Site Notice', to: '/admin/notice', icon: Bell }, { name: 'Users', to: '/admin/users', icon: Users }, - { name: 'My Profile', to: `/admin/users/edit/${myId}`, icon: User }, ]; const openMobileSidebar = () => { diff --git a/resources/js/pages/Profile.vue b/resources/js/pages/Profile.vue new file mode 100644 index 0000000..dd9ba59 --- /dev/null +++ b/resources/js/pages/Profile.vue @@ -0,0 +1,471 @@ + + + diff --git a/resources/js/pages/admin/resources/BulkImageCreate.vue b/resources/js/pages/admin/resources/BulkImageCreate.vue index 585b04d..d16f140 100644 --- a/resources/js/pages/admin/resources/BulkImageCreate.vue +++ b/resources/js/pages/admin/resources/BulkImageCreate.vue @@ -55,12 +55,15 @@ const addFiles = (files) => { ); const availableSlots = MAX_IMAGES - selectedFiles.value.length; + if (availableSlots <= 0) { fileLimitError.value = `You can only upload a maximum of ${MAX_IMAGES} images at once.`; + return; } const filesToAdd = imageFiles.slice(0, availableSlots); + if (imageFiles.length > availableSlots) { fileLimitError.value = `Only the first ${availableSlots} image(s) were added. Maximum limit is ${MAX_IMAGES} images.`; } diff --git a/resources/js/pages/admin/users/CreateOrEdit.vue b/resources/js/pages/admin/users/CreateOrEdit.vue index 9244823..86226d1 100644 --- a/resources/js/pages/admin/users/CreateOrEdit.vue +++ b/resources/js/pages/admin/users/CreateOrEdit.vue @@ -6,7 +6,6 @@ import { watch } from 'vue'; const props = defineProps({ user: Object, permissions: Array, - shouldHideOptions: Boolean, }); const roles = [ @@ -182,7 +181,7 @@ const submitForm = () => {

-
+