diff --git a/README.md b/README.md index 8b82292..a371941 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,41 @@ Onboard::addStep('Excluded Step') }); ``` +Limiting steps to a specific class: + +```php +Onboard::addStep('Limited Step', User::class) + ->link('/post/create'); + +// or + +Onboard::addStep('Limited Step', 'App\Models\User') + ->link('/post/create'); +``` + +When using limited steps, steps that are not limited will be available to all classes. For example: + +```php +// Defining User steps +Onboard::addStep('Limited User Step', User::class) + ->link('/post/create'); + +// Defining Team steps +Onboard::addStep('Limited Team Step', Team::class) + ->link('/post/create'); + +// Defining a step that is available to all classes +Onboard::addStep('Normal Step') + ->link('/post/create'); +``` + +The above will result in 1 step being available to all classes, and 2 steps being available to the `User` and `Team` classes: + +`Other` classes will only see the `Normal Step`. +`User` classes will both see the `Normal Step` and `Limited User Step`. +`Team` classes will both see the `Normal Step` and `Limited Team Step`. + + Definining custom attributes and accessing them: ```php diff --git a/src/Facades/Onboard.php b/src/Facades/Onboard.php index 1bd0ab5..8f9a972 100644 --- a/src/Facades/Onboard.php +++ b/src/Facades/Onboard.php @@ -9,7 +9,7 @@ use Spatie\Onboard\OnboardingSteps; /** - * @method OnboardingStep addStep(string $title) + * @method OnboardingStep addStep(string $title, string $model = null) * @method Collection steps(Onboardable $model) */ class Onboard extends Facade diff --git a/src/OnboardingSteps.php b/src/OnboardingSteps.php index fa52d6a..09369c0 100644 --- a/src/OnboardingSteps.php +++ b/src/OnboardingSteps.php @@ -10,17 +10,35 @@ class OnboardingSteps /** @var array */ protected array $steps = []; - public function addStep(string $title): OnboardingStep + public function addStep(string $title, string $model = null): OnboardingStep { - $this->steps[] = $step = new OnboardingStep($title); + $step = new OnboardingStep($title); - return $step; + if ($model && new $model() instanceof Onboardable) { + return $this->steps[$model][] = $step; + } + + return $this->steps['default'][] = $step; } public function steps(Onboardable $model): Collection { - return collect($this->steps) + return collect($this->getStepsArray($model)) ->map(fn (OnboardingStep $step) => $step->initiate($model)) ->filter(fn (OnboardingStep $step) => $step->notExcluded()); } + + private function getStepsArray(Onboardable $model): array + { + $key = get_class($model); + + if (key_exists($key, $this->steps)) { + return array_merge( + $this->steps[$key], + $this->steps['default'] ?? [] + ); + } + + return $this->steps['default'] ?? []; + } } diff --git a/tests/OnboardTest.php b/tests/OnboardTest.php index 1e05c97..934a013 100644 --- a/tests/OnboardTest.php +++ b/tests/OnboardTest.php @@ -3,10 +3,12 @@ use Spatie\Onboard\OnboardingManager; use Spatie\Onboard\OnboardingSteps; +use Spatie\Onboard\Tests\Team; use Spatie\Onboard\Tests\User; beforeEach(function () { $this->user = new User(); + $this->team = new Team(); }); test('steps can be defined and configured', function () { @@ -21,6 +23,35 @@ }); $this->assertEquals(1, $onboardingSteps->steps(new User())->count()); + $this->assertEquals(1, $onboardingSteps->steps(new Team())->count()); + + $userStep = $onboardingSteps->steps(new User())->first(); + $teamStep = $onboardingSteps->steps(new Team())->first(); + + expect($userStep->link)->toBe('/some/url') + ->and($userStep->cta)->toBe('Test This!') + ->and($userStep->title)->toBe('Test Step') + ->and($userStep->another)->toBe('attribute'); + + expect($teamStep->link)->toBe('/some/url') + ->and($teamStep->cta)->toBe('Test This!') + ->and($teamStep->title)->toBe('Test Step') + ->and($teamStep->another)->toBe('attribute'); +}); + +test('limited steps can be defined and configured', function () { + $onboardingSteps = new OnboardingSteps(); + + $onboardingSteps->addStep('Test Step', User::class) + ->link('/some/url') + ->cta('Test This!') + ->attributes(['another' => 'attribute']) + ->completeIf(function () { + return true; + }); + + $this->assertEquals(1, $onboardingSteps->steps(new User())->count()); + $this->assertEquals(0, $onboardingSteps->steps(new Team())->count()); $step = $onboardingSteps->steps(new User())->first(); @@ -30,6 +61,40 @@ ->and($step->another)->toBe('attribute'); }); +test('limited steps can be defined with normal steps', function () { + $onboardingSteps = new OnboardingSteps(); + + $onboardingSteps->addStep('Test Step', User::class); + + $onboardingSteps->addStep('Test Step Normal'); + + $this->assertEquals(2, $onboardingSteps->steps(new User())->count()); +}); + +test('multipe limited step models can be defined', function () { + $onboardingSteps = new OnboardingSteps(); + + $onboardingSteps->addStep('Test Step', User::class); + + $onboardingSteps->addStep('Test Step Team', Team::class); + + $this->assertEquals(1, $onboardingSteps->steps(new User())->count()); + $this->assertEquals(1, $onboardingSteps->steps(new Team())->count()); +}); + +test('multipe limited step models can be defined with normal steps', function () { + $onboardingSteps = new OnboardingSteps(); + + $onboardingSteps->addStep('Test Step', User::class); + + $onboardingSteps->addStep('Test Step Normal', Team::class); + + $onboardingSteps->addStep('Test Step Normal'); + + $this->assertEquals(2, $onboardingSteps->steps(new User())->count()); + $this->assertEquals(2, $onboardingSteps->steps(new Team())->count()); +}); + test('is in progress when all steps are incomplete', function () { $onboardingSteps = new OnboardingSteps(); $onboardingSteps->addStep('Test Step'); @@ -62,6 +127,31 @@ ->and($onboarding->inProgress())->toBeFalse(); }); +test('is finished when all steps are complete for limited models steps', function () { + $onboardingSteps = new OnboardingSteps(); + $onboardingSteps->addStep('Test Step', User::class) + ->completeIf(function () { + return true; + }); + $onboardingSteps->addStep('Test Step', Team::class) + ->completeIf(function () { + return false; + }); + + $onboardingSteps->addStep('Excluded Step') + ->excludeIf(function () { + return true; + }) + ->completeIf(function () { + return false; + }); + + $onboarding = new OnboardingManager($this->user, $onboardingSteps); + + expect($onboarding->finished())->toBeTrue() + ->and($onboarding->inProgress())->toBeFalse(); +}); + test('it returns the correct next unfinished step', function () { $onboardingSteps = new OnboardingSteps(); $onboardingSteps->addStep('Step 1') diff --git a/tests/Team.php b/tests/Team.php new file mode 100644 index 0000000..3d77b78 --- /dev/null +++ b/tests/Team.php @@ -0,0 +1,12 @@ +