diff --git a/app/Http/Controllers/Web/Account/EditProfileController.php b/app/Http/Controllers/Web/Account/EditProfileController.php index e350f38..38c0ee1 100644 --- a/app/Http/Controllers/Web/Account/EditProfileController.php +++ b/app/Http/Controllers/Web/Account/EditProfileController.php @@ -6,22 +6,33 @@ use App\Http\Requests\Account\EditProfileRequest; use App\Models\ProfileInfoModel; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Storage; class EditProfileController extends Controller { public function edit(EditProfileRequest $request) { - $profile_info = ProfileInfoModel::updateOrCreate( - ['user_id' => auth()->user()->id], - [ - 'bio' => $request->post('bio'), - 'link' => $request->post('link') - ] - ); - - auth()->user()->name = $request->name; - $save = auth()->user()->save(); + auth()->user()->name = $request->post('name'); + auth()->user()->bio = $request->post('bio'); + auth()->user()->website = $request->post('website'); + + if($request->hasFile('avatar')) { + auth()->user()->avatar = $request->file('avatar')->store('avatars'); + } + + if($request->hasFile('banner')) { + auth()->user()->banner = $request->file('banner')->store('banners'); + } + if($request->has('delete_banner')) { + if(auth()->user()->banner) { + Storage::disk('public')->delete(auth()->user()->banner); + } + + auth()->user()->banner = null; + } + + $save = auth()->user()->save(); - if($profile_info && $save) { + if($save) { return response()->json([ 'status' => true, 'type' => 'success', diff --git a/app/Http/Controllers/Web/Account/LoginController.php b/app/Http/Controllers/Web/Account/LoginController.php index 9fc1c15..71a2a92 100644 --- a/app/Http/Controllers/Web/Account/LoginController.php +++ b/app/Http/Controllers/Web/Account/LoginController.php @@ -36,6 +36,7 @@ public function signup(SignUpRequest $request) { $user = User::create($request->validated()); if($user) { + Auth::login($user); $user->notify(new VerifyEmailNotification); return response()->json([ diff --git a/app/Http/Controllers/Web/Account/ProfileController.php b/app/Http/Controllers/Web/Account/ProfileController.php index 4b49379..8b5b7a1 100644 --- a/app/Http/Controllers/Web/Account/ProfileController.php +++ b/app/Http/Controllers/Web/Account/ProfileController.php @@ -9,7 +9,6 @@ class ProfileController extends Controller { public function render(User $user) { - $profile_info = $user->profileInfo; - return view('pages/account/profile', compact('user', 'profile_info')); + return view('pages/account/profile', compact('user')); } } diff --git a/app/Http/Requests/Account/EditProfileRequest.php b/app/Http/Requests/Account/EditProfileRequest.php index 1524d6a..e5f1c05 100644 --- a/app/Http/Requests/Account/EditProfileRequest.php +++ b/app/Http/Requests/Account/EditProfileRequest.php @@ -18,7 +18,10 @@ public function rules(): array { return [ 'name' => 'required|min:3|string|max:255', 'bio' => 'nullable|string|min:5|max:255', - 'link' => 'nullable|active_url' + 'website' => 'nullable|active_url', + 'banner' => 'nullable|image|max:5120|mimes:jpg,png', + 'avatar' => 'nullable|image|max:5120|mimes:jpg,png', + 'delete_banner' => 'sometimes' ]; } @@ -26,17 +29,23 @@ public function attributes() : array { return [ 'name' => 'Имя', 'bio' => 'Описание', - 'link' => 'Ссылка' + 'website' => 'Ссылка', + 'banner' => 'Баннер', + 'avatar' => 'Аватар' ]; } public function messages() : array { return [ 'required' => ":attribute является обязательным полем.", - 'min' => ':attribute должен быть минимум :min символов.', + 'name.min' => ':attribute должен быть минимум :min символов.', 'string' => ':attribute должен быть строкой.', - 'max' => ':attribute может быть максимум :max символов.', - 'active_url' => ':attribute должна быть рабочей ссылкой.' + 'name.max' => ':attribute может быть максимум :max символов.', + 'active_url' => ':attribute должна быть рабочей ссылкой.', + 'image' => ':attribute должен быть изображением.', + 'banner.max' => ':attribute может быть максимум :max КБ', + 'avatar.max' => ':attribute может быть максимум :max КБ', + 'mimes' => ':attribute может быть только в формате PNG, JPG.' ]; } diff --git a/app/Models/User.php b/app/Models/User.php index 4e97b81..303a04e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -23,6 +23,8 @@ class User extends Authenticatable 'username', 'email', 'password', + 'avatar', + 'banner' ]; /** @@ -61,7 +63,11 @@ public function profileLink() { return route('profile.profile', $this->username); } - public function profileInfo() { - return $this->hasOne(ProfileInfoModel::class); + public function getAvatarLink() { + return url('/storage/'.$this->avatar); + } + + public function getBannerLink() { + return url('/storage/'.$this->banner); } } diff --git a/app/Traits/Followable.php b/app/Traits/Followable.php index eb8be10..57511c7 100644 --- a/app/Traits/Followable.php +++ b/app/Traits/Followable.php @@ -12,22 +12,8 @@ public function follows() 'user_id', 'following_user_id'); } - public function follow(User $user) - { - return $this->follows()->save($user); - } - - public function unfollow(User $user) - { - return $this->follows()->detach($user); - } - public function toggleFollow(User $user) { - if($this->isFollowing($user)) { - return $this->unfollow($user); - } - - return $this->follow($user); + return $this->follows()->toggle($user); } diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index e83809b..4767f05 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -14,7 +14,11 @@ public function up(): void Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); - $table->string('username'); + $table->string('username')->unique(); + $table->string('avatar')->nullable(); + $table->string('banner')->nullable(); + $table->string('bio')->nullable(); + $table->string('website')->nullable(); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); diff --git a/database/migrations/2023_08_26_213732_profile_info_migration.php b/database/migrations/2023_08_26_213732_profile_info_migration.php deleted file mode 100644 index 014e2d0..0000000 --- a/database/migrations/2023_08_26_213732_profile_info_migration.php +++ /dev/null @@ -1,31 +0,0 @@ -primary('user_id'); - $table->string('bio')->nullable(); - $table->string('link')->nullable(); - $table->foreignId('user_id'); - $table->timestamps(); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - // - } -}; diff --git a/public/img/default/default-avatar.svg b/public/img/default/default-avatar.svg new file mode 100644 index 0000000..703f92f --- /dev/null +++ b/public/img/default/default-avatar.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/default/default-banner.svg b/public/img/default/default-banner.svg new file mode 100644 index 0000000..8a93ef1 --- /dev/null +++ b/public/img/default/default-banner.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/js/script.js b/public/js/script.js index 99478ab..8664afe 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -27,6 +27,58 @@ $('#edit_profile_form').submit(function (e) { }); }); +$("#banner_input, #avatar_input").change(function (e) { + e.preventDefault(); + + const _self = $(this); + const image = _self.prop('files')[0]; + + const id = _self.attr('id'); + const preview_id = id.split('_')[0]; + + if(id === 'banner_input') { + const label = $("label[for='delete_banner']"); + + label.removeClass('hidden'); + } + + if(!image) return; + + if((image.size / 10**6) > 5) { + return createToast({message: "Файл слишком большой. Максимальный размер - 5 мб.", type: "error"}); + } + + const reader = new FileReader(); + + reader.onload = function (event) { + $("#"+ preview_id +"_preview").attr('src', reader.result); + }; + + reader.readAsDataURL(image); +}); + +$("body").on('change', '#delete_banner', function () { + const _self = $(this); + const checked = _self.is(":checked"); + + if(checked) { + const avatar_preview = $("#banner_preview"); + const src = avatar_preview.attr('src'); + const data_src = avatar_preview.attr('data-user-banner-link'); + + if(data_src && src !== data_src) { //уже был установлен какой-то баннер: превью поверх основного баннера или просто основной баннер + avatar_preview.attr('src', data_src); + _self.prop('checked', false); + $("#banner_input").val(''); //очищаем инпут с картинкой + } else { //удаляется либо превью, если баннера не было, либо сам баннер + avatar_preview.attr('src', '/img/default/default-banner.svg'); + avatar_preview.removeAttr('data-user-avatar-link'); + _self.closest('label').addClass("hidden"); + _self.addClass("hidden"); + } + } +}); + $('#send_email_verification_form').submit(function (e) { e.preventDefault(); diff --git a/resources/assets/js/editProfile.js b/resources/assets/js/editProfile.js index 306466d..94a08ce 100644 --- a/resources/assets/js/editProfile.js +++ b/resources/assets/js/editProfile.js @@ -26,3 +26,55 @@ $('#edit_profile_form').submit(function (e) { submit_button.prop('disabled', false); }); }); + +$("#banner_input, #avatar_input").change(function (e) { + e.preventDefault(); + + const _self = $(this); + const image = _self.prop('files')[0]; + + const id = _self.attr('id'); + const preview_id = id.split('_')[0]; + + if(id === 'banner_input') { + const label = $("label[for='delete_banner']"); + + label.removeClass('hidden'); + } + + if(!image) return; + + if((image.size / 10**6) > 5) { + return createToast({message: "Файл слишком большой. Максимальный размер - 5 мб.", type: "error"}); + } + + const reader = new FileReader(); + + reader.onload = function (event) { + $("#"+ preview_id +"_preview").attr('src', reader.result); + }; + + reader.readAsDataURL(image); +}); + +$("body").on('change', '#delete_banner', function () { + const _self = $(this); + const checked = _self.is(":checked"); + + if(checked) { + const avatar_preview = $("#banner_preview"); + const src = avatar_preview.attr('src'); + const data_src = avatar_preview.attr('data-user-banner-link'); + + if(data_src && src !== data_src) { //уже был установлен какой-то баннер: превью поверх основного баннера или просто основной баннер + avatar_preview.attr('src', data_src); + _self.prop('checked', false); + $("#banner_input").val(''); //очищаем инпут с картинкой + } else { //удаляется либо превью, если баннера не было, либо сам баннер + avatar_preview.attr('src', '/img/default/default-banner.svg'); + avatar_preview.removeAttr('data-user-avatar-link'); + _self.closest('label').addClass("hidden"); + _self.addClass("hidden"); + } + } +}); diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index d53ba60..83ea2f1 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -37,11 +37,18 @@
Подписки
- Посмотреть всех + @if($follows->isNotEmpty()) + Посмотреть всех + @endif
diff --git a/resources/views/pages/account/profile.blade.php b/resources/views/pages/account/profile.blade.php index 912aeb0..6980e0d 100644 --- a/resources/views/pages/account/profile.blade.php +++ b/resources/views/pages/account/profile.blade.php @@ -6,7 +6,7 @@