diff --git a/app/Http/Controllers/Web/Account/EditProfileController.php b/app/Http/Controllers/Web/Account/EditProfileController.php
new file mode 100644
index 0000000..e350f38
--- /dev/null
+++ b/app/Http/Controllers/Web/Account/EditProfileController.php
@@ -0,0 +1,38 @@
+ auth()->user()->id],
+ [
+ 'bio' => $request->post('bio'),
+ 'link' => $request->post('link')
+ ]
+ );
+
+ auth()->user()->name = $request->name;
+ $save = auth()->user()->save();
+
+
+ if($profile_info && $save) {
+ return response()->json([
+ 'status' => true,
+ 'type' => 'success',
+ 'message' => 'Данные успешно сохранены.'
+ ]);
+ }
+
+ return response()->json([
+ 'status' => false,
+ 'type' => 'error',
+ 'message' => 'Произошла ошибка. Попробуйте еще раз.'
+ ]);
+ }
+}
diff --git a/app/Http/Controllers/Web/Account/ProfileController.php b/app/Http/Controllers/Web/Account/ProfileController.php
new file mode 100644
index 0000000..4b49379
--- /dev/null
+++ b/app/Http/Controllers/Web/Account/ProfileController.php
@@ -0,0 +1,15 @@
+profileInfo;
+ return view('pages/account/profile', compact('user', 'profile_info'));
+ }
+}
diff --git a/app/Http/Controllers/Web/Follow/FollowsController.php b/app/Http/Controllers/Web/Follow/FollowsController.php
new file mode 100644
index 0000000..4402c07
--- /dev/null
+++ b/app/Http/Controllers/Web/Follow/FollowsController.php
@@ -0,0 +1,18 @@
+user()->toggleFollow($user);
+
+ return response()->json([
+ 'status' => true
+ ]);
+ }
+}
diff --git a/app/Http/Controllers/Web/Posts/PostsController.php b/app/Http/Controllers/Web/Posts/PostsController.php
index ee1cf3a..2dc57e6 100644
--- a/app/Http/Controllers/Web/Posts/PostsController.php
+++ b/app/Http/Controllers/Web/Posts/PostsController.php
@@ -5,12 +5,18 @@
use App\Http\Controllers\Controller;
use App\Http\Requests\Posts\CreateRequest;
use App\Models\PostsModel;
+use App\Models\User;
class PostsController extends Controller {
- public function get() {
+ public function feed() {
return auth()->user()->feed();
}
+ public function get($id) {
+ return User::find($id)->posts;
+ }
+
+
public function create(CreateRequest $request) {
$post = PostsModel::create([
'user_id' => auth()->id(),
diff --git a/app/Http/Requests/Account/EditProfileRequest.php b/app/Http/Requests/Account/EditProfileRequest.php
new file mode 100644
index 0000000..1524d6a
--- /dev/null
+++ b/app/Http/Requests/Account/EditProfileRequest.php
@@ -0,0 +1,59 @@
+ 'required|min:3|string|max:255',
+ 'bio' => 'nullable|string|min:5|max:255',
+ 'link' => 'nullable|active_url'
+ ];
+ }
+
+ public function attributes() : array {
+ return [
+ 'name' => 'Имя',
+ 'bio' => 'Описание',
+ 'link' => 'Ссылка'
+ ];
+ }
+
+ public function messages() : array {
+ return [
+ 'required' => ":attribute является обязательным полем.",
+ 'min' => ':attribute должен быть минимум :min символов.',
+ 'string' => ':attribute должен быть строкой.',
+ 'max' => ':attribute может быть максимум :max символов.',
+ 'active_url' => ':attribute должна быть рабочей ссылкой.'
+ ];
+ }
+
+ protected function failedValidation(Validator $validator) : void {
+ throw new HttpResponseException(response()->json([
+ 'status' => false,
+ 'type' => 'error',
+ 'message' => $validator->errors()->first()
+ ]));
+
+ }
+
+ public function failedAuthorization() : void {
+ throw new HttpResponseException(response()->json([
+ 'status' => false,
+ 'type' => 'error',
+ 'message' => 'Вы не можете выполнить данное действие.'
+ ]));
+ }
+}
diff --git a/app/Models/ProfileInfoModel.php b/app/Models/ProfileInfoModel.php
new file mode 100644
index 0000000..0897ded
--- /dev/null
+++ b/app/Models/ProfileInfoModel.php
@@ -0,0 +1,21 @@
+hasMany(PostsModel::class)->with('user');
+ return $this->hasMany(PostsModel::class)->with('user')->latest();
}
- public function follows() {
- return $this->belongsToMany(User::class, 'follows', 'user_id', 'following_user_id');
+ public function profileLink() {
+ return route('profile.profile', $this->username);
}
- public function follow(User $user) {
- return $this->follows()->save($user);
+ public function profileInfo() {
+ return $this->hasOne(ProfileInfoModel::class);
}
}
diff --git a/app/Traits/Followable.php b/app/Traits/Followable.php
new file mode 100644
index 0000000..eb8be10
--- /dev/null
+++ b/app/Traits/Followable.php
@@ -0,0 +1,38 @@
+belongsToMany(User::class, '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);
+ }
+
+
+ public function isFollowing(User $user)
+ {
+ return $this->follows()->where('following_user_id', $user->id)->exists();
+ }
+}
diff --git a/database/migrations/2023_08_26_213732_profile_info_migration.php b/database/migrations/2023_08_26_213732_profile_info_migration.php
new file mode 100644
index 0000000..014e2d0
--- /dev/null
+++ b/database/migrations/2023_08_26_213732_profile_info_migration.php
@@ -0,0 +1,31 @@
+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/js/script.js b/public/js/script.js
index b4a6922..99478ab 100644
--- a/public/js/script.js
+++ b/public/js/script.js
@@ -1,3 +1,32 @@
+$('#edit_profile_form').submit(function (e) {
+ e.preventDefault();
+
+ const _self = $(this);
+ const submit_button = _self.find(':submit');
+ submit_button.addClass('disabled');
+ submit_button.prop('disabled', true);
+
+ const url = _self.attr('action');
+ const data = new FormData(this);
+
+ axios.post(url, data)
+ .then(data => {
+ if(data.data.status) {
+ _self.closest('#edit_profile-modal').find('button[data-modal-hide]').trigger('click'); //закрытие модального окна
+ createToast({...data.data});
+ } else {
+ createToast({...data.data});
+ }
+ })
+ .catch(() => {
+ createToast({message: "Произошла ошибка. Попробуйте еще раз.", type: "error"});
+ })
+ .finally(() => {
+ submit_button.removeClass('disabled');
+ submit_button.prop('disabled', false);
+ });
+});
+
$('#send_email_verification_form').submit(function (e) {
e.preventDefault();
@@ -125,9 +154,11 @@ function displayPost(data) {
'
\n' +
' \n' +
'
\n' +
+ '
' +
' \n' +
data.user.name +
' @'+ data.user.username +'\n' +
+ '
' +
'
·\n' +
'
'+ post_date +'\n' +
' \n' +
@@ -139,8 +170,19 @@ function displayPost(data) {
);
}
-function getPosts() {
- axios.get('/posts/get')
+function getFeed() {
+ axios.get('/posts/feed')
+ .then(data => {
+ data.data.reverse();
+ data.data.forEach(post => {
+ displayPost(post);
+ });
+ })
+ .catch(() => createToast({message: "Произошла ошибка. Попробуйте еще раз.", type: "error"}))
+}
+
+function getPosts(user_id) {
+ axios.get('/posts/'+ user_id +'/get')
.then(data => {
data.data.reverse();
data.data.forEach(post => {
diff --git a/resources/assets/js/editProfile.js b/resources/assets/js/editProfile.js
new file mode 100644
index 0000000..306466d
--- /dev/null
+++ b/resources/assets/js/editProfile.js
@@ -0,0 +1,28 @@
+$('#edit_profile_form').submit(function (e) {
+ e.preventDefault();
+
+ const _self = $(this);
+ const submit_button = _self.find(':submit');
+ submit_button.addClass('disabled');
+ submit_button.prop('disabled', true);
+
+ const url = _self.attr('action');
+ const data = new FormData(this);
+
+ axios.post(url, data)
+ .then(data => {
+ if(data.data.status) {
+ _self.closest('#edit_profile-modal').find('button[data-modal-hide]').trigger('click'); //закрытие модального окна
+ createToast({...data.data});
+ } else {
+ createToast({...data.data});
+ }
+ })
+ .catch(() => {
+ createToast({message: "Произошла ошибка. Попробуйте еще раз.", type: "error"});
+ })
+ .finally(() => {
+ submit_button.removeClass('disabled');
+ submit_button.prop('disabled', false);
+ });
+});
diff --git a/resources/assets/js/posts.js b/resources/assets/js/posts.js
index b31cf31..3ae5830 100644
--- a/resources/assets/js/posts.js
+++ b/resources/assets/js/posts.js
@@ -38,9 +38,11 @@ function displayPost(data) {
'

\n' +
'
\n' +
' \n' +
+ '
' +
' \n' +
data.user.name +
' @'+ data.user.username +'\n' +
+ '
' +
'
·\n' +
'
'+ post_date +'\n' +
' \n' +
@@ -52,8 +54,19 @@ function displayPost(data) {
);
}
-function getPosts() {
- axios.get('/posts/get')
+function getFeed() {
+ axios.get('/posts/feed')
+ .then(data => {
+ data.data.reverse();
+ data.data.forEach(post => {
+ displayPost(post);
+ });
+ })
+ .catch(() => createToast({message: "Произошла ошибка. Попробуйте еще раз.", type: "error"}))
+}
+
+function getPosts(user_id) {
+ axios.get('/posts/'+ user_id +'/get')
.then(data => {
data.data.reverse();
data.data.forEach(post => {
diff --git a/resources/views/includes/_follows-list.blade.php b/resources/views/includes/_follows-list.blade.php
index e22198d..388a97b 100644
--- a/resources/views/includes/_follows-list.blade.php
+++ b/resources/views/includes/_follows-list.blade.php
@@ -1,7 +1,7 @@

-
+
{{$user->name}}
{{'@'.$user->username}}
diff --git a/resources/views/includes/_nav-links.blade.php b/resources/views/includes/_nav-links.blade.php
new file mode 100644
index 0000000..3181c33
--- /dev/null
+++ b/resources/views/includes/_nav-links.blade.php
@@ -0,0 +1,11 @@
+
diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php
index aa0394c..f0367c4 100644
--- a/resources/views/index.blade.php
+++ b/resources/views/index.blade.php
@@ -1,4 +1,4 @@
-@extends('layouts/default')
+@extends('layouts/empty')
@section('title', 'Y. It`s what`s happening / Y')
diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php
index 736ac6f..d53ba60 100644
--- a/resources/views/layouts/default.blade.php
+++ b/resources/views/layouts/default.blade.php
@@ -8,11 +8,44 @@
-
+
-
-
- @yield('content')
+
+
+ @yield('modals')
+
+
+
+ @include('includes/_nav-links')
+
+
+ @yield('content')
+
+
+
+
+
Подписки
+
+ @foreach(auth()->user()->follows->take(5) as $user)
+ @include('includes/_follows-list')
+ @endforeach
+
+
Посмотреть всех
+
+
+
+
diff --git a/resources/views/layouts/empty.blade.php b/resources/views/layouts/empty.blade.php
new file mode 100644
index 0000000..736ac6f
--- /dev/null
+++ b/resources/views/layouts/empty.blade.php
@@ -0,0 +1,24 @@
+
+
+
+ @yield('title')
+
+
+
+
+
+
+
+
+
+
+ @yield('content')
+
+
+
+
+
+
+@yield('scripts')
+
+
diff --git a/resources/views/pages/account/profile.blade.php b/resources/views/pages/account/profile.blade.php
new file mode 100644
index 0000000..912aeb0
--- /dev/null
+++ b/resources/views/pages/account/profile.blade.php
@@ -0,0 +1,137 @@
+@extends('layouts/default')
+
+@section('title', "$user->name (@$user->username)")
+
+@section('modals')
+
+
+
+
+
+
+ Редактирование профиля
+
+
+
+
+

+
+
+

+
+
+
+
+
+
+@endsection
+
+@section('content')
+
+
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/pages/home.blade.php b/resources/views/pages/home.blade.php
index d617486..7949ef7 100644
--- a/resources/views/pages/home.blade.php
+++ b/resources/views/pages/home.blade.php
@@ -3,77 +3,35 @@
@section('title', 'home')
@section('content')
-
-
-
-
-
-
-
Главная
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
Подписки
-
- @foreach(auth()->user()->follows->take(5) as $user)
- @include('includes/_follows-list')
- @endforeach
-
-
Посмотреть всех
-
-
+
+
@endsection
@section('scripts')
-
+
@endsection
diff --git a/routes/web.php b/routes/web.php
index b911c14..198ba18 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -1,7 +1,10 @@
['auth', 'verified']], function () {
Route::group(['prefix' => 'posts', 'as' => 'posts.'], function () {
- Route::get('/get', [PostsController::class, 'get'])->name('get');
+ Route::get('/feed', [PostsController::class, 'feed'])->name('feed');
+ Route::get('/{id}/get', [PostsController::class, 'get'])->name('posts');
Route::post('/create', [PostsController::class, 'create'])->name('create');
});
+
+ Route::group(['prefix' => 'profile', 'as' => 'profile.'], function () {
+ Route::get('/{user:username}', [ProfileController::class, 'render'])->name('profile');
+ Route::post('/{user:username}/follow', [FollowsController::class, 'follow']);
+ Route::post('/edit', [EditProfileController::class, 'edit'])->name('edit');
+ });
});