Laravel Nova Resource Stubs For Spark Teams

Lee Mason

Lee Mason

At Gambit Nash we are on the verge of releasing WP Git Updater. WP Git Updater provides automated source control updates for WordPress websites stored in git. Very much like dependabot but for WordPress sites not using composer version management.

As this is a service which has a monthly subscription. The obvious choice was to implement Laravel Spark and let it take care of the subscription management. As an added bonus it provided us with a base to work from for the rest of the site (layouts, style, etc).

Im going to review Spark in a broader post, so I’m not going to go too far into a review, but suffice to say the kiosk feature is “ok”, but its not on the level of Laravel Nova (and nor should it be). So we took the decision to build a nova backend for the site too.

I was quite surprised to find scarce examples or packages to display Spark information in Nova. Might even be worth Spark having some stubs included to show this info when Nova is also installed.

We have used Spark through a team billing profile, so the following stubs don’t take into account user subscriptions, but I’m sure you could modify the resources to work for users if needed.

Team Resource

<?php
namespace App\Nova;

use Illuminate\Support\Str;
use Laravel\Nova\Fields\BelongsToMany;
use Laravel\Nova\Fields\DateTime;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Text;
use Laravel\Spark\Spark;

class Team extends Resource
{
    public static $model = \App\Models\Team::class;

    public static $group = 'Spark';

    public static $search = [
        'id',
        'name',
        'update_token'
    ];

    public static $title = 'name';

    public function fields(Request $request)
    {
        return [
            ID::make('ID', 'id')->sortable(),
            Text::make('Name', 'name')->sortable()->rules('required', 'max:255'),
            Text::make('Slug', 'slug'),
            Text::make('Update Token', 'update_token')->readonly(),
            Text::make('Stripe ID', 'stripe_id')->nullable(),
            Text::make('Current Plan', 'current_billing_plan')->nullable(),
            DateTime::make('Trial Ends', 'trial_ends_at')->nullable(),
            DateTime::make('Created At', 'created_at')->readonly()->hideFromIndex(),
            DateTime::make('Updated At', 'updated_at')->readonly()->hideFromIndex(),
            HasMany::make('Subscriptions', 'subscriptions', TeamSubscription::class),
            BelongsToMany::make('Team Members', 'users', User::class)
                ->fields(function () {
                    return [
                        Select::make('Role')
                            ->options(
                                array_merge(
                                    Spark::roles(),
                                    [
                                        //default role
                                        Spark::defaultRole() => Str::ucfirst(Spark::defaultRole()),
                                        //owner role
                                        'owner' => 'Owner'
                                    ]
                                )
                            )
                    ];
                }),
        ];
    }
}

Team Subscription Resource

<?php
namespace App\Nova;

use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\DateTime;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Number;
use Laravel\Nova\Fields\Text;

class TeamSubscription extends Resource
{
    public static $model = \Laravel\Spark\TeamSubscription::class;

    public static $group = 'Spark';

    public static $search = [
        'id',
        'name',
        'stripe_id',
        'stripe_plan',
        'stripe_status'
    ];

    public static $title = 'name';

    public function fields(Request $request)
    {
        return [
            ID::make()->sortable(),
            Text::make('Name', 'name')->nullable(),
            Text::make('Stripe ID', 'stripe_id')->nullable(),
            Text::make('Stripe Plan', 'stripe_plan')->nullable(),
            Text::make('Stripe Status', 'stripe_status')->nullable()->sortable(),
            Number::make('QTY', 'quantity')->nullable(),
            DateTime::make('Trial Ends', 'trial_ends_at')->nullable()->sortable(),
            DateTime::make('Ends At', 'ends_at')->nullable()->sortable(),
            DateTime::make('Created', 'created_at')->sortable()->readonly()->hideFromIndex(),
            DateTime::make('Updated At', 'updated_at')->sortable()->readonly()->hideFromIndex(),
            BelongsTo::make('Team', 'team', Team::class)->searchable(),
            HasMany::make('Subscription Items', 'items', TeamSubscriptionItem::class)
        ];
    }
}

Team Subscription Item Resource

<?php
namespace App\Nova;

use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\DateTime;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Number;
use Laravel\Nova\Fields\Text;

class TeamSubscriptionItem extends Resource
{
    public static $model = \Laravel\Spark\TeamSubscriptionItem::class;

    public static $group = 'Spark';

    public static $search = [
        'id',
        'stripe_id',
        'stripe_plan',
    ];

    public function fields(Request $request)
    {
        return [
            ID::make()->sortable(),
            Text::make('Stripe ID', 'stripe_id')->nullable(),
            Text::make('Stripe Plan', 'stripe_plan')->nullable(),
            Number::make('QTY', 'quantity')->nullable(),
            DateTime::make('Created', 'created_at')->sortable()->readonly()->hideFromIndex(),
            DateTime::make('Updated At', 'updated_at')->sortable()->readonly()->hideFromIndex(),
            BelongsTo::make('Team Subscription', 'subscription', TeamSubscription::class)->searchable(),
        ];
    }
}

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

If you agree to these terms, please click here.

Comments