Compare commits

...

6 Commits

Author SHA1 Message Date
ROMANGOLIENKO d2b1499659 Merge remote-tracking branch 'origin/feature/visually-impaired-mode' into feature/visually-impaired-mode
# Conflicts:
#	resources/views/new-design/bakalavr-special.blade.php
2024-04-24 15:28:37 +03:00
ROMANGOLIENKO 197187091c adding feedback 2024-04-24 15:27:07 +03:00
ROMANGOLIENKO ba8d590a33 visually-impaired mode fix 2024-04-24 13:20:04 +03:00
ROMANGOLIENKO 2d231676c4 fixing green circle button 2024-04-24 13:20:04 +03:00
aslan 2e32908e45 fix CI 2024-04-24 09:35:19 +03:00
aslan a1ccaba32a add feedback and status resources 2024-04-23 14:23:21 +03:00
30 changed files with 964 additions and 100 deletions

View File

@ -0,0 +1,52 @@
<?php
namespace App\Http\Controllers\admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\admin\StoreFeedbackRequest;
use App\Http\Requests\admin\UpdateFeedbackRequest;
use App\Models\Feedback;
use App\Models\FeedbackStatus;
class FeedbackController extends Controller
{
public function index()
{
$feedbacks = Feedback::all();
return view('admin.feedback.index', compact('feedbacks'));
}
public function store(StoreFeedbackRequest $request)
{
$validated = $request->validated();
$feedback = new Feedback();
$feedback->contact = $validated['contact'];
$feedback->text = $validated['text'];
$feedback->status_id = 1;
$feedback->save();
flash('Ваше сообщение отправлено!')->success();
return back();
}
public function edit(Feedback $feedback)
{
$feedbackStatuses = FeedbackStatus::pluck('name', 'id');
return view('admin.feedback.edit', compact('feedback', 'feedbackStatuses'));
}
public function update(UpdateFeedbackRequest $request, Feedback $feedback)
{
$validated = $request->validated();
$feedback->contact = $validated['contact'];
$feedback->text = $validated['text'];
$feedback->status_id = $validated['status_id'];
$feedback->save();
return redirect()->route('feedback.index');
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Http\Controllers\admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\admin\StoreFeedbackStatusRequest;
use App\Http\Requests\admin\UpdateFeedbackStatusRequest;
use App\Models\FeedbackStatus;
class FeedbackStatusController extends Controller
{
public function index()
{
$feedbackStatuses = FeedbackStatus::all();
return view('admin.feedback_statuses.index', compact('feedbackStatuses'));
}
public function create()
{
return view('admin.feedback_statuses.create');
}
public function store(StoreFeedbackStatusRequest $request)
{
$validated = $request->validated();
$feedbackStatus = new FeedbackStatus();
$feedbackStatus->name = $validated['name'];
$feedbackStatus->save();
return redirect()->route('feedback_statuses.index');
}
public function edit(FeedbackStatus $feedbackStatus)
{
return view('admin.feedback_statuses.edit', compact('feedbackStatus'));
}
public function update(UpdateFeedbackStatusRequest $request, FeedbackStatus $feedbackStatus)
{
$validated = $request->validated();
$feedbackStatus->name = $validated['name'];
$feedbackStatus->save();
return redirect()->route('feedback_statuses.index');
}
public function destroy(FeedbackStatus $feedbackStatus)
{
if ($feedbackStatus->feedbacks()->exists()) {
return back();
}
$feedbackStatus->delete();
return redirect()->route('feedback_statuses.index');
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Requests\admin;
use Illuminate\Foundation\Http\FormRequest;
class StoreFeedbackRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'contact' => 'required|string|max:255',
'text' => 'string|nullable',
];
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Http\Requests\admin;
use Illuminate\Foundation\Http\FormRequest;
class StoreFeedbackStatusRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => 'required|string|max:255',
];
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Requests\admin;
use Illuminate\Foundation\Http\FormRequest;
class UpdateFeedbackRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'contact' => 'required|string|max:255',
'text' => 'string|nullable',
'status_id' => 'required|numeric|exists:feedback_statuses,id',
];
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Http\Requests\admin;
use Illuminate\Foundation\Http\FormRequest;
class UpdateFeedbackStatusRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => 'required|string|max:255',
];
}
}

25
app/Models/Feedback.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Feedback extends Model
{
use HasFactory;
protected $fillable = [
'id',
'contact',
'text',
'stats_id',
'created_at',
];
public function status(): BelongsTo
{
return $this->belongsTo(FeedbackStatus::class);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class FeedbackStatus extends Model
{
use HasFactory;
protected $fillable = [
'id',
'name',
'created_at',
];
public function feedbacks(): HasMany
{
return $this->hasMany('App\Models\Feedback', 'status_id');
}
}

View File

@ -13,6 +13,7 @@
"fakerphp/faker": "^1.23.1",
"guzzlehttp/guzzle": "^7.8.1",
"imangazaliev/didom": "^2.0.1",
"laracasts/flash": "^3.2",
"laravel/framework": "^10.48.2",
"laravel/sanctum": "^3.3.3",
"laravel/tinker": "^2.9.0",

56
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7430aa832d42dad89f7314c9c96e0023",
"content-hash": "cdd9e5c44654ea2c37c37d36bc80e259",
"packages": [
{
"name": "brick/math",
@ -1302,6 +1302,60 @@
},
"time": "2023-03-05T03:23:48+00:00"
},
{
"name": "laracasts/flash",
"version": "3.2.3",
"source": {
"type": "git",
"url": "https://github.com/laracasts/flash.git",
"reference": "c2c4be1132f1bec3a689e84417a1c5787e6c71fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laracasts/flash/zipball/c2c4be1132f1bec3a689e84417a1c5787e6c71fd",
"reference": "c2c4be1132f1bec3a689e84417a1c5787e6c71fd",
"shasum": ""
},
"require": {
"illuminate/support": "~5.0|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"php": ">=5.4.0"
},
"require-dev": {
"mockery/mockery": "dev-master",
"phpunit/phpunit": "^6.1|^9.5.10|^10.5"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laracasts\\Flash\\FlashServiceProvider"
],
"aliases": {
"Flash": "Laracasts\\Flash\\Flash"
}
}
},
"autoload": {
"files": [
"src/Laracasts/Flash/functions.php"
],
"psr-0": {
"Laracasts\\Flash": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jeffrey Way",
"email": "jeffrey@laracasts.com"
}
],
"description": "Easy flash notifications",
"time": "2024-03-03T16:51:25+00:00"
},
{
"name": "laravel/framework",
"version": "v10.48.2",

View File

@ -0,0 +1,18 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class FeedbackFactory extends Factory
{
public function definition(): array
{
return [
'contact' => fake()->email(),
'text' => fake()->text(),
'status_id' => 1,
];
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class FeedbackStatusFactory extends Factory
{
public function definition(): array
{
return [
'name' => fake()->name(),
];
}
}

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('feedback_statuses', function (Blueprint $table) {
$table->id();
$table->string('name', 255);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('feedback_statuses');
}
};

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('feedback', function (Blueprint $table) {
$table->id();
$table->string('contact', 255);
$table->text('text');
$table->foreignId('status_id')->constrained('feedback_statuses');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('feedback');
}
};

View File

@ -10,31 +10,36 @@ class DatabaseSeeder extends Seeder
{
public function run(): void
{
User::factory()->create([
'name' => config('app.admin_name'),
'email' => config('app.admin_email'),
'password' => 123456
]);
// User::factory()->create([
// 'name' => config('app.admin_name'),
// 'email' => config('app.admin_email'),
// 'password' => 123456
// ]);
// User::factory(10)->create();
$this->call([
EducationalInstitutionSeeder::class,
FacultySeeder::class,
DepartmentSeeder::class,
EducationLevelSeeder::class,
EducationFormSeeder::class,
ExaminationTypeSeeder::class,
SubjectSeeder::class,
SubjectTypeSeeder::class,
DirectionSeeder::class,
EntranceExaminationSeeder::class,
DirectionProfileSeeder::class,
]);
// $this->call([
// EducationalInstitutionSeeder::class,
// FacultySeeder::class,
// DepartmentSeeder::class,
// EducationLevelSeeder::class,
// EducationFormSeeder::class,
// ExaminationTypeSeeder::class,
// SubjectSeeder::class,
// SubjectTypeSeeder::class,
// DirectionSeeder::class,
// EntranceExaminationSeeder::class,
// DirectionProfileSeeder::class,
// ]);
// $this->call([
// AdmissionSeeder::class,
// DocumentSeeder::class,
// ]);
$this->call([
AdmissionSeeder::class,
DocumentSeeder::class,
FeedbackStatusSeeder::class,
FeedbackSeeder::class,
]);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class FeedbackSeeder extends Seeder
{
public function run(): void
{
DB::table('feedback')->insert([
[
'contact' => '79112223344',
'text' => 'Мое новое обращение',
'status_id' => 1,
],
[
'contact' => 'example@example.com',
'text' => 'Мое новое обращение',
'status_id' => 1,
],
]);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class FeedbackStatusSeeder extends Seeder
{
public function run(): void
{
DB::table('feedback_statuses')->insert([
[
'name' => 'создано',
],
[
'name' => 'в работе',
],
]);
}
}

View File

@ -0,0 +1,56 @@
@php use App\Helpers\PositionHelper; @endphp
@extends('layouts.admin_layout')
@section('content')
@auth()
<div class="row">
<div class="col">
<h1 class="">Изменить Статус обращения</h1>
{{ Form::open(['url' => route('feedback.update', $feedback), 'method' => 'PATCH', 'files'=>'true', 'class' => 'needs-validation', 'novalidate']) }}
<div class="col">
<div class="mt-3">
{{ Form::label('contact', 'Контакт', ['data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.feedback.contact')]) }}
</div>
<div class="mt-1">
{{ Form::text('contact', $feedback->contact, ['class' => 'form-control', 'data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.feedback.contact'), 'required', 'readonly' => ""]) }}
</div>
<div class="text-danger">
@if ($errors->any())
{{ $errors->first('contact') }}
@endif
</div>
<div class="mt-3">
{{ Form::label('text', 'Текст', ['data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.feedback.text')]) }}
</div>
<div class="mt-1">
{{ Form::textarea('text', $feedback->text, ['class' => 'form-control', 'data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.feedback.text'), 'required', 'readonly' => ""]) }}
</div>
<div class="text-danger">
@if ($errors->any())
{{ $errors->first('text') }}
@endif
</div>
<div class="mt-3">
{{ Form::label('status_id', 'Статус обращения', ['data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.feedback.status_id')]) }}
</div>
<div class="mt-1">
{{ Form::select('status_id', $feedbackStatuses, $feedback->status_id, ['class' => 'form-control', 'data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.feedback.status_id'), 'required']) }}
</div>
<div class="text-danger">
@if ($errors->any())
{{ $errors->first('text') }}
@endif
</div>
<div class="mt-3">
{{ Form::submit('Изменить', ['class' => 'btn btn-primary']) }}
</div>
</div>
{{ Form::close() }}
</div>
</div>
@endauth
@include('layouts.bootstrap_validation')
@endsection

View File

@ -0,0 +1,35 @@
@extends('layouts.admin_layout')
@section('content')
<div class="container">
<h2>Обр. связь</h2>
<br>
<br>
<table class="table">
<thead class="border-b-2 border-solid border-black text-left" style="text-align: left">
<tr>
<th scope="col">Контакт</th>
<th scope="col">Текст</th>
<th scope="col">Статус</th>
<th scope="col">Создано</th>
<th scope="col">Действия</th>
</tr>
</thead>
<tbody>
@foreach($feedbacks as $feedback)
<tr class="">
<td>{{ $feedback->contact }}</a></td>
<td>{{ $feedback->text }}</a></td>
<td>{{ $feedback->status->name }}</a></td>
<td>{{ $feedback->created_at }}</a></td>
<td><a href="{{ route("feedback.edit", $feedback) }}"
class="btn btn-secondary">редактировать</a>
</td>
</tr>
@endforeach
</tbody>
</table>
<br>
<br>
</div>
@endsection

View File

@ -0,0 +1,36 @@
@php use App\Helpers\PositionHelper; @endphp
@extends('layouts.admin_layout')
@section('content')
@auth()
<div class="row">
<div class="col">
<h1 class=""> Создать Статус</h1>
{{ Form::open(['url' => route('feedback_statuses.store'), 'method' => 'POST', 'files'=>'true', 'class' => 'needs-validation', 'novalidate']) }}
<div class="col">
<div class="mt-3">
{{ Form::label('name', 'Название', ['data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.news.name')]) }}
<span class="text-danger">*</span>
</div>
<div class="mt-1">
{{ Form::text('name', '', ['class' => 'form-control', 'data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.news.name'), 'required']) }}
<div class="invalid-feedback">
Поле "Название" обязательно!
</div>
</div>
<div class="text-danger">
@if ($errors->any())
{{ $errors->first('name') }}
@endif
</div>
<div class="mt-3">
{{ Form::submit('Создать', ['class' => 'btn btn-primary']) }}
</div>
</div>
{{ Form::close() }}
</div>
</div>
@endauth
@include('layouts.bootstrap_validation')
@endsection

View File

@ -0,0 +1,36 @@
@php use App\Helpers\PositionHelper; @endphp
@extends('layouts.admin_layout')
@section('content')
@auth()
<div class="row">
<div class="col">
<h1 class="">Изменить Новость</h1>
{{ Form::open(['url' => route('feedback_statuses.update', $feedbackStatus), 'method' => 'PATCH', 'files'=>'true', 'class' => 'needs-validation', 'novalidate']) }}
<div class="col">
<div class="mt-3">
{{ Form::label('name', 'Название', ['data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.news.name')]) }}
<span class="text-danger">*</span>
</div>
<div class="mt-1">
{{ Form::text('name', $feedbackStatus->name, ['class' => 'form-control', 'data-bs-toggle' => "tooltip", 'data-bs-title' => __('tooltips.news.name'), 'required']) }}
<div class="invalid-feedback">
Поле "Название" обязательно!
</div>
</div>
<div class="text-danger">
@if ($errors->any())
{{ $errors->first('name') }}
@endif
</div>
<div class="mt-3">
{{ Form::submit('Изменить', ['class' => 'btn btn-primary']) }}
</div>
</div>
{{ Form::close() }}
</div>
</div>
@endauth
@include('layouts.bootstrap_validation')
@endsection

View File

@ -0,0 +1,36 @@
@extends('layouts.admin_layout')
@section('content')
<div class="container">
<h2>Статусы</h2>
<br>
<a href="{{ route('feedback_statuses.create') }}" class="btn btn-primary">Создать Статус</a>
<br>
<br>
<table class="table">
<thead class="border-b-2 border-solid border-black text-left" style="text-align: left">
<tr>
<th scope="col">Название</th>
<th scope="col">Действия</th>
</tr>
</thead>
<tbody>
@foreach($feedbackStatuses as $status)
<tr class="">
<td>{{ $status->name }}</a></td>
<td><a href="{{ route("feedback_statuses.edit", $status) }}"
class="btn btn-secondary">редактировать</a>
<a rel="nofollow" data-method="delete" data-confirm="Вы действительно хотите удалить?"
href="{{ route('feedback_statuses.destroy', $status) }}"
class="btn btn-danger">
удалить
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
<br>
<br>
</div>
@endsection

View File

@ -3,9 +3,13 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="expires" content="0" />
@php
// phpcs:disable
echo '<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate" />';
echo '<meta http-equiv="pragma" content="no-cache" />';
echo '<meta http-equiv="expires" content="0" />';
// phpcs:enable
@endphp
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="csrf-param" content="_token"/>
@ -49,6 +53,7 @@
<aside class="col-2">
<ul class="list-group ">
<li class="list-group-item {{ request()->is('admin/news*') ? 'active' : '' }}"><a class="{{ request()->is('admin/news*') ? 'link-light' : '' }}" href="{{ route('news.index') }}">Новости</a></li>
<li class="list-group-item {{ request()->is('admin/feedback*') && !request()->is('admin/feedback_statuses*') ? 'active' : '' }}"><a class="{{ request()->is('admin/feedback*') && !request()->is('admin/feedback_statuses*') ? 'link-light' : '' }}" href="{{ route('feedback.index') }}">Обратная связь</a></li>
<li class="list-group-item {{ request()->is('admin/documents*') ? 'active' : '' }}"><a class="{{ request()->is('admin/documents*') ? 'link-light' : '' }}" href="{{ route('documents.index') }}">Документы</a></li>
<li class="list-group-item {{ request()->is('admin/admissions*') ? 'active' : '' }}"><a class="{{ request()->is('admin/admissions*') ? 'link-light' : '' }}" href="{{ route('admissions.index') }}">Экран Приема</a></li>
<li class="list-group-item {{ request()->is('admin/directions*') ? 'active' : '' }}"><a class="{{ request()->is('admin/directions*') ? 'link-light' : '' }}" href="{{ route('directions.index') }}">Направления</a></li>
@ -70,6 +75,8 @@
<li class="list-group-item {{ request()->is('admin/subjects*') ? 'active' : '' }}"><a class="{{ request()->is('admin/subjects*') ? 'link-light' : '' }}" href="{{ route('subjects.index') }}">Предметы</a></li>
<li class="list-group-item {{ request()->is('admin/subject_types*') ? 'active' : '' }}"><a class="{{ request()->is('admin/subject_types*') ? 'link-light' : '' }}" href="{{ route('subject_types.index') }}">Типы Предметов</a></li>
<li class="list-group-item {{ request()->is('admin/direction_profiles*') ? 'active' : '' }}"><a class="{{ request()->is('admin/direction_profiles*') ? 'link-light' : '' }}" href="{{ route('direction_profiles.index') }}">Профили подготовки</a></li>
<li class="list-group-item"></li>
<li class="list-group-item {{ request()->is('admin/feedback_statuses*') ? 'active' : '' }}"><a class="{{ request()->is('admin/feedback_statuses*') ? 'link-light' : '' }}" href="{{ route('feedback_statuses.index') }}">Статусы Обр. связи</a></li>
</ul>
</aside>
<main class="col-10">@yield('content')</main>

View File

@ -23,6 +23,8 @@
@yield('extra_styles')
<!-- css end here-->
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="csrf-param" content="_token"/>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

View File

@ -74,11 +74,15 @@
integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous">
</script>
<body>
<header>
<div class="container-fluid position-relative fon1_blok visually_impaired_mode ">
<div class="mt-4 position-absolute" style="margin-left:11%;">@include('flash::message')</div>
<div class=" d-none d-xl-flex justify-content-end align-items-end position-absolute float-end z-1 "
style="height: 100%; ">
<div style="width: 60%">
@ -766,6 +770,8 @@
<div class="col-11">
<p class=" fs-4"> 385000, Республика Адыгея, г. Майкоп, ул. Первомайская, д. 191 </p>
</div>
<div class="col-11">
<a href="#"><img width="30px" height="30px" src="{{ URL::to('img/front-page/vid.png') }}" alt="vid"></a>
<a href="#"><img width="30px" height="30px" src="{{ URL::to('img/front-page/vk.png') }}" alt="vid"></a>
@ -781,6 +787,45 @@
</div>
</div>
</div>
<div class="row ms-4">
<!-- Button trigger modal -->
<div class="col-11">
<a class=" fs-4 btn btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#feedbackModal"> Обратная связь </a>
</div>
<!-- Modal -->
<div class="modal fade" id="feedbackModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="POST" action="{{route('feedback.store')}}">
@csrf
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Ваши контакты</label>
<input type="text" class="form-control" name="contact" id="contact" aria-describedby="contactHelp" >
<div id="contactHelp" class="form-text"> Ваш телефон или электронная почта</div>
</div>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label"> Ваше сообщение</label>
<textarea type="text" class="form-control" name="text" id="text"> </textarea>
</div>
<button type="submit" class="btn btn-primary">Отправить</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"> Закрыть </button>
</div>
</div>
</div>
</div>
</div>
</div>
@ -792,4 +837,9 @@
</body>
<script>
$('div.alert').not('.alert-important').delay(15000).fadeOut(350);
</script>
@endsection

View File

@ -13,6 +13,8 @@ use App\Http\Controllers\admin\Catalog\DirectionController;
use App\Http\Controllers\admin\Catalog\EducationalInstitutionController;
use App\Http\Controllers\admin\Catalog\FacultyController;
use App\Http\Controllers\admin\DocumentController;
use App\Http\Controllers\admin\FeedbackController;
use App\Http\Controllers\admin\FeedbackStatusController;
use App\Http\Controllers\admin\UserController;
use App\Http\Controllers\NewsController;
use Rap2hpoutre\LaravelLogViewer\LogViewerController;
@ -68,6 +70,9 @@ Route::middleware(['auth', 'verified'])->prefix('admin')->group(function () {
Route::resource('/direction_profiles', DirectionProfileController::class)
->scoped(['direction_profile' => 'slug']);
Route::resource('/feedback', FeedbackController::class)->only(['index', 'edit', 'update']);
Route::resource('/feedback_statuses', FeedbackStatusController::class);
Route::resources([
'/documents' => DocumentController::class,
'/users' => UserController::class,

View File

@ -1,5 +1,6 @@
<?php
use App\Http\Controllers\admin\FeedbackController;
use App\Http\Controllers\admin\PageController;
use App\Models\Faculty;
use Illuminate\Support\Facades\Route;
@ -18,82 +19,81 @@ Route::get('/inostran', [PageController::class, 'inostran'])->name('inostran');
Route::get('/magistr', [PageController::class, 'magistr'])->name('magistr');
Route::post('/feedback', [FeedbackController::class, 'store'])->name('feedback.store');
Route::get('/course', function () {
return view('menu.course');
})->name('course');
Route::get('/applicant', function () {
return view('menu.abitur');
})->name('abitur');
Route::get('/for-foreign-applicants', function () {
return view('menu.inostrannym-abiturientam');
})->name('inostrannym-abiturientam');
Route::get('/paid_edu', function () {
return view('menu.paid_edu');
})->name('paid_edu');
Route::get('/olympiads-for-schoolchildren', function () {
return view('menu.olimpiady-dlya-shkolnikov');
})->name('olimpiady-dlya-shkolnikov');
Route::get('/training courses', function () {
return view('menu.podgotovitelnye-kursy');
})->name('podgotovitelnye-kursy');
//Route::get('/course', function () {
// return view('menu.course');
//})->name('course');
//
//Route::get('/applicant', function () {
// return view('menu.abitur');
//})->name('abitur');
//
//Route::get('/for-foreign-applicants', function () {
// return view('menu.inostrannym-abiturientam');
//})->name('inostrannym-abiturientam');
//
//Route::get('/paid_edu', function () {
// return view('menu.paid_edu');
//})->name('paid_edu');
//
//Route::get('/olympiads-for-schoolchildren', function () {
// return view('menu.olimpiady-dlya-shkolnikov');
//})->name('olimpiady-dlya-shkolnikov');
//
//Route::get('/training courses', function () {
// return view('menu.podgotovitelnye-kursy');
//})->name('podgotovitelnye-kursy');
Route::get('/reception-screens', [PageController::class, 'index'])->name('reception-screens');
Route::get('/web-consultations', function () {
return view('menu.abitur.web-consultations');
})->name('web-consultations');
Route::get('/specialty-magistracy', function () {
return view('menu.abitur.spetsialitet-magistratura');
})->name('spetsialitet-magistratura');
Route::get('/college', function () {
return view('menu.abitur.kolledzh');
})->name('kolledzh');
Route::get('/paid-educational-services', function () {
return view('menu.abitur.platnye-obrazovatelnye-uslugi');
})->name('platnye-obrazovatelnye-uslugi');
Route::get('/residency', function () {
return view('menu.abitur.ordinatura');
})->name('ordinatura');
Route::get('/traineeship', function () {
return view('menu.abitur.aspirantura');
})->name('aspirantura');
Route::get('/video-materials-for-applicants', function () {
return view('menu.abitur.videomaterialy-dlya-postupayushchikh');
})->name('videomaterialy-dlya-postupayushchikh');
Route::get('/international-activity', function () {
return view('menu.inostrannym-abiturientam.mezhdunarodnaya-deyatelnost');
})->name('mezhdunarodnaya-deyatelnost');
Route::get('/general-information', function () {
return view('menu.inostrannym-abiturientam.obshchie-svedeniya');
})->name('obshchie-svedeniya');
Route::get('/departments-list', function () {
return view('menu.inostrannym-abiturientam.kafedry');
})->name('kafedry');
Route::get('/international-education-center', function () {
return view('menu.inostrannym-abiturientam.tsentr-mezhdunarodnogo-obrazovaniya');
})->name('tsentr-mezhdunarodnogo-obrazovaniya');
Route::get('/academic-mobility-and-international-cooperation', function () {
return view('menu.inostrannym-abiturientam.akademicheskaya-mobilnost-i-mezhdunarodnoe-sotrudnichestvo');
})->name('akademicheskaya-mobilnost-i-mezhdunarodnoe-sotrudnichestvo');
//Route::get('/web-consultations', function () {
// return view('menu.abitur.web-consultations');
//})->name('web-consultations');
//
//Route::get('/specialty-magistracy', function () {
// return view('menu.abitur.spetsialitet-magistratura');
//})->name('spetsialitet-magistratura');
//
//Route::get('/college', function () {
// return view('menu.abitur.kolledzh');
//})->name('kolledzh');
//
//Route::get('/paid-educational-services', function () {
// return view('menu.abitur.platnye-obrazovatelnye-uslugi');
//})->name('platnye-obrazovatelnye-uslugi');
//
//Route::get('/residency', function () {
// return view('menu.abitur.ordinatura');
//})->name('ordinatura');
//
//Route::get('/traineeship', function () {
// return view('menu.abitur.aspirantura');
//})->name('aspirantura');
//
//Route::get('/video-materials-for-applicants', function () {
// return view('menu.abitur.videomaterialy-dlya-postupayushchikh');
//})->name('videomaterialy-dlya-postupayushchikh');
//
//Route::get('/international-activity', function () {
// return view('menu.inostrannym-abiturientam.mezhdunarodnaya-deyatelnost');
//})->name('mezhdunarodnaya-deyatelnost');
//
//Route::get('/general-information', function () {
// return view('menu.inostrannym-abiturientam.obshchie-svedeniya');
//})->name('obshchie-svedeniya');
//
//Route::get('/departments-list', function () {
// return view('menu.inostrannym-abiturientam.kafedry');
//})->name('kafedry');
//
//Route::get('/international-education-center', function () {
// return view('menu.inostrannym-abiturientam.tsentr-mezhdunarodnogo-obrazovaniya');
//})->name('tsentr-mezhdunarodnogo-obrazovaniya');
//
//Route::get('/academic-mobility-and-international-cooperation', function () {
// return view('menu.inostrannym-abiturientam.akademicheskaya-mobilnost-i-mezhdunarodnoe-sotrudnichestvo');
//})->name('akademicheskaya-mobilnost-i-mezhdunarodnoe-sotrudnichestvo');

View File

@ -0,0 +1,92 @@
<?php
namespace Tests\Feature\admin;
use App\Models\FeedbackStatus;
use App\Models\News;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class FeedbackStatusTest extends TestCase
{
private User $user;
private FeedbackStatus $status;
private array $data;
protected function setUp(): void
{
parent::setUp();
$this->status = FeedbackStatus::factory()->create();
$this->data = FeedbackStatus::factory()->make()->only([
'name',
]);
$this->user = User::factory()->create([
'name' => 'admin',
'email' => 'test@example.com',
'password' => 123456
]);
}
public function testIndexFeedbackStatusPage(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->get(route('feedback_statuses.index'));
$response->assertOk();
}
public function testCreateFeedbackStatusPage(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->get(route('feedback_statuses.create'));
$response->assertOk();
}
public function testStoreFeedbackStatus(): void
{
$file = UploadedFile::fake()->create('fake.jpg', 100);
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->post(route('feedback_statuses.store'), $this->data);
$response->assertRedirect(route('feedback_statuses.index'));
$this->assertDatabaseHas('feedback_statuses', $this->data);
}
public function testEditFeedbackStatusPage(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->get(route('feedback_statuses.edit', $this->status));
$response->assertOk();
}
public function testUpdateFeedbackStatus(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->patch(route('feedback_statuses.update', $this->status), $this->data);
$response->assertRedirect(route('feedback_statuses.index'));
$this->assertDatabaseHas('feedback_statuses', $this->data);
}
public function testDestroyFeedbackStatus(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->delete(route('feedback_statuses.destroy', $this->status));
$response->assertRedirect(route('feedback_statuses.index'));
$this->assertDatabaseMissing('feedback_statuses', $this->status->toArray());
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace Tests\Feature\admin;
use App\Models\Feedback;
use App\Models\FeedbackStatus;
use App\Models\News;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Tests\TestCase;
class FeedbackTest extends TestCase
{
private User $user;
private Feedback $feedback;
private array $data;
protected function setUp(): void
{
parent::setUp();
$this->feedbackStatus = FeedbackStatus::factory()->create();
$this->feedback = Feedback::factory()->create();
$this->data = Feedback::factory()->make()->only([
'contact',
'text',
'status_id',
]);
$this->user = User::factory()->create([
'name' => 'admin',
'email' => 'test@example.com',
'password' => 123456
]);
}
public function testIndexFeedbacksPage(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->get(route('feedback.index'));
$response->assertOk();
}
public function testStoreFeedback(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->post(route('feedback.store'), $this->data);
$response->assertJson(["result" => "success"]);
$this->assertDatabaseHas('feedback', $this->data);
}
public function testEditFeedbackPage(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->get(route('feedback.edit', $this->feedback));
$response->assertOk();
}
public function testUpdateFeedback(): void
{
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->patch(route('feedback.update', $this->feedback), $this->data);
$response->assertRedirect(route('feedback.index'));
$this->assertDatabaseHas('feedback', $this->data);
}
}

View File

@ -1,10 +1,7 @@
<?php
namespace Tests\Feature\admin\catalog;
namespace Tests\Feature\admin;
use App\Models\Department;
use App\Models\EducationalInstitution;
use App\Models\Faculty;
use App\Models\News;
use App\Models\User;
use Illuminate\Http\UploadedFile;