diff --git a/app/Http/Controllers/Admin/Account/ProfileController.php b/app/Http/Controllers/Admin/Account/ProfileController.php index 9bec07d..4eebb03 100644 --- a/app/Http/Controllers/Admin/Account/ProfileController.php +++ b/app/Http/Controllers/Admin/Account/ProfileController.php @@ -7,6 +7,7 @@ use App\Http\Controllers\Controller; use App\Http\Requests\Admin\Account\UpdateProfileRequest; use App\Services\Account\ProfileService; +use App\Support\Media\MediaPresenter; use Illuminate\Http\RedirectResponse; use Inertia\Inertia; use Inertia\Response; @@ -26,6 +27,9 @@ public function edit(): Response return Inertia::render('admin/account/Profile', [ 'genders' => Gender::selectOptions(), 'user' => $user, + 'profilePhoto' => $user->profile + ? MediaPresenter::first($user->profile, 'profile_photo') + : null, ]); } diff --git a/app/Http/Controllers/Admin/Hr/EmployeeController.php b/app/Http/Controllers/Admin/Hr/EmployeeController.php index 27e582d..0e3fb4b 100644 --- a/app/Http/Controllers/Admin/Hr/EmployeeController.php +++ b/app/Http/Controllers/Admin/Hr/EmployeeController.php @@ -12,6 +12,7 @@ use App\Http\Requests\Admin\ToggleStatusRequest; use App\Models\User; use App\Services\Hr\EmployeeService; +use App\Support\Media\MediaPresenter; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Inertia\Inertia; @@ -85,6 +86,9 @@ public function edit(User $user): Response 'employmentStatuses' => EmploymentStatus::selectOptions(), 'roles' => $this->assignableRoleOptions(), 'employee' => $user, + 'profilePhoto' => $user->profile + ? MediaPresenter::first($user->profile, 'profile_photo') + : null, ]); } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index bd9f377..2722d2e 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -57,6 +57,7 @@ public function share(Request $request): array 'last_login_at' => $request->user()->last_login_at, 'roles' => $request->user()->getRoleNames(), 'permissions' => $request->user()->getAllPermissions()->pluck('name'), + 'profile_photo_url' => $request->user()->profile?->profile_photo_url, ] : null, 'password_default' => config('auth.password_default'), ], diff --git a/app/Http/Requests/Admin/Account/UpdateProfileRequest.php b/app/Http/Requests/Admin/Account/UpdateProfileRequest.php index 889cb2a..70f69e4 100644 --- a/app/Http/Requests/Admin/Account/UpdateProfileRequest.php +++ b/app/Http/Requests/Admin/Account/UpdateProfileRequest.php @@ -27,6 +27,9 @@ public function rules(): array 'gender' => ['nullable', Rule::enum(Gender::class)], 'birth_date' => ['nullable', 'date', 'before:today'], 'address' => ['nullable', 'string'], + 'profile_photo' => ['nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:2048'], + 'remove_profile_photo_ids' => ['nullable', 'array'], + 'remove_profile_photo_ids.*' => ['integer'], ]; } @@ -43,6 +46,7 @@ public function attributes(): array 'gender' => 'jenis kelamin', 'birth_date' => 'tanggal lahir', 'address' => 'alamat', + 'profile_photo' => 'foto profil', ]; } } diff --git a/app/Http/Requests/Admin/Hr/EmployeeRequest.php b/app/Http/Requests/Admin/Hr/EmployeeRequest.php index 2020263..2e656a4 100644 --- a/app/Http/Requests/Admin/Hr/EmployeeRequest.php +++ b/app/Http/Requests/Admin/Hr/EmployeeRequest.php @@ -37,6 +37,9 @@ public function rules(): array 'birth_date' => ['nullable', 'date', 'before:today'], 'address' => ['nullable', 'string'], 'role' => ['required', Rule::in(Role::assignableValues())], + 'profile_photo' => ['nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:2048'], + 'remove_profile_photo_ids' => ['nullable', 'array'], + 'remove_profile_photo_ids.*' => ['integer'], ]; if (! $isOwner) { @@ -61,6 +64,7 @@ public function attributes(): array 'gender' => 'jenis kelamin', 'birth_date' => 'tanggal lahir', 'address' => 'alamat', + 'profile_photo' => 'foto profil', 'role' => 'role', 'join_date' => 'tanggal bergabung', 'employment_status' => 'status kepegawaian', diff --git a/app/Models/Purchase.php b/app/Models/Purchase.php index 09ffaac..92d8435 100644 --- a/app/Models/Purchase.php +++ b/app/Models/Purchase.php @@ -3,8 +3,8 @@ namespace App\Models; use App\Enums\OwnerVerificationStatus; -use App\Models\Concerns\HasPendingOwnerVerification; use App\Models\Concerns\HasModuleMedia; +use App\Models\Concerns\HasPendingOwnerVerification; use App\Models\Concerns\InteractsWithActivityLog; use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Guarded; diff --git a/app/Models/UserProfile.php b/app/Models/UserProfile.php index 25189e1..d87acff 100644 --- a/app/Models/UserProfile.php +++ b/app/Models/UserProfile.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Enums\Gender; +use App\Models\Concerns\HasModuleMedia; use App\Models\Concerns\InteractsWithActivityLog; use Carbon\Carbon; use Illuminate\Database\Eloquent\Attributes\Appends; @@ -12,12 +13,23 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; +use Spatie\MediaLibrary\HasMedia; #[Guarded(['id'])] -#[Appends(['birth_date_formatted', 'birth_date_input', 'gender_label'])] -class UserProfile extends Model +#[Appends(['birth_date_formatted', 'birth_date_input', 'gender_label', 'profile_photo_url'])] +class UserProfile extends Model implements HasMedia { - use HasFactory, InteractsWithActivityLog, SoftDeletes; + use HasFactory, HasModuleMedia, InteractsWithActivityLog, SoftDeletes; + + public static function mediaModuleName(): string + { + return 'user-profile'; + } + + public function registerMediaCollections(): void + { + $this->addMediaCollection('profile_photo')->singleFile(); + } protected function casts(): array { @@ -52,4 +64,11 @@ public function genderLabel(): Attribute get: fn () => $this->gender?->label(), ); } + + public function profilePhotoUrl(): Attribute + { + return Attribute::make( + get: fn () => $this->getFirstMediaUrl('profile_photo') ?: null, + ); + } } diff --git a/app/Services/Account/ProfileService.php b/app/Services/Account/ProfileService.php index bde3267..ac171f5 100644 --- a/app/Services/Account/ProfileService.php +++ b/app/Services/Account/ProfileService.php @@ -3,6 +3,8 @@ namespace App\Services\Account; use App\Models\User; +use App\Models\UserProfile; +use App\Services\Media\MediaService; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Log; @@ -10,6 +12,10 @@ class ProfileService { + public function __construct( + private readonly MediaService $mediaService, + ) {} + /** * @param array $validated */ @@ -22,7 +28,8 @@ public function update(array $validated, User $user): void 'username' => $validated['username'], ]); - $user->profile()->updateOrCreate( + /** @var UserProfile $profile */ + $profile = $user->profile()->updateOrCreate( ['user_id' => $user->id], [ 'full_name' => $validated['full_name'], @@ -32,6 +39,11 @@ public function update(array $validated, User $user): void 'address' => $validated['address'] ?? null, ], ); + + $newFiles = ! empty($validated['profile_photo']) ? [$validated['profile_photo']] : []; + $removeIds = $validated['remove_profile_photo_ids'] ?? []; + + $this->mediaService->syncCollection($profile, 'profile_photo', $newFiles, $removeIds, 1); }); } catch (ValidationException $e) { throw $e; diff --git a/app/Services/Hr/EmployeeService.php b/app/Services/Hr/EmployeeService.php index 2cd8ccf..2589104 100644 --- a/app/Services/Hr/EmployeeService.php +++ b/app/Services/Hr/EmployeeService.php @@ -6,6 +6,7 @@ use App\Models\Employee; use App\Models\User; use App\Models\UserProfile; +use App\Services\Media\MediaService; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; @@ -15,6 +16,10 @@ class EmployeeService { + public function __construct( + private readonly MediaService $mediaService, + ) {} + /** * @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery */ @@ -66,7 +71,7 @@ public function create(array $validated): void 'password' => Hash::make(config('auth.password_default')), ]); - UserProfile::create([ + $profile = UserProfile::create([ 'user_id' => $user->id, 'full_name' => $validated['full_name'], 'phone_number' => $validated['phone_number'], @@ -75,6 +80,8 @@ public function create(array $validated): void 'address' => $validated['address'], ]); + $this->syncProfilePhoto($profile, $validated); + if ($validated['role'] !== Role::OWNER->value) { Employee::create([ 'user_id' => $user->id, @@ -113,7 +120,8 @@ public function update(User $user, array $validated): void 'username' => $validated['username'], ]); - $user->profile()->updateOrCreate( + /** @var UserProfile $profile */ + $profile = $user->profile()->updateOrCreate( ['user_id' => $user->id], [ 'full_name' => $validated['full_name'], @@ -124,6 +132,8 @@ public function update(User $user, array $validated): void ], ); + $this->syncProfilePhoto($profile, $validated); + $hasEmployee = ! empty($validated['join_date']) && ! empty($validated['employment_status']) && ! empty($validated['base_salary']); if ($hasEmployee) { @@ -203,6 +213,17 @@ public function delete(User $user): void } } + /** + * @param array $validated + */ + private function syncProfilePhoto(UserProfile $profile, array $validated): void + { + $newFiles = ! empty($validated['profile_photo']) ? [$validated['profile_photo']] : []; + $removeIds = $validated['remove_profile_photo_ids'] ?? []; + + $this->mediaService->syncCollection($profile, 'profile_photo', $newFiles, $removeIds, 1); + } + private function applySorting(Builder $query, string $sort, string $direction): void { $employeeSorts = [ diff --git a/app/Services/Manage/OwnerVerificationService.php b/app/Services/Manage/OwnerVerificationService.php index d839085..9c90d04 100644 --- a/app/Services/Manage/OwnerVerificationService.php +++ b/app/Services/Manage/OwnerVerificationService.php @@ -11,7 +11,6 @@ use App\Models\Purchase; use App\Models\RawMaterial; use App\Models\User; -use App\Services\Manage\PurchaseService; use App\Services\Master\ProductService; use App\Services\Master\RawMaterialService; use App\Services\System\PushNotificationService; diff --git a/resources/js/components/UserNav.vue b/resources/js/components/UserNav.vue index c10ac23..e4184a5 100644 --- a/resources/js/components/UserNav.vue +++ b/resources/js/components/UserNav.vue @@ -1,5 +1,5 @@ @@ -164,6 +194,9 @@ function submit() { + Alamat