Current state with latest updates
This commit is contained in:
@@ -10,6 +10,7 @@ use App\Services\Academy\AcademyAccessService;
|
||||
use App\Services\Academy\AcademyInteractionService;
|
||||
use App\Support\AcademyAnalytics\AcademyAnalyticsContentType;
|
||||
use App\Support\Seo\SeoFactory;
|
||||
use App\Support\Seo\SeoDataBuilder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Inertia;
|
||||
@@ -44,6 +45,13 @@ final class AcademyChallengeController extends Controller
|
||||
route('academy.challenges.index'),
|
||||
)
|
||||
->toArray();
|
||||
$seo = SeoDataBuilder::fromArray($seo)
|
||||
->breadcrumbs([
|
||||
['name' => 'Academy', 'url' => route('academy.index')],
|
||||
['name' => 'Challenges', 'url' => route('academy.challenges.index')],
|
||||
])
|
||||
->build()
|
||||
->toArray();
|
||||
|
||||
return Inertia::render('Academy/List', [
|
||||
'pageType' => 'challenges',
|
||||
@@ -94,12 +102,24 @@ final class AcademyChallengeController extends Controller
|
||||
'submitted_at' => $submission->submitted_at?->toISOString(),
|
||||
])->values()->all();
|
||||
|
||||
$seo = app(SeoFactory::class)->collectionPage(
|
||||
$challenge->title . ' — Skinbase Academy',
|
||||
Str::limit((string) ($challenge->excerpt ?? $challenge->description ?? ''), 160, '...'),
|
||||
route('academy.challenges.show', ['slug' => $challenge->slug]),
|
||||
$challenge->cover_image,
|
||||
)->toArray();
|
||||
$canonical = route('academy.challenges.show', ['slug' => $challenge->slug]);
|
||||
$description = Str::limit((string) ($challenge->excerpt ?? $challenge->description ?? ''), 160, '...');
|
||||
$seo = SeoDataBuilder::fromArray(
|
||||
app(SeoFactory::class)->collectionPage(
|
||||
$challenge->title . ' — Skinbase Academy',
|
||||
$description,
|
||||
$canonical,
|
||||
$challenge->cover_image,
|
||||
)->toArray()
|
||||
)
|
||||
->breadcrumbs([
|
||||
['name' => 'Academy', 'url' => route('academy.index')],
|
||||
['name' => 'Challenges', 'url' => route('academy.challenges.index')],
|
||||
['name' => (string) $challenge->title, 'url' => $canonical],
|
||||
])
|
||||
->addJsonLd($this->challengeStructuredData($payload, $canonical, $description))
|
||||
->build()
|
||||
->toArray();
|
||||
|
||||
$interaction = $this->interactions->getInteractionState($request->user(), AcademyAnalyticsContentType::CHALLENGE, (int) $challenge->id);
|
||||
|
||||
@@ -128,4 +148,46 @@ final class AcademyChallengeController extends Controller
|
||||
],
|
||||
])->rootView('academy');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function challengeStructuredData(array $payload, string $canonical, string $description): array
|
||||
{
|
||||
$image = trim((string) ($payload['cover_image'] ?? ''));
|
||||
$imageUrl = $image !== '' && preg_match('/^https?:\/\//i', $image) === 1 ? $image : ($image !== '' ? url($image) : null);
|
||||
$requiredTags = array_values((array) ($payload['required_tags'] ?? []));
|
||||
$status = strtolower(trim((string) ($payload['status'] ?? '')));
|
||||
$eventStatus = match ($status) {
|
||||
'scheduled' => 'https://schema.org/EventScheduled',
|
||||
'active', 'voting' => 'https://schema.org/EventInProgress',
|
||||
'completed', 'archived' => 'https://schema.org/EventCompleted',
|
||||
default => null,
|
||||
};
|
||||
|
||||
return array_filter([
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'Event',
|
||||
'name' => (string) ($payload['title'] ?? 'Skinbase Academy challenge'),
|
||||
'description' => $description,
|
||||
'url' => $canonical,
|
||||
'image' => $imageUrl,
|
||||
'startDate' => $payload['starts_at'] ?? null,
|
||||
'endDate' => $payload['ends_at'] ?? null,
|
||||
'eventStatus' => $eventStatus,
|
||||
'eventAttendanceMode' => 'https://schema.org/OnlineEventAttendanceMode',
|
||||
'location' => [
|
||||
'@type' => 'VirtualLocation',
|
||||
'url' => $canonical,
|
||||
],
|
||||
'organizer' => [
|
||||
'@type' => 'Organization',
|
||||
'name' => config('seo.site_name', 'Skinbase'),
|
||||
'url' => url('/'),
|
||||
],
|
||||
'keywords' => $requiredTags !== [] ? $requiredTags : null,
|
||||
'isAccessibleForFree' => (string) ($payload['access_level'] ?? 'free') === 'free',
|
||||
], fn (mixed $value): bool => $value !== null && $value !== '' && $value !== []);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user