فهرست منبع

feat: доделал оставшиеся страницы

comp-4 1 ماه پیش
والد
کامیت
7d466d47f4

+ 39 - 0
app/Http/Controllers/AdminController.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\Application;
+use Illuminate\Http\Request;
+
+class AdminController extends Controller
+{
+    public function index(Request $request) {
+        $filterStatus = $request->input('status', 'all');
+        $per_page = $request->input('per_page', '10');
+
+        $query = Application::with('user', 'course')->orderBy('created_at');
+
+        if ($filterStatus !== 'all') {
+            $query->where('status', $filterStatus);
+        }
+
+        $applications = $query->paginate($per_page);
+
+        return view('admin.index', compact('applications', 'filterStatus'));
+    }
+
+    public function updateStatus(Request $request, $id) {
+        $request->validate([
+            'status' => ['required']
+        ]);
+
+        $application = Application::findOrFail($id);
+        $oldStatus = $application->status;
+        $application->status = $request->status;
+        $application->save();
+
+        return redirect()
+        ->back()
+        ->with('success', "Статус заявки '$id' изменен с '$oldStatus' на '$application->status'");
+    }
+}

+ 14 - 0
app/Http/Controllers/ApplicationController.php

@@ -43,4 +43,18 @@ class ApplicationController extends Controller
         ->route('applications.index')
         ->with('success', 'Заявка успешно создана!');
     }
+
+    public function setReview(Request $request, $id) {
+        $request->validate([
+            'review' => ['required'],
+        ]);
+        
+        $application = Application::findOrFail($id);
+        $application->review = $request->review;
+        $application->save();
+
+        return redirect()
+        ->back()
+        ->with('success', "Отзыв на заявку $id успешно оставлен!");
+    }
 }

+ 4 - 2
app/Http/Controllers/Auth/RegisteredUserController.php

@@ -31,11 +31,13 @@ class RegisteredUserController extends Controller
     public function store(Request $request): RedirectResponse
     {
         $request->validate([
-            'login' => ['required', 'string', 'max:255', 'unique:' . User::class],
-            'fio' => ['required', 'string', 'max:255'],
+            'login' => ['required', 'string', 'min:6', 'max:255', 'unique:' . User::class],
+            'fio' => ['required', 'string', 'regex:/^[а-яА-Яёе ]+$/', 'max:255'],
             'phone' => ['required', 'string', 'max:255'],
             'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:' . User::class],
             'password' => ['required', 'confirmed', Rules\Password::defaults()],
+        ], [
+            'fio' => 'В поле ФИО могут быть только символы кириллицы и пробелы'
         ]);
 
         $user = User::create([

+ 25 - 0
app/Http/Middleware/AdminMiddleware.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Symfony\Component\HttpFoundation\Response;
+
+class AdminMiddleware
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
+     */
+    public function handle(Request $request, Closure $next): Response
+    {
+        if (Auth::user()->role !== 'admin') {
+            abort('403', 'Только для админов');
+        }
+
+        return $next($request);
+    }
+}

+ 4 - 1
bootstrap/app.php

@@ -1,5 +1,6 @@
 <?php
 
+use App\Http\Middleware\AdminMiddleware;
 use Illuminate\Foundation\Application;
 use Illuminate\Foundation\Configuration\Exceptions;
 use Illuminate\Foundation\Configuration\Middleware;
@@ -11,7 +12,9 @@ return Application::configure(basePath: dirname(__DIR__))
         health: '/up',
     )
     ->withMiddleware(function (Middleware $middleware): void {
-        //
+        $middleware->alias([
+            'admin' => AdminMiddleware::class,
+        ]);
     })
     ->withExceptions(function (Exceptions $exceptions): void {
         //

+ 80 - 0
resources/views/admin/index.blade.php

@@ -0,0 +1,80 @@
+<x-app-layout>
+    <div class="py-12">
+        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
+            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
+                <div class="p-6 text-gray-900">
+                    <h1 class="text-xl font-medium">Администрирование</h1>
+
+                    @if (session('success'))
+                        <span class="btn btn-success mt-4 mb-4">{{session('success')}}</span>
+                    @endif
+
+                    <div class="flex flex-col gap-2 mt-4">
+                        <h2 class="text-l font-medium">Фильтрация по статусу</h2>
+                        <div class="flex gap-2 mt-2">
+                            <a class="btn {{ $filterStatus === 'all' ? 'btn-success' : '' }}" href="{{ route('admin.index') }}">Все</a>
+                            <a class="btn {{ $filterStatus === 'Новая' ? 'btn-success' : '' }}" href="{{ route('admin.index', ['status' => 'Новая']) }}">Новые</a>
+                            <a class="btn {{ $filterStatus === 'Идет обучение' ? 'btn-success' : '' }}" href="{{ route('admin.index', ['status' => 'Идет обучение']) }}">Идет обучение</a>
+                            <a class="btn {{ $filterStatus === 'Обучение завершено' ? 'btn-success' : '' }}" href="{{ route('admin.index', ['status' => 'Обучение завершено']) }}">Обучение завершено</a>
+                        </div>
+                    </div>
+
+                    <table class="w-full text-center mt-4">
+                        <thead>
+                            <tr>
+                                <th>
+                                    №
+                                </th>
+                                <th>
+                                    Пользователь
+                                </th>
+                                <th>
+                                    Курс
+                                </th>
+                                <th>
+                                    Дата начала обучения
+                                </th>
+                                <th>
+                                    Способ оплаты
+                                </th>
+                                <th>
+                                    Статус
+                                </th>
+                            </tr>
+                            <tr style="height: 15px;"></tr>
+                        </thead>
+                        <tbody>
+                            @foreach ($applications as $app)
+                                <tr style="height: 70px; border-block: 1px solid #6b7280;">
+                                    <td>{{$app->id}}</td>
+                                    <td>{{$app->user->login}}</td>
+                                    <td>{{$app->course->name}}</td>
+                                    <td>{{$app->date_start}}</td>
+                                    <td>{{$app->payment_method}}</td>
+                                    <td>
+                                        <form method="POST" action="{{ route('admin.update-status', $app->id) }}">
+                                            @csrf
+                                            @method('patch')
+
+                                            <select class="border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="status" 
+                                            onchange="this.form.submit()"
+                                            >
+                                                <option value="Новая" {{ $app->status === 'Новая' ? 'selected' : '' }}>Новая</option>
+                                                <option value="Идет обучение" {{ $app->status === 'Идет обучение' ? 'selected' : '' }}>Идет обучение</option>
+                                                <option value="Обучение завершено" {{ $app->status === 'Обучение завершено' ? 'selected' : '' }}>Обучение завершено</option>
+                                            </select>
+                                        </form>
+                                    </td>
+                                </tr>
+                            @endforeach
+                        </tbody>
+                    </table>
+
+                    <div class="mt-4">
+                        {{ $applications->withQueryString()->links() }}
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</x-app-layout>

+ 1 - 1
resources/views/applications/create.blade.php

@@ -29,7 +29,7 @@
 
                        <div class="flex flex-col gap-2 mt-4" style="align-items: start;">
                             <label for="date_start" class="block font-medium text-sm text-gray-700">Желаемая дата обучения</label>
-                            <input name="date_start" type="text" data-date-input placeholder="ДД.ММ.ГГГГ"  class="border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"  />
+                            <input name="date_start" type="text" data-date-input placeholder="ДД-ММ-ГГГГ"  class="border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"  />
                         </div>
 
                         <div class="flex flex-col gap-2 mt-4" style="align-items: start;">

+ 47 - 3
resources/views/applications/index.blade.php

@@ -37,15 +37,59 @@
                                     <td>{{$app->course->name}}</td>
                                     <td>{{$app->date_start}}</td>
                                     <td>{{$app->payment_method}}</td>
-                                    <td>{{$app->status}}</td>
+                                    <td>
+                                        @if ($app->status === 'Новая')
+                                            <span style="background-color: lightblue; color: #ffffff; padding: 5px; border-radius: 6px;">
+                                                {{$app->status}}
+                                            </span>
+                                        @endif
+                                        
+                                        @if ($app->status === 'Идет обучение')
+                                            <span style="background-color: blue; color: #ffffff; padding: 5px; border-radius: 6px;">
+                                                {{$app->status}}
+                                            </span>
+                                        @endif
+
+                                        @if ($app->status === 'Обучение завершено')
+                                            <span style="background-color: purple; color: #ffffff; padding: 5px; border-radius: 6px;">
+                                                {{$app->status}}
+                                            </span>
+                                        @endif
+                                    </td>
                                     
                                     @if ($app->status === 'Обучение завершено')
                                     <td>
-                                        <x-primary-button>Отзыв</x-primary-button>
+                                        <x-primary-button type="button" data-bs-toggle="modal" data-bs-target="#reviewModal{{ $app->id }}">Отзыв</x-primary-button>
 
-                                        <form method="" action="">
+                                        <form method="POST" action="{{ route('applications.set-review', $app->id) }}">
                                             @csrf
 
+                                            <div class="modal fade" id="reviewModal{{ $app->id }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
+                                                <div class="modal-dialog">
+                                                  <div class="modal-content">
+                                                    <div class="modal-header">
+                                                       <h5 class="modal-title" id="exampleModalLabel">Ваш отзыв на курс</h5>
+                                                      <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                                                    </div>
+                                                        <div class="modal-body">
+                                                            <textarea
+                                                            name="review"
+                                                            class="border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
+                                                            style="resize: none; height: 200px; width: 100%;" 
+                                                            {{ empty($app->review) ? '' : 'disabled' }}
+                                                            >{{$app->review}}</textarea>
+                                                        </div>
+                                                        <div class="modal-footer">
+                                                            <x-primary-button type="button"  data-bs-dismiss="modal" style="background-color: #6b7280;">Закрыть</x-primary-button>
+
+                                                            @if (empty($app->review))
+                                                            <x-primary-button type="submit">Отправить</x-primary-button>
+                                                            @endif
+                                                        </div>
+                                                  </div>
+                                                </div>
+                                            </div>
+
                                         </form>
                                     </td>
                                     @endif

+ 2 - 2
resources/views/auth/register.blade.php

@@ -12,7 +12,7 @@
                 <!-- fio -->
         <div class="mt-4">
             <x-input-label for="fio" :value="__('ФИО')" />
-            <x-text-input id="fio" class="block mt-1 w-full" type="text" name="fio" :value="old('fio')" required autofocus autocomplete="fio" />
+            <x-text-input id="fio" class="block mt-1 w-full" type="text" name="fio" :value="old('fio')" required autofocus autocomplete="fio" placeholder="Иванов Иван Иванович" />
             <x-input-error :messages="$errors->get('fio')" class="mt-2" />
         </div>
 
@@ -26,7 +26,7 @@
         <!-- Email Address -->
         <div class="mt-4">
             <x-input-label for="email" :value="__('Email')" />
-            <x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autocomplete="username" />
+            <x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autocomplete="username" placeholder="user@example.com" />
             <x-input-error :messages="$errors->get('email')" class="mt-2" />
         </div>
 

+ 41 - 2
resources/views/dashboard.blade.php

@@ -2,8 +2,47 @@
     <div class="py-12">
         <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
             <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
-                <div class="p-6 text-gray-900">
-                    <h1 class="text-xl font-medium"></h1>
+                <div class="flex p-6 text-gray-900" style="align-items: start; column-gap: 50px;">
+                    <p style="max-width: 500px;">
+                        Вы можете
+                        <a href="{{ route('applications.create')}}" style="color: lightblue;"> 
+                        составить
+                        </a>
+                        заявку на обучение по программе дополнительного профессионального образования, указав наименование курса, 
+                        желаемое время начала обучения, способ оплаты курса.
+                        <br />
+                        <br/>
+                        После подачи заявки она поступает на рассмотрение администратору,
+                        который проверяет корректность введенных данных и может изменить статус
+                        заявки.
+                    </p>
+<div style="max-width: 600px; width: 100%; aspect-ratio: 1;" id="carouselExampleDark" class="carousel carousel-dark slide" data-bs-ride="carousel" data-bs-interval="3000" data-bs-pause="false">
+  <div class="carousel-indicators">
+    <button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
+    <button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="1" aria-label="Slide 2"></button>
+    <button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="2" aria-label="Slide 3"></button>
+  </div>
+  <div class="carousel-inner">
+    <div class="carousel-item active" >
+      <img src="/images/image03.png" class="d-block w-100" alt="..." width="600" height="600" loading="lazy" style="object-fit: cover;">
+    </div>
+    <div class="carousel-item">
+      <img src="/images/image02.jpg" class="d-block w-100" alt="..." width="600" height="600" loading="lazy" style="object-fit: cover;">
+    </div>
+    <div class="carousel-item">
+      <img src="/images/image04.jpg" class="d-block w-100" alt="..." width="600" height="600" loading="lazy" style="object-fit: cover;">
+    </div>
+  </div>
+  <button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleDark" data-bs-slide="prev">
+    <span class="carousel-control-prev-icon" aria-hidden="true"></span>
+    <span class="visually-hidden">Previous</span>
+  </button>
+  <button class="carousel-control-next" type="button" data-bs-target="#carouselExampleDark" data-bs-slide="next">
+    <span class="carousel-control-next-icon" aria-hidden="true"></span>
+    <span class="visually-hidden">Next</span>
+  </button>
+</div>
+
                 </div>
             </div>
         </div>

+ 1 - 1
resources/views/layouts/navigation.blade.php

@@ -26,7 +26,7 @@
                     </x-nav-link>
 
                     @if (Auth::user()->role === 'admin')
-                    <x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
+                    <x-nav-link :href="route('admin.index')" :active="request()->routeIs('admin.index')">
                         {{ __('Администрирование') }}
                     </x-nav-link>
                     @endif

+ 11 - 0
routes/web.php

@@ -1,5 +1,6 @@
 <?php
 
+use App\Http\Controllers\AdminController;
 use App\Http\Controllers\ApplicationController;
 use App\Http\Controllers\ProfileController;
 use Illuminate\Support\Facades\Route;
@@ -19,10 +20,20 @@ Route::middleware('auth')->group(function () {
 
     Route::get('/applications', [ApplicationController::class, 'index'])->name('applications.index');
 
+    Route::post('/applications/{id}', [ApplicationController::class, 'setReview'])->name('applications.set-review');
+
+
     Route::get('/applications/create', [ApplicationController::class, 'create'])->name('applications.create');
 
     Route::post('/applications/store', [ApplicationController::class, 'store'])->name('applications.store');
 
 });
 
+
+Route::middleware(['auth', 'admin'])->group(function () {
+    Route::get('/admin', [AdminController::class, 'index'])->name('admin.index');
+
+    Route::patch('/admin/{id}', [AdminController::class, 'updateStatus'])->name('admin.update-status');
+});
+
 require __DIR__.'/auth.php';