phplaravellaravel-livewirelaravel-jetstream

How to set current_team_id when user accepts Jetstream team invitation by email to the Team id of the Admin inviting him?


I am developing an App that uses Jetstream registration as well as teams. With my App users join App once and they stay, so I need set current_team_id to user when he/she accepts invitation via email.

In my concern AddTeamMember.php has somethning to do with this, I added some codes to implement this but it does not work, it as follows.

$newTeamMember->forceFill([
    'current_team_id' => $team->id,
])->save();

I have tried other solutions earlier such as creating a new Class AcceptTeamInvitation but it's implementation was not even clear to me.

I expect Column current_team_id of Users table to be updated with Admin Team Inviting a user to join a Team.

<?php

namespace App\Actions\Jetstream;

use App\Models\User;
use App\Models\TeamInvitation;
use Illuminate\Support\Facades\Gate;
use Laravel\Jetstream\Events\TeamMemberAdded;
use Laravel\Jetstream\Contracts\AcceptsTeamInvitations;

class AcceptTeamInvitation 
{
    /**
     * Accept a team invitation.
     */
    public function accept(User $user, string $invitationId): void
    {
        // Retrieve the invitation or fail
        $invitation = TeamInvitation::whereKey($invitationId)->firstOrFail();

        // Authorize the action
        Gate::forUser($user)->authorize('acceptTeamInvitation', $invitation);

        // Attach the user to the team with the assigned role
        $invitation->team->users()->attach($user, [
            'role' => $invitation->role,
        ]);

        // Set the current team ID for the user
        $user->forceFill([
            'current_team_id' => $invitation->team->id,
        ])->save();

        // Fire the event
        TeamMemberAdded::dispatch($invitation->team, $user);

        // Delete the invitation
        $invitation->delete();
    }
}

AddTeamMember.php fullcodes.

<?php

namespace App\Actions\Jetstream;

use App\Models\Team;
use App\Models\User;
use Closure;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Laravel\Jetstream\Contracts\AddsTeamMembers;
use Laravel\Jetstream\Events\AddingTeamMember;
use Laravel\Jetstream\Events\TeamMemberAdded;
use Laravel\Jetstream\Jetstream;
use Laravel\Jetstream\Rules\Role;

class AddTeamMember implements AddsTeamMembers
{
    /**
     * Add a new team member to the given team.
     */
    public function add(User $user, Team $team, string $email, ?string $role = null): void
    {
        Gate::forUser($user)->authorize('addTeamMember', $team);

        $this->validate($team, $email, $role);

        $newTeamMember = Jetstream::findUserByEmailOrFail($email);

        AddingTeamMember::dispatch($team, $newTeamMember);

        $team->users()->attach(
            $newTeamMember, ['role' => $role]
        );

        $newTeamMember->forceFill([
            'current_team_id' => $team->id,
        ])->save();

        TeamMemberAdded::dispatch($team, $newTeamMember);
    }

    /**
     * Validate the add member operation.
     */
    protected function validate(Team $team, string $email, ?string $role): void
    {
        Validator::make([
            'email' => $email,
            'role' => $role,
        ], $this->rules(), [
            'email.exists' => __('We were unable to find a registered user with this email address.'),
        ])->after(
            $this->ensureUserIsNotAlreadyOnTeam($team, $email)
        )->validateWithBag('addTeamMember');
    }

    /**
     * Get the validation rules for adding a team member.
     *
     * @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
     */
    protected function rules(): array
    {
        return array_filter([
            'email' => ['required', 'email', 'exists:users'],
            'role' => Jetstream::hasRoles()
                            ? ['required', 'string', new Role]
                            : null,
        ]);
    }

    /**
     * Ensure that the user is not already on the team.
     */
    protected function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
    {
        return function ($validator) use ($team, $email) {
            $validator->errors()->addIf(
                $team->hasUserWithEmail($email),
                'email',
                __('This user already belongs to the team.')
            );
        };
    }
}


Solution

  • Create custom AcceptTeamInvitation action

    public function accept(User $user, string $invitationId): void
    {
        $invitation = TeamInvitation::findOrFail($invitationId);
        
        $invitation->team->users()->attach($user, ['role' => $invitation->role]);
        
        $user->update(['current_team_id' => $invitation->team->id]);
        
        $invitation->delete();
    }
    

    Register it in JetstreamServiceProvider

    $this->app->singleton(
        \Laravel\Jetstream\Contracts\AcceptsTeamInvitations::class,
        \App\Actions\Jetstream\AcceptTeamInvitation::class
    );