Commit 22f5df84fd3819d2cc3d8146ed7de9cc81daf551

Authored by Андрей Ларионов
1 parent 185d7799ae

Образование табы

Showing 4 changed files with 404 additions and 49 deletions Side-by-side Diff

app/Http/Controllers/Admin/EducationController.php
... ... @@ -121,6 +121,16 @@ class EducationController extends Controller
121 121 return redirect()->route('admin.education.edit', ['education' => $education]);
122 122 }
123 123  
  124 + public function edit_program(ProgramEducation $program, Education $education) {
  125 + $id_education = $education->id;
  126 + return view('admin.education.program-edit', compact('id_education', 'education', 'program'));
  127 + }
  128 +
  129 + public function update_program(ProgramEducationRequest $request, ProgramEducation $program, Education $education) {
  130 + $program->update($request->all());
  131 + return redirect()->route('admin.education.edit', ['education' => $education]);
  132 + }
  133 +
124 134 public function delete_program(ProgramEducation $program, Education $education) {
125 135 $education = $education->id;
126 136 $program->delete();
resources/views/admin/education/form.blade.php
... ... @@ -101,58 +101,106 @@
101 101 </form>
102 102  
103 103 @isset($education)
104   - <hr>
105   - <h5 class="text-gray-700 dark:text-gray-400">Специалитеты и категории:</h5>
106   - <form method="GET" action="{{ route('admin.add-program-education') }}">
107   - <label class="block text-sm">
108   - <span class="text-gray-700 dark:text-gray-400">Категория образования</span>
109   - <input type="hidden" name="id" value="{{ $education->id }}"/>
110   - <input name="level" id="level"
111   - class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"
112   - placeholder="Новое образование" value=""
113   - /><br>
114   - <button type="submit" id="btn_education" name="btn_education" class="px-3 py-1 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-md active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple">
115   - Добавить
116   - </button>
117   - </label><br>
118   - </form>
119   - <hr>
120   - @if ($program->count())
121   - @php $bool = true;
122   - $i = 1;
123   - $level = "";
124   - @endphp
125   -
126   - @foreach ($program as $pro)
127   - @if ((!empty($level)) && ($level <> $pro->level ))
128   - </div>
129   - </div><br>
130   - @php $bool = true; $i++; @endphp
131   - @endif
132   - @if ($bool == true)
133   - <div class="tabs">
134   - <input type="radio" name="tab-btn" id="tab-btn-{{$i}}" value="" checked>
135   - <label for="tab-btn-{{$i}}">{{ $pro->level }}</label>
136   - <div id="content-{{$i}}">
137   -
138   - @php $bool = false;
139   - $level = $pro->level;
140   - @endphp
141   - @endif
142   - <label class="block text-sm">
143   - <h4 class="mb-4 text-lg font-semibold text-gray-600 dark:text-gray-300">Специальность: {{$pro->name}}</h4>
144   - <span class="text-gray-700 dark:text-gray-400">Описание: {{$pro->text}}</span>
145   - <a href="{{ route('admin.delete-program-education', ['program' => $pro->id, 'education' => $education->id]) }}">Удалить</a>
146   - </label><br><hr>
147   - @endforeach
  104 + <div class="tabs_ js_tabs px-4 py-3 bg-white rounded-lg shadow-md dark:bg-gray-800">
  105 + <h2 class="my-6 text-2xl font-semibold text-gray-700 dark:text-gray-200">
  106 + Программы образования
  107 + </h2>
  108 + <form class="tabs__form js_tabs_form" method="GET" action="{{ route('admin.add-program-education') }}">
  109 + <label class="tabs__label block mt-4 text-sm">
  110 + <div class="relative text-gray-500 focus-within:text-purple-600">
  111 + <input type="hidden" name="id" value="{{ $education->id }}"/>
  112 + <input name="level" class="tabs__input js_tabs_input block w-full pr-20 text-sm text-black dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray form-input" placeholder="Введите название таба"/>
  113 + <!-- For disabled buttons ADD these classes: opacity-50 cursor-not-allowed
  114 + And REMOVE these classes: active:bg-purple-600 hover:bg-purple-700 focus:shadow-outline-purple -->
  115 + <button class="tabs__submit-btn js_tabs_submit_btn absolute inset-y-0 right-0 px-4 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-r-md focus:outline-none opacity-50 cursor-not-allowed" disabled>+</button>
  116 + <!-- <button class="tabs__submit-btn js_tabs_submit_btn absolute inset-y-0 right-0 px-4 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-r-md active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple">+</button> -->
148 117 </div>
149   - </div><br>
150   - @else
151   - <span class="text-gray-700 dark:text-gray-400">Нет записей</span>
152   - @endif
153   - @endisset
  118 + </label>
  119 + </form>
  120 + <div class="tabs__buttons js_tabs_buttons flex flex-col flex-wrap mb-4 md:flex-row md:space-x-4">
  121 + @if ($program->count())
  122 + @php $bool = true;
  123 + $i = 1;
  124 + $level = "";
  125 + @endphp
  126 +
  127 + @foreach ($program as $pro)
  128 + @if ((!empty($level)) && ($level <> $pro->level ))
  129 + @php $bool = true; $i++; @endphp
  130 + @endif
  131 + @if ($bool == true)
  132 + <div>
  133 + <button class="tabs__btn js_tabs_btn mt-4 px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple" data-btn="{{ $pro->level }}" data-id="{{$i}}">{{ $pro->level }}</button>
  134 + </div>
  135 + @php $bool = false;
  136 + $level = $pro->level;
  137 + @endphp
  138 + @endif
  139 + @endforeach
  140 + @endif
  141 + </div>
  142 + <div class="tabs__content js_tabs_content">
  143 + @if ($program->count())
  144 + @php $bool = true;
  145 + $i = 1;
  146 + $level = "";
  147 + @endphp
  148 +
  149 + @foreach ($program as $pro)
  150 + @if ((!empty($level)) && ($level <> $pro->level))
  151 + </tbody>
  152 + </table>
  153 + </div>
  154 + @php $bool = true; $i++; @endphp
  155 + @endif
  156 +
  157 + @if ($bool == true)
  158 + <div class="tabs__item js_tabs_item @php echo($i>1) ? 'hidden' : ''; @endphp" data-id="{{$i}}">
  159 + <table class="mb-4 w-full whitespace-no-wrap">
  160 + <thead>
  161 + <tr
  162 + class="text-xs font-semibold tracking-wide text-left text-gray-500 uppercase border-b dark:border-gray-700 bg-gray-50 dark:text-gray-400 dark:bg-gray-800"
  163 + >
  164 + <th class="px-4 py-3">Специализация</th>
  165 + <th class="px-4 py-3">Описание</th>
  166 + <th class="px-4 py-3">Редактирование</th>
154 167  
  168 + </tr>
  169 + </thead>
  170 + <tbody
  171 + class="bg-white divide-y dark:divide-gray-700 dark:bg-gray-800"
  172 + >
  173 + @php $bool = false;
  174 + $level = $pro->level;
  175 + @endphp
  176 + @endif
  177 + <tr class="text-gray-700 dark:text-gray-400">
  178 + <td class="px-4 py-3">
  179 + <div class="flex items-center text-sm">
  180 + <div>
  181 + <p class="font-semibold">Специальность: </p>
  182 + <p class="text-xs text-gray-600 dark:text-gray-400">
  183 + {{$pro->name}}
  184 + </p>
  185 + </div>
  186 + </div>
  187 + </td>
  188 + <td class="px-4 py-3 text-sm">
  189 + <span class="text-gray-700 dark:text-gray-400">Описание: {{$pro->text}}</span>
  190 + </td>
  191 + <td class="px-4 py-3 text-xs">
  192 + <a href="{{ route('admin.edit-program-education', ['program' => $pro->id, 'education' => $education->id]) }}">Изменить</a> |
  193 + <a href="{{ route('admin.delete-program-education', ['program' => $pro->id, 'education' => $education->id]) }}">Удалить</a>
  194 +
  195 + </td>
  196 + </tr>
  197 + @endforeach
  198 + @endif
  199 + </div>
  200 + </div>
  201 + @endisset
155 202 </div>
  203 +
156 204 <script src="//cdn.ckeditor.com/4.14.0/standard/ckeditor.js"></script>
157 205  
158 206 <!--<script src="{{ asset('./ckeditor/ckeditor.js') }}"></script>-->
... ... @@ -163,3 +211,251 @@
163 211 filebrowserUploadMethod: 'form'
164 212 });
165 213 </script>
  214 +<script>
  215 + window.addEventListener('DOMContentLoaded', () => {
  216 +
  217 + setTabs(3);
  218 +
  219 + function setTabs(qty) {
  220 +
  221 + const tabs = document.querySelector('.js_tabs');
  222 + const tabsForm = tabs.querySelector('.js_tabs_form');
  223 + const tabsInput = tabs.querySelector('.js_tabs_input');
  224 + const tabsSubmitBtn = tabs.querySelector('.js_tabs_submit_btn');
  225 + const tabsButtons = tabs.querySelector('.js_tabs_buttons');
  226 + const tabsContent = tabs.querySelector('.js_tabs_content');
  227 +
  228 + tabsForm.addEventListener('submit', (e) => {
  229 +
  230 + //e.preventDefault();
  231 +
  232 + const tabsInputValue = tabsInput.value;
  233 + const tabsBtns = tabsButtons.querySelectorAll('.js_tabs_btn');
  234 + const id = Date.now();
  235 +
  236 + if (tabsInput.dataset.edit) {
  237 +
  238 + tabsBtns.forEach(btn => {
  239 + if (tabsInput.dataset.edit === btn.dataset.id) {
  240 + btn.textContent = tabsInputValue;
  241 + btn.dataset.btn = tabsInputValue;
  242 + }
  243 + });
  244 + console.log('Эта ветка выполнилась');
  245 + tabsInput.removeAttribute('data-edit');
  246 +
  247 + } else {
  248 +
  249 + if (!tabsBtns.length) {
  250 + tabsButtons.innerHTML += getTabsBtnTemplate(tabsInputValue, id);
  251 + tabsContent.innerHTML += getTabsItemTemplate(id);
  252 + }
  253 +
  254 + if (tabsBtns.length && tabsBtns.length < qty) {
  255 +
  256 + let isMatch = false;
  257 +
  258 + tabsBtns.forEach(btn => {
  259 + if (tabsInputValue === btn.dataset.btn) {
  260 + isMatch = true;
  261 + }
  262 + });
  263 +
  264 + console.log('Альтернативная ветка!');
  265 + if (!isMatch) {
  266 + tabsButtons.innerHTML += getTabsBtnTemplate(tabsInputValue, id);
  267 + tabsContent.innerHTML += getTabsItemTemplate(id, 'hidden');
  268 + }
  269 + }
  270 + }
  271 +
  272 + tabsInput.value = '';
  273 + addDisabledBtnStatus(tabsSubmitBtn);
  274 +
  275 + });
  276 +
  277 + tabsInput.addEventListener('input', () => {
  278 +
  279 + if (tabsInput.value !== '') {
  280 + removeDisabledBtnStatus(tabsSubmitBtn);
  281 + } else {
  282 + addDisabledBtnStatus(tabsSubmitBtn);
  283 + }
  284 +
  285 + });
  286 +
  287 + tabsButtons.addEventListener('click', (e) => {
  288 +
  289 + const target = e.target.closest('.js_tabs_btn');
  290 +
  291 + if (target) {
  292 +
  293 + const tabsItems = tabs.querySelectorAll('.js_tabs_item');
  294 +
  295 + tabsItems.forEach(item => {
  296 +
  297 + item.classList.add('hidden');
  298 +
  299 + if (target.dataset.id === item.dataset.id) {
  300 + item.classList.remove('hidden');
  301 + }
  302 + });
  303 + }
  304 +
  305 + });
  306 +
  307 + tabsButtons.addEventListener('dblclick', (e) => {
  308 +
  309 + const target = e.target.closest('.js_tabs_btn');
  310 +
  311 + if (target) {
  312 +
  313 + tabsInput.value = target.dataset.btn;
  314 + tabsInput.dataset.edit = target.dataset.id;
  315 + removeDisabledBtnStatus(tabsSubmitBtn);
  316 +
  317 + }
  318 +
  319 + });
  320 +
  321 + function getTabsBtnTemplate(btnName, id) {
  322 + return `
  323 + <div>
  324 + <button class="tabs__btn js_tabs_btn mt-4 px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple" data-btn="${btnName}" data-id="${id}">${btnName}</button>
  325 + </div>
  326 + `;
  327 + }
  328 +
  329 + function getTabsItemTemplate(id, className = '') {
  330 + return `
  331 + <div class="tabs__item js_tabs_item ${className}" data-id="${id}">
  332 + <div class="mb-4">${id}</div>
  333 + <table class="mb-4 w-full whitespace-no-wrap">
  334 + <thead>
  335 + <tr
  336 + class="text-xs font-semibold tracking-wide text-left text-gray-500 uppercase border-b dark:border-gray-700 bg-gray-50 dark:text-gray-400 dark:bg-gray-800"
  337 + >
  338 + <th class="px-4 py-3">Client</th>
  339 + <th class="px-4 py-3">Amount</th>
  340 + <th class="px-4 py-3">Status</th>
  341 + <th class="px-4 py-3">Date</th>
  342 + </tr>
  343 + </thead>
  344 + <tbody
  345 + class="bg-white divide-y dark:divide-gray-700 dark:bg-gray-800"
  346 + >
  347 + <tr class="text-gray-700 dark:text-gray-400">
  348 + <td class="px-4 py-3">
  349 + <div class="flex items-center text-sm">
  350 + <!-- Avatar with inset shadow -->
  351 + <div
  352 + class="relative hidden w-8 h-8 mr-3 rounded-full md:block"
  353 + >
  354 + <img
  355 + class="object-cover w-full h-full rounded-full"
  356 + src="https://images.unsplash.com/flagged/photo-1570612861542-284f4c12e75f?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjE3Nzg0fQ"
  357 + alt=""
  358 + loading="lazy"
  359 + />
  360 + <div
  361 + class="absolute inset-0 rounded-full shadow-inner"
  362 + aria-hidden="true"
  363 + ></div>
  364 + </div>
  365 + <div>
  366 + <p class="font-semibold">Hans Burger</p>
  367 + <p class="text-xs text-gray-600 dark:text-gray-400">
  368 + 10x Developer
  369 + </p>
  370 + </div>
  371 + </div>
  372 + </td>
  373 + <td class="px-4 py-3 text-sm">
  374 + $ 863.45
  375 + </td>
  376 + <td class="px-4 py-3 text-xs">
  377 + <span
  378 + class="px-2 py-1 font-semibold leading-tight text-green-700 bg-green-100 rounded-full dark:bg-green-700 dark:text-green-100"
  379 + >
  380 + Approved
  381 + </span>
  382 + </td>
  383 + <td class="px-4 py-3 text-sm">
  384 + 6/10/2020
  385 + </td>
  386 + </tr>
  387 +
  388 + <tr class="text-gray-700 dark:text-gray-400">
  389 + <td class="px-4 py-3">
  390 + <div class="flex items-center text-sm">
  391 + <!-- Avatar with inset shadow -->
  392 + <div
  393 + class="relative hidden w-8 h-8 mr-3 rounded-full md:block"
  394 + >
  395 + <img
  396 + class="object-cover w-full h-full rounded-full"
  397 + src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&facepad=3&fit=facearea&s=707b9c33066bf8808c934c8ab394dff6"
  398 + alt=""
  399 + loading="lazy"
  400 + />
  401 + <div
  402 + class="absolute inset-0 rounded-full shadow-inner"
  403 + aria-hidden="true"
  404 + ></div>
  405 + </div>
  406 + <div>
  407 + <p class="font-semibold">Jolina Angelie</p>
  408 + <p class="text-xs text-gray-600 dark:text-gray-400">
  409 + Unemployed
  410 + </p>
  411 + </div>
  412 + </div>
  413 + </td>
  414 + <td class="px-4 py-3 text-sm">
  415 + $ 369.95
  416 + </td>
  417 + <td class="px-4 py-3 text-xs">
  418 + <span
  419 + class="px-2 py-1 font-semibold leading-tight text-orange-700 bg-orange-100 rounded-full dark:text-white dark:bg-orange-600"
  420 + >
  421 + Pending
  422 + </span>
  423 + </td>
  424 + <td class="px-4 py-3 text-sm">
  425 + 6/10/2020
  426 + </td>
  427 + </tr>
  428 + </tbody>
  429 + </table>
  430 +
  431 + <div class="flex flex-col flex-wrap mb-4 md:flex-row md:space-x-4">
  432 + <div>
  433 + <a href="#" class="mt-4 px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple">Редактировать</a>
  434 + </div>
  435 + <div>
  436 + <a href="#" class="mt-4 px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple">Удалить</a>
  437 + </div>
  438 + </div>
  439 + </div>
  440 + `;
  441 + }
  442 +
  443 + function addDisabledBtnStatus(btn) {
  444 + btn.disabled = true;
  445 + btn.classList.add('opacity-50', 'cursor-not-allowed');
  446 + btn.classList.remove('active:bg-purple-600', 'hover:bg-purple-700', 'focus:shadow-outline-purple');
  447 + }
  448 +
  449 + function removeDisabledBtnStatus(btn) {
  450 + btn.disabled = false;
  451 + btn.classList.remove('opacity-50', 'cursor-not-allowed');
  452 + btn.classList.add('active:bg-purple-600', 'hover:bg-purple-700', 'focus:shadow-outline-purple');
  453 + }
  454 +
  455 + }
  456 +
  457 + console.log('main.js init');
  458 +
  459 + });
  460 +</script>
  461 +
resources/views/admin/education/program-edit.blade.php
... ... @@ -0,0 +1,45 @@
  1 +@extends('layout.admin', ['title' => 'Админка - Образование - Редактирование программы обучения'])
  2 +
  3 +@section('content')
  4 + <form method="POST" action="{{ route('admin.update-program-education', ['program' => $program, 'education' => $education]) }}">
  5 + @csrf
  6 +
  7 + <div class="px-4 py-3 mb-8 bg-white rounded-lg shadow-md dark:bg-gray-800">
  8 + <input type="hidden" id="education_id" name="education_id" value="{{ $id_education }}"/>
  9 + <input type="hidden" id="level" name="level" value="{{ $program->name }}"/>
  10 +
  11 + <label class="block text-sm">
  12 + <span class="text-gray-700 dark:text-gray-400">Название специализации</span>
  13 + <input name="name" id="name"
  14 + class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"
  15 + placeholder="Название специализации" required value="{{ old('name') ?? $program->name ?? '' }}"
  16 + />
  17 + @error('name')
  18 + <span class="text-xs text-red-600 dark:text-red-400">
  19 + {{ $message }}
  20 + </span>
  21 + @enderror
  22 + </label><br>
  23 +
  24 + <label class="block text-sm">
  25 + <span class="text-gray-700 dark:text-gray-400">Текст</span>
  26 + <textarea class="block w-full mt-1 text-sm dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 form-textarea focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray ckeditor" name="text" placeholder="Текст (html)" required
  27 + rows="10">{{ old('text') ?? $program->text ?? '' }}</textarea>
  28 + @error('text')
  29 + <span class="text-xs text-red-600 dark:text-red-400">
  30 + {{ $message }}
  31 + </span>
  32 + @enderror
  33 + </label><br>
  34 +
  35 + <div class="flex flex-col flex-wrap mb-4 space-y-4 md:flex-row md:items-end md:space-x-4">
  36 + <div>
  37 + <button type="submit" class="px-3 py-1 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-md active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple">
  38 + Сохранить
  39 + </button>
  40 + </div>
  41 + </div>
  42 + </div>
  43 + </form>
  44 +
  45 +@endsection
... ... @@ -228,6 +228,10 @@ Route::group([
228 228  
229 229 Route::get('program-education', [EducationController::class, 'add_program'])->name('add-program-education');
230 230 Route::post('program-education', [EducationController::class, 'store_program'])->name('store-program-education');
  231 +
  232 + Route::get('program-education/edit/{program}/{education}', [EducationController::class, 'edit_program'])->name('edit-program-education');
  233 + Route::post('program-education/edit/{program}/{education}', [EducationController::class, 'update_program'])->name('update-program-education');
  234 +
231 235 Route::get('program-education/delete/{program}/{education}', [EducationController::class, 'delete_program'])->name('delete-program-education');
232 236  
233 237 //Route::get('job-titles', [AdminController::class, 'index'])->name('job-titles');