Selaa lähdekoodia

Notes, clients, fixes etc

Alexander Musikhin 11 kuukautta sitten
vanhempi
sitoutus
820c053e69

+ 1 - 1
app/Helpers/roles.php

@@ -20,7 +20,7 @@ if(!function_exists('hasRole')){
         if(!$user) $user = auth()->user();
 
         $roles = explode(',', $roles);
-        return (in_array($user->role, $roles));
+        return ($user && in_array($user->role, $roles));
     }
 }
 

+ 50 - 0
app/Http/Controllers/ClientController.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\Client;
+use Illuminate\Http\Request;
+
+class ClientController extends Controller
+{
+    public function index()
+    {
+        return Client::all();
+    }
+
+    public function store(Request $request)
+    {
+        $request->validate([
+            'name' => ['required'],
+            'phone' => ['required'],
+            'email' => ['required', 'email', 'max:254'],
+        ]);
+
+        return Client::create($request->validated());
+    }
+
+    public function show(Client $client)
+    {
+        return $client;
+    }
+
+    public function update(Request $request, Client $client)
+    {
+        $request->validate([
+            'name' => ['required'],
+            'phone' => ['required'],
+            'email' => ['required', 'email', 'max:254'],
+        ]);
+
+        $client->update($request->validated());
+
+        return $client;
+    }
+
+    public function destroy(Client $client)
+    {
+        $client->delete();
+
+        return response()->json();
+    }
+}

+ 28 - 0
app/Http/Controllers/UserController.php

@@ -3,8 +3,10 @@
 namespace App\Http\Controllers;
 
 use App\Http\Requests\DeleteUser;
+use App\Http\Requests\StoreProfile;
 use App\Http\Requests\StoreUser;
 use App\Models\User;
+use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Hash;
 
 class UserController extends Controller
@@ -78,4 +80,30 @@ class UserController extends Controller
             return redirect()->route('user.index')->with(['success' => 'Пользователь ' . $user->name . ' удалён!']);
         }
     }
+
+    public function profile(Request $request)
+    {
+        $this->data['current_menu'] = 'profile';
+        $this->data['user'] = $request->user();
+        return view('users.profile', $this->data);
+    }
+
+    public function storeProfile(StoreProfile $request)
+    {
+        $data = $request->validated();
+
+        unset($data['current_password'], $data['password']);
+        if(
+            isset($request->current_password)
+            && isset($request->password)
+            && (Hash::check($request->current_password, $request->user()->password))) {
+            $data['password'] = Hash::make($request->password);
+        }
+
+        User::query()->where('id', '=', $request->user()->id)->update($data);
+
+        return redirect()->route('user.profile')->with(['success' => 'Профиль обновлён!']);
+    }
+
+
 }

+ 38 - 0
app/Http/Requests/StoreProfile.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class StoreProfile extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     */
+    public function authorize(): bool
+    {
+        return auth()->check();
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
+     */
+    public function rules(): array
+    {
+        return [
+            'name'              => 'string|required|min:2',
+            'current_password'  => 'nullable',
+            'password'          => 'nullable|min:8|confirmed',
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'password' => 'Пароль должен быть не менее 8 символов!',
+            'name'  => 'Имя обязательно и не менее 2 символов!',
+        ];
+    }
+}

+ 1 - 1
app/Http/Requests/StoreUser.php

@@ -31,7 +31,7 @@ class StoreUser extends FormRequest
         ];
     }
 
-    public function messages()
+    public function messages(): array
     {
         return [
             'name'      => 'Поле обязательно для заполнения и должно быть не менее 2 символов!',

+ 17 - 0
app/Models/Client.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\SoftDeletes;
+
+class Client extends Model
+{
+    use SoftDeletes;
+
+    protected $fillable = [
+        'name',
+        'phone',
+        'email',
+    ];
+}

+ 13 - 4
database/migrations/2024_12_19_143844_create_products_table.php

@@ -13,14 +13,23 @@ return new class extends Migration
     {
         Schema::create('products', function (Blueprint $table) {
             $table->id();
+
             $table->unsignedInteger('year');
-            $table->string('name');
+            $table->string('name_tz');
+            $table->string('type_tz');
             $table->string('nomenclature_number');
-            $table->string('type');
-            $table->string('article')->unique();
             $table->string('sizes');
+            $table->string('manufacturer');
             $table->string('unit');
-            // other params
+            $table->string('type');
+            $table->string('price_status');
+            $table->unsignedBigInteger('product_price');
+            $table->unsignedBigInteger('installation_price');
+            $table->unsignedBigInteger('service_price');
+            $table->unsignedBigInteger('total_price');
+            $table->text('manufacturer_name');
+            $table->string('article');
+            $table->text('note');
             $table->softDeletes();
             $table->timestamps();
         });

+ 28 - 0
database/migrations/2024_12_19_161249_create_clients_table.php

@@ -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 {
+    public function up(): void
+    {
+        Schema::create('clients', function (Blueprint $table) {
+            $table->id();
+            $table->string('name');
+            $table->string('phone');
+            $table->string('email');
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('clients');
+    }
+};

+ 9 - 2
database/seeders/DatabaseSeeder.php

@@ -2,9 +2,7 @@
 
 namespace Database\Seeders;
 
-use App\Models\Role;
 use App\Models\User;
-// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
 use Illuminate\Database\Seeder;
 use Illuminate\Support\Facades\Hash;
 
@@ -15,6 +13,15 @@ class DatabaseSeeder extends Seeder
      */
     public function run(): void
     {
+        if(User::query()->get()->count() < 1) {
+            User::create([
+                'name'  => 'Администратор СМЕНИ ПАРОЛЬ!',
+                'email' => 'admin@admin.com',
+                'role'  => 'admin',
+                'password' => Hash::make('admin')
+            ]);
+        }
+
         $this->call(DistrictSeeder::class);
         $this->call(AreaSeeder::class);
     }

+ 8 - 1
package-lock.json

@@ -5,7 +5,8 @@
     "packages": {
         "": {
             "dependencies": {
-                "bootstrap-icons": "^1.11.3"
+                "bootstrap-icons": "^1.11.3",
+                "jquery": "^3.7.1"
             },
             "devDependencies": {
                 "@popperjs/core": "^2.11.6",
@@ -1430,6 +1431,12 @@
                 "jiti": "bin/jiti.js"
             }
         },
+        "node_modules/jquery": {
+            "version": "3.7.1",
+            "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+            "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
+            "license": "MIT"
+        },
         "node_modules/laravel-vite-plugin": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.1.1.tgz",

+ 2 - 1
package.json

@@ -18,6 +18,7 @@
         "vite": "^6.0"
     },
     "dependencies": {
-        "bootstrap-icons": "^1.11.3"
+        "bootstrap-icons": "^1.11.3",
+        "jquery": "^3.7.1"
     }
 }

+ 4 - 20
resources/js/bootstrap.js

@@ -8,27 +8,11 @@ import 'bootstrap';
 
 import axios from 'axios';
 window.axios = axios;
-
 window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
 
-/**
- * Echo exposes an expressive API for subscribing to channels and listening
- * for events that are broadcast by Laravel. Echo and event broadcasting
- * allows your team to easily build robust real-time web applications.
- */
-
-// import Echo from 'laravel-echo';
 
-// import Pusher from 'pusher-js';
-// window.Pusher = Pusher;
+import $ from 'jquery';
+window.$ = $;
 
-// window.Echo = new Echo({
-//     broadcaster: 'pusher',
-//     key: import.meta.env.VITE_PUSHER_APP_KEY,
-//     cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
-//     wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
-//     wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
-//     wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
-//     forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
-//     enabledTransports: ['ws', 'wss'],
-// });
+import * as bootstrap from 'bootstrap'
+window.bootstrap = bootstrap;

+ 16 - 1
resources/sass/app.scss

@@ -11,4 +11,19 @@
 
 .invalid-feedback {
   display: block !important;
-}
+}
+
+.alerts{
+
+  position: absolute;
+  right: 0;
+  top: 0;
+  opacity: 0.8;
+  z-index: 999;
+
+
+  div {
+    padding-left: 3rem;
+    padding-right: 3rem;
+  }
+}

+ 6 - 6
resources/views/auth/login.blade.php

@@ -4,14 +4,14 @@
     <div class="row justify-content-center">
         <div class="col-md-8">
             <div class="card">
-                <div class="card-header">{{ __('Login') }}</div>
+                <div class="card-header">Вход в систему</div>
 
                 <div class="card-body">
                     <form method="POST" action="{{ route('login') }}">
                         @csrf
 
                         <div class="row mb-3">
-                            <label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
+                            <label for="email" class="col-md-4 col-form-label text-md-end">Email</label>
 
                             <div class="col-md-6">
                                 <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@@ -25,7 +25,7 @@
                         </div>
 
                         <div class="row mb-3">
-                            <label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
+                            <label for="password" class="col-md-4 col-form-label text-md-end">Пароль</label>
 
                             <div class="col-md-6">
                                 <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
@@ -44,7 +44,7 @@
                                     <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
 
                                     <label class="form-check-label" for="remember">
-                                        {{ __('Remember Me') }}
+                                        Запомнить меня
                                     </label>
                                 </div>
                             </div>
@@ -53,12 +53,12 @@
                         <div class="row mb-0">
                             <div class="col-md-8 offset-md-4">
                                 <button type="submit" class="btn btn-primary">
-                                    {{ __('Login') }}
+                                    Войти
                                 </button>
 
                                 @if (Route::has('password.request'))
                                     <a class="btn btn-link" href="{{ route('password.request') }}">
-                                        {{ __('Forgot Your Password?') }}
+                                        Забыли пароль?
                                     </a>
                                 @endif
                             </div>

+ 33 - 4
resources/views/layouts/app.blade.php

@@ -17,13 +17,27 @@
     @vite(['resources/sass/app.scss', 'resources/js/app.js'])
 </head>
 <body>
+    <div class="alerts">
+        @if($message = session('success'))
+            <div class="main-alert alert alert-success" role="alert">
+                {{ $message }}
+            </div>
+        @endif
+
+        @if($message = session('danger'))
+            <div class="main-alert alert alert-danger" role="alert">
+                {{ $message }}
+            </div>
+        @endif
+    </div>
+
     <div id="app">
         <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
             <div class="container">
                 <a class="navbar-brand" href="{{ url('/') }}">
                     {{ config('app.name', 'Laravel') }}
                 </a>
-                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
+                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Открыть меню">
                     <span class="navbar-toggler-icon"></span>
                 </button>
 
@@ -39,13 +53,13 @@
                         @guest
                             @if (Route::has('login'))
                                 <li class="nav-item">
-                                    <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
+                                    <a class="nav-link" href="{{ route('login') }}">Вход</a>
                                 </li>
                             @endif
 
                             @if (Route::has('register'))
                                 <li class="nav-item">
-                                    <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
+                                    <a class="nav-link" href="{{ route('register') }}">Регистрация</a>
                                 </li>
                             @endif
                         @else
@@ -55,10 +69,11 @@
                                 </a>
 
                                 <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
+                                    <a class="dropdown-item" href="{{ route('user.profile') }}">Профиль</a>
                                     <a class="dropdown-item" href="{{ route('logout') }}"
                                        onclick="event.preventDefault();
                                                      document.getElementById('logout-form').submit();">
-                                        {{ __('Logout') }}
+                                        Выход
                                     </a>
 
                                     <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@@ -78,5 +93,19 @@
             </div>
         </main>
     </div>
+
+    @stack('scripts')
+    <script type="module">
+        $(document).ready(function (){
+            if($('.main-alert').length){
+                setTimeout(function (){
+                    $('.main-alert').fadeTo(2000, 500).slideUp(500, function (){
+                        $(".main-alert").slideUp(500);
+                    })
+                }, 3000);
+            }
+        });
+    </script>
+
 </body>
 </html>

+ 4 - 40
resources/views/users/profile.blade.php

@@ -1,4 +1,4 @@
-@extends('layouts.app', ['title' => 'Профиль', 'experience' => $user->experience])
+@extends('layouts.app', ['title' => 'Профиль'])
 
 @section('content')
     <div class="px-3 col-xxl-8 offset-xxl-1">
@@ -7,34 +7,7 @@
 
             @include('partials.input', ['name' => 'email', 'title' => 'E-mail', 'disabled' => true, 'value' => $user->email])
             @include('partials.input', ['name' => 'name', 'title' => 'Имя', 'required' => true, 'value' => $user->name])
-            @include('partials.input', ['name' => 'surname', 'title' => 'Фамилия', 'value' => $user->surname])
-
-
-
-            @include('partials.avatars', ['user' => auth()->user()])
-
-            @include('partials.color', ['name' => 'bg_color', 'title' => 'Фон', 'value' => $user->bg_color ?? '#55def7'])
-
-            @if(auth()->user()->experience > $max_subscribe_experience)
-                <div class="visually-hidden">
-                    @include('partials.input', ['name' => 'e_mail', 'title' => 'E-mail', 'value' => $user->email])
-                </div>
-
-                @include('partials.input', ['name' => 'subscribe', 'title' => 'Подпись', 'value' => $user->subscribe ?? '', 'datalist' => $subscribes->pluck('caption')])
-            @else
-                @include('partials.select', ['name' => 'subscribe', 'title' => 'Подпись', 'options' => $subscribes->pluck('caption', 'caption')->toArray(), 'value' => $user->subscribe ?? ''])
-            @endif
-
-            @include('partials.input', ['name' => 'role', 'title' => 'Роли', 'disabled' => true, 'value' => implode(', ', $user->roles->pluck('title')->toArray())])
-            <div class="my-2">
-                <div class="row">
-                    <div class="col-md-4 text-md-end mt-1 fw-bold pe-3">Уведомления</div>
-                    <div class="col-md-8 mt-1 fst-italic">Выберите типы уведомлений, которые будем присылать вам на E-mail</div>
-                </div>
-                @foreach($notification_types as $type_id => $t)
-                    @include('partials.checkbox', ['name' => 'types[]', 'title' => $t, 'value' => $type_id, 'checked' => in_array($type_id, auth()->user()->notification_types->pluck('id')->toArray())])
-                @endforeach
-            </div>
+            @include('partials.input', ['name' => 'role', 'title' => 'Роль', 'disabled' => true, 'value' => getRoles($user->role)])
 
             <div class="row pwd-change-link mb-3">
                 <div class="offset-md-4">
@@ -42,23 +15,14 @@
                 </div>
             </div>
 
-            <div class="pwg-change d-none">
+            <div class="pwg-change @if(!$errors->any()) d-none @endif">
                 @include('partials.input', ['name' => 'current_password', 'type' => 'password', 'title' => 'Текущий пароль'])
                 @include('partials.input', ['name' => 'password', 'type' => 'password', 'title' => 'Новый пароль'])
                 @include('partials.input', ['name' => 'password_confirmation', 'type' => 'password', 'title' => 'Подтверждение пароля'])
             </div>
             @include('partials.submit', [''])
-            <a href="#" class="btn btn-outline-info my-3 d-inline-block d-md-none" onclick="$('#logout').submit();">Выход</a>
+{{--            <a href="#" class="btn btn-outline-info my-3 d-inline-block d-md-none" onclick="$('#logout').submit();">Выход</a>--}}
         </form>
     </div>
 @endsection
 
-@push('scripts')
-    <script type="module">
-        $('#subscribe').on('keyup', function (){
-            if($(this).val() === '') {
-                $('#dl-subscribe').attr('open', 'open');
-            }
-        });
-    </script>
-@endpush

+ 20 - 10
routes/web.php

@@ -6,20 +6,30 @@ use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Route;
 
 Route::get('/', function () {
-    return 'root';
+    return 'root page';
 });
 
-Auth::routes();
+Auth::routes(['register' => false, 'reset' => false, 'verify' => false, 'confirm' => false]);
 
 Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
 
-Route::prefix('admin')->middleware('role:' . Role::ADMIN)->group(function (){
-    Route::prefix('users')->group(function (){
-        Route::get('', [UserController::class, 'index'])->name('user.index');
-        Route::get('create', [UserController::class, 'create'])->name('user.create');
-        Route::get('{user}', [UserController::class, 'show'])->name('user.show');
-        Route::post('', [UserController::class, 'store'])->name('user.store');
-        Route::put('{user}', [UserController::class, 'update'])->name('user.update');
-        Route::delete('{user}', [UserController::class, 'destroy'])->name('user.destroy');
+Route::middleware('auth:web')->group(function () {
+
+    // admin routes
+    Route::prefix('admin')->middleware('role:' . Role::ADMIN)->group(function (){
+        Route::prefix('users')->group(function (){
+            Route::get('', [UserController::class, 'index'])->name('user.index');
+            Route::get('create', [UserController::class, 'create'])->name('user.create');
+            Route::get('{user}', [UserController::class, 'show'])->name('user.show');
+            Route::post('', [UserController::class, 'store'])->name('user.store');
+            Route::put('{user}', [UserController::class, 'update'])->name('user.update');
+            Route::delete('{user}', [UserController::class, 'destroy'])->name('user.destroy');
+        });
     });
+
+    // profile
+    Route::get('profile', [UserController::class, 'profile'])->name('user.profile');
+    Route::post('profile/store', [UserController::class, 'storeProfile'])->name('profile.store');
+
+
 });