Group class term dates, single-class embed mode, and offering editing
CI / Tests (PHP 8.2) (pull_request) Successful in 45s
CI / Tests (PHP 8.1) (pull_request) Successful in 48s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 1m14s
CI / PHPStan (pull_request) Successful in 1m16s
CI / Tests (PHP 8.3) (pull_request) Successful in 37s
CI / Build Plugin Zip (pull_request) Has been skipped

Group class offerings now carry real dates: the add/edit form takes a
start date plus a sessions control (one-off, or weekly for N sessions;
the end date is computed as start + (N-1) weeks via
Offering::weeklyTermEnd). Dates are validated strictly (Y-m-d) and shown
in the offerings list and on the student-facing class card, including
the weekly session count.

[us_group_classes offering="<id>"] (block attribute offeringId, chosen
from a dropdown of active classes fetched from the public offerings
endpoint) restricts the page to a single class so the enrolment flow can
be embedded on a page dedicated to that class; a pinned class that is no
longer offered reports itself closed instead of falling back to the
catalog.

Offerings are now editable from the admin screen: an Edit button
prefills the shared add/edit form and saving posts usc_action=update.
Updates always preserve the original owner and currency, and non-admin
instructors can only load and update their own offerings. The form also
gains the previously missing description field and an Active toggle (the
admin-UI counterpart of the REST is_active flag) so an edit cannot wipe
data the form never collected.

Closes #59

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-07-05 23:18:59 -03:00
co-authored by Claude Fable 5
parent 9d8924132c
commit cde8704267
15 changed files with 653 additions and 42 deletions
@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Unsupervised\Schedular\Tests\Unit\GroupClass;
use Brain\Monkey\Functions;
use Unsupervised\Schedular\GroupClass\GroupClassPage;
use Unsupervised\Schedular\Tests\Unit\TestCase;
class GroupClassPageTest extends TestCase
{
private GroupClassPage $page;
protected function setUp(): void
{
parent::setUp();
$this->page = new GroupClassPage();
Functions\when('is_user_logged_in')->justReturn(true);
Functions\when('current_user_can')->justReturn(true);
Functions\when('wp_enqueue_style')->justReturn(null);
Functions\when('wp_enqueue_script')->justReturn(null);
Functions\when('absint')->alias(static fn ($value) => abs((int) $value));
}
public function testDefaultRenderHasNoOfferingRestriction(): void
{
$html = $this->page->render([]);
self::assertStringContainsString('id="us-group-app"', $html);
self::assertStringNotContainsString('data-offering', $html);
}
public function testShortcodeOfferingAttributePinsASingleClass(): void
{
$html = $this->page->render(['offering' => '12']);
self::assertStringContainsString('data-offering="12"', $html);
}
public function testBlockOfferingIdAttributePinsASingleClass(): void
{
$html = $this->page->render(['offeringId' => 7]);
self::assertStringContainsString('data-offering="7"', $html);
}
public function testGarbageOfferingAttributeIsIgnored(): void
{
$html = $this->page->render(['offering' => 'banana']);
self::assertStringNotContainsString('data-offering', $html);
}
public function testLoggedOutVisitorGetsLoginPrompt(): void
{
Functions\when('is_user_logged_in')->justReturn(false);
Functions\when('get_permalink')->justReturn('http://example.com/classes/');
Functions\when('wp_login_url')->justReturn('http://example.com/wp-login.php');
$html = $this->page->render([]);
self::assertStringContainsString('log in to enrol in a class', $html);
self::assertStringNotContainsString('us-group-app', $html);
}
}