chore: commit remaining workspace changes

This commit is contained in:
2026-05-08 21:51:29 +02:00
parent 8d108b8a76
commit ff96ef796e
97 changed files with 18020 additions and 2196 deletions

View File

@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Academy;
use App\Http\Controllers\Controller;
use App\Models\AcademyCourse;
use App\Models\AcademyLesson;
use App\Services\Academy\AcademyAccessService;
use App\Services\Academy\AcademyCourseNavigationService;
use App\Services\Academy\AcademyCourseProgressService;
use App\Support\Seo\SeoFactory;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
final class AcademyCourseLessonController extends Controller
{
public function __construct(
private readonly AcademyAccessService $access,
private readonly AcademyCourseNavigationService $navigation,
private readonly AcademyCourseProgressService $progress,
) {
}
public function show(Request $request, AcademyCourse $course, AcademyLesson $lesson): Response
{
abort_unless((bool) config('academy.enabled', true), 404);
abort_unless($course->isPublished(), 404);
$course->load(['sections', 'courseLessons.section', 'courseLessons.lesson.category']);
$courseLesson = $this->navigation->findCourseLesson($course, $lesson);
abort_unless($courseLesson instanceof \App\Models\AcademyCourseLesson, 404);
if ($request->user()) {
$this->progress->updateLastLesson($request->user(), $course, $lesson);
$this->progress->markCourseCompletedIfFinished($request->user(), $course);
}
$progress = $this->progress->getProgress($request->user(), $course);
$previousLesson = $this->navigation->previousLesson($course, $lesson);
$nextLesson = $this->navigation->nextLesson($course, $lesson);
$courseOutline = $this->navigation->orderedCourseLessons($course)
->map(fn (\App\Models\AcademyCourseLesson $entry): array => $this->access->courseLessonPayload($entry, $request->user()))
->values()
->all();
$payload = $this->access->courseLessonPayload($courseLesson, $request->user(), true);
$canonical = route('academy.courses.lessons.show', ['course' => $course->slug, 'lesson' => $lesson->slug]);
$description = Str::limit(trim((string) ($lesson->seo_description ?? $lesson->excerpt ?? 'Skinbase Academy course lesson.')), 160, '...');
$seo = app(SeoFactory::class)->academyLessonPage(
(string) ($lesson->seo_title ?? ($lesson->title . ' — ' . $course->title)),
$description,
$canonical,
(string) ($payload['article_cover_image_url'] ?? $payload['cover_image_url'] ?? $lesson->cover_image ?? ''),
[
['name' => 'Academy', 'url' => route('academy.index')],
['name' => 'Courses', 'url' => route('academy.courses.index')],
['name' => (string) $course->title, 'url' => route('academy.courses.show', ['course' => $course->slug])],
['name' => (string) $lesson->title, 'url' => $canonical],
],
array_values((array) ($payload['tags'] ?? [])),
$lesson->published_at?->toAtomString(),
$lesson->updated_at?->toAtomString(),
(string) $course->title,
)->toArray();
return Inertia::render('Academy/Show', [
'pageType' => 'lesson',
'item' => $payload,
'relatedLessons' => [],
'relatedCourses' => [],
'previousLesson' => $previousLesson ? $this->access->courseLessonPayload($previousLesson, $request->user()) : null,
'nextLesson' => $nextLesson ? $this->access->courseLessonPayload($nextLesson, $request->user()) : null,
'seo' => $seo,
'pricingUrl' => route('academy.pricing'),
'completeUrl' => $request->user() ? route('academy.lessons.complete', ['lesson' => $lesson->id]) : null,
'completed' => $request->user()?->academyLessonProgress()->where('lesson_id', $lesson->id)->whereNotNull('completed_at')->exists() ?? false,
'courseContext' => [
'id' => (int) $course->id,
'title' => (string) $course->title,
'slug' => (string) $course->slug,
'subtitle' => (string) ($course->subtitle ?? ''),
'showUrl' => route('academy.courses.show', ['course' => $course->slug]),
'completePayload' => ['course_id' => $course->id],
'progress' => [
'percent' => (int) ($progress['progress_percent'] ?? 0),
'completedRequired' => (int) ($progress['completed_required'] ?? 0),
'totalRequired' => (int) ($progress['total_required'] ?? 0),
'completed' => (bool) ($progress['completed'] ?? false),
],
'outline' => $courseOutline,
],
])->rootView('collections');
}
}