Initial commit
This commit is contained in:
commit
c909d539bc
7178 files changed
+756624
No files matched your search
@@ -0,0 +1,95 @@
|
||||
<x-app-layout>
|
||||
<div class="py-12">
|
||||
<div class="max-w-3xl mx-auto sm:px-6 lg:px-8">
|
||||
|
||||
<div class="bg-white shadow-sm sm:rounded-lg overflow-hidden">
|
||||
<div class="p-6 text-gray-900">
|
||||
|
||||
<h1 class="text-2xl font-bold mb-6">Add New Course</h1>
|
||||
|
||||
{{-- Error Messages --}}
|
||||
@if ($errors->any())
|
||||
<div class="bg-red-100 text-red-800 p-4 rounded mb-6">
|
||||
<ul class="list-disc pl-5">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('admin.courses.store') }}" method="POST" class="space-y-6">
|
||||
@csrf
|
||||
|
||||
{{-- Subject --}}
|
||||
<div>
|
||||
<label for="subject_id" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Subject
|
||||
</label>
|
||||
<select id="subject_id" name="subject_id"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-200 focus:border-blue-300"
|
||||
required>
|
||||
<option value="">-- Choose a subject --</option>
|
||||
@foreach ($subjects as $subject)
|
||||
<option value="{{ $subject->id }}"
|
||||
{{ old('subject_id') == $subject->id ? 'selected' : '' }}>
|
||||
{{ $subject->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Level --}}
|
||||
<div>
|
||||
<label for="level_id" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Level
|
||||
</label>
|
||||
<select id="level_id" name="level_id"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-200 focus:border-blue-300"
|
||||
required>
|
||||
<option value="">-- Choose a level --</option>
|
||||
@foreach ($levels as $level)
|
||||
<option value="{{ $level->id }}"
|
||||
{{ old('level_id') == $level->id ? 'selected' : '' }}>
|
||||
{{ $level->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Lead Teacher --}}
|
||||
<div>
|
||||
<label for="lead_teacher" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Lead Teacher
|
||||
</label>
|
||||
<input id="lead_teacher" type="text" name="lead_teacher"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-200 focus:border-blue-300"
|
||||
value="{{ old('lead_teacher') }}" required>
|
||||
</div>
|
||||
|
||||
{{-- Description --}}
|
||||
<div>
|
||||
<label for="description" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Description
|
||||
</label>
|
||||
<textarea id="description" name="description"
|
||||
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-200 focus:border-blue-300"
|
||||
rows="4">{{ old('description') }}</textarea>
|
||||
</div>
|
||||
|
||||
{{-- Save Button --}}
|
||||
<div>
|
||||
<button type="submit"
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700
|
||||
font-medium text-sm shadow-sm transition">
|
||||
Save Course
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@@ -0,0 +1,62 @@
|
||||
<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-2xl font-bold mb-4">Courses</h1>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="bg-green-100 text-green-800 p-3 rounded mb-4">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($courses->isEmpty())
|
||||
<p>No courses have been added yet.</p>
|
||||
@else
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full border border-gray-200 bg-white">
|
||||
<thead class="bg-gray-100 border-b">
|
||||
<tr>
|
||||
<th class="px-4 py-2 text-left">ID</th>
|
||||
<th class="px-4 py-2 text-left">Subject</th>
|
||||
<th class="px-4 py-2 text-left">Level</th>
|
||||
<th class="px-4 py-2 text-left">Lead Teacher</th>
|
||||
<th class="px-4 py-2 text-left">Description</th>
|
||||
<th class="px-4 py-2 text-left">Created</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($courses as $course)
|
||||
<tr class="border-b hover:bg-gray-50">
|
||||
<td class="px-4 py-2">{{ $course->id }}</td>
|
||||
<td class="px-4 py-2">
|
||||
<a href="{{ route('admin.courses.show', $course) }}">
|
||||
{{ $course->subject->name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-4 py-2">
|
||||
{{ $course->level ? $course->level->name : '—' }}
|
||||
</td>
|
||||
<td class="px-4 py-2">{{ $course->lead_teacher }}</td>
|
||||
<td class="px-4 py-2">{{ $course->description }}</td>
|
||||
<td class="px-4 py-2">{{ $course->created_at->format('Y-m-d') }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
<div class="mt-6">
|
||||
<a href="{{ route('admin.courses.create') }}"
|
||||
class="px-4 py-2 bg-gray-200 border border-gray-300 rounded-md
|
||||
font-semibold text-sm text-black hover:bg-gray-300
|
||||
focus:outline-none focus:ring focus:ring-gray-400 transition">
|
||||
Add New Course
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@@ -0,0 +1,192 @@
|
||||
<x-app-layout>
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
|
||||
<div class="bg-white shadow-sm sm:rounded-lg overflow-hidden">
|
||||
<div class="p-6 text-gray-900">
|
||||
|
||||
<h1 class="text-2xl font-bold mb-6">
|
||||
Manage Course: {{ $course->subject->name }} ({{ $course->level->name }})
|
||||
</h1>
|
||||
|
||||
@forelse($course->modules as $module)
|
||||
<div class="mb-10">
|
||||
<!-- Module Name -->
|
||||
<h2 class="text-xl font-semibold mb-4">
|
||||
{{ $module->name }}
|
||||
</h2>
|
||||
|
||||
<div class="bg-gray-50 border rounded-lg p-5">
|
||||
|
||||
<!-- SECTION HEADER + ADD FORM -->
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold">
|
||||
Lesson Sections
|
||||
</h3>
|
||||
|
||||
<form action="{{ route('admin.sections.store', ['course' => $course->slug]) }}"
|
||||
method="POST"
|
||||
class="flex items-center gap-2">
|
||||
@csrf
|
||||
<input type="hidden" name="module_id" value="{{ $module->id }}">
|
||||
|
||||
<input type="text"
|
||||
name="title"
|
||||
placeholder="New Section Title"
|
||||
required
|
||||
class="border rounded px-2 py-1 text-sm w-48 focus:ring-blue-200 focus:border-blue-300">
|
||||
|
||||
<button type="submit"
|
||||
class="px-3 py-1 bg-green-100 text-green-700 rounded hover:bg-green-200 text-sm font-medium">
|
||||
➕ Add
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- SECTION LIST -->
|
||||
<ul id="section-list-{{ $module->id }}"
|
||||
class="border rounded divide-y divide-gray-200 sortable-item bg-white">
|
||||
|
||||
@foreach($module->lessonSections->sortBy('order') as $section)
|
||||
<li class="flex items-center justify-between px-4 py-2 hover:bg-gray-50"
|
||||
data-id="{{ $section->id }}">
|
||||
|
||||
<!-- Drag handle + link -->
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="cursor-move text-gray-400 select-none">⋮⋮</span>
|
||||
|
||||
<a href="{{ route('admin.sections.show', [
|
||||
'course' => $course->slug,
|
||||
'section' => $section->slug
|
||||
]) }}"
|
||||
class="text-blue-600 hover:underline">
|
||||
{{ $section->title }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Rename + Delete -->
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
<!-- RENAME -->
|
||||
<form action="{{ route('admin.sections.update', [
|
||||
'course' => $course->slug,
|
||||
'lessonSection' => $section->slug
|
||||
]) }}"
|
||||
method="POST"
|
||||
class="flex items-center gap-1">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<input type="text"
|
||||
name="title"
|
||||
value="{{ $section->title }}"
|
||||
class="border border-gray-300 rounded px-2 py-0.5 text-sm w-40 focus:ring-blue-200 focus:border-blue-300">
|
||||
|
||||
<button type="submit"
|
||||
class="text-blue-600 hover:text-blue-800 text-sm">
|
||||
✔
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- DELETE -->
|
||||
<button onclick="if (confirmDelete('{{ $section->title }}')) document.getElementById('delete-section-{{ $section->id }}').submit();"
|
||||
class="text-red-600 hover:text-red-800 text-sm">
|
||||
✖
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SINGLE DELETE FORM (correct route, no duplicates) -->
|
||||
<form id="delete-section-{{ $section->id }}"
|
||||
action="{{ route('admin.sections.destroy', [
|
||||
'course' => $course->slug,
|
||||
'section' => $section->slug
|
||||
]) }}"
|
||||
method="POST"
|
||||
class="hidden">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
</form>
|
||||
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
||||
<!-- Hidden reorder field + button -->
|
||||
<button form="reorderForm-{{ $module->id }}"
|
||||
class="mt-3 px-3 py-1 bg-blue-100 text-blue-700 rounded hover:bg-blue-200 text-sm font-medium">
|
||||
💾 Save Section Order
|
||||
</button>
|
||||
|
||||
<form action="{{ route('admin.sections.reorder', ['course' => $course->slug]) }}"
|
||||
method="POST"
|
||||
id="reorderForm-{{ $module->id }}"
|
||||
class="hidden">
|
||||
@csrf
|
||||
<input type="hidden" name="order" id="reorderInput-{{ $module->id }}">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-gray-600">
|
||||
No modules yet.
|
||||
<a href="{{ route('admin.modules.create') }}" class="text-blue-600 hover:underline">
|
||||
Add a module
|
||||
</a>
|
||||
</p>
|
||||
@endforelse
|
||||
|
||||
<!-- Add New Module -->
|
||||
<div class="mt-8 bg-gray-50 border rounded-lg p-5">
|
||||
<h3 class="text-lg font-semibold mb-4">Add a New Module</h3>
|
||||
|
||||
<form action="{{ route('admin.modules.store') }}" method="POST" class="flex gap-3">
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="course_id" value="{{ $course->id }}">
|
||||
|
||||
<input type="text"
|
||||
name="name"
|
||||
class="flex-1 border-gray-300 rounded-md shadow-sm focus:ring focus:ring-blue-200"
|
||||
placeholder="Module Name"
|
||||
required>
|
||||
|
||||
<button type="submit"
|
||||
class="px-3 py-1 bg-green-100 text-green-700 rounded hover:bg-green-200 text-sm font-medium">
|
||||
➕ Add Module
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
|
||||
<!-- Sortable -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Reorder handling
|
||||
document.querySelectorAll('[id^="section-list-"]').forEach(list => {
|
||||
const moduleId = list.id.replace('section-list-', '');
|
||||
const reorderForm = document.getElementById('reorderForm-' + moduleId);
|
||||
const reorderInput = document.getElementById('reorderInput-' + moduleId);
|
||||
|
||||
new Sortable(list, { animation: 150 });
|
||||
|
||||
reorderForm.addEventListener('submit', function () {
|
||||
const ids = [...list.querySelectorAll('li')].map(li => li.dataset.id);
|
||||
reorderInput.value = JSON.stringify(ids);
|
||||
});
|
||||
});
|
||||
|
||||
function confirmDelete(name) {
|
||||
return confirm(
|
||||
`Are you sure you want to delete the lesson section "${name}"?\n\n` +
|
||||
`⚠️ All chapters and lessons inside it will also be deleted.`
|
||||
);
|
||||
}
|
||||
</script>
|
||||
Reference in new issue
Block a user