Update expiry email to show pending role. if there is one

This commit is contained in:
DariusIII
2026-05-30 18:15:49 +02:00
parent 6e5940cd81
commit f8c52d176e
4 changed files with 61 additions and 2 deletions
+19 -1
View File
@@ -24,16 +24,31 @@ class AccountWillExpire extends Mailable
public ?string $preheader;
public bool $hasPendingRole;
public ?string $pendingRoleName;
public ?string $pendingRoleStartDate;
private string $siteEmail;
public function __construct(User $user, int $days)
{
$roleExpiryInfo = $user->getRoleExpiryInfo();
$pendingRole = $roleExpiryInfo['pending_role'];
$pendingStart = $roleExpiryInfo['pending_start'];
$this->days = $days;
$this->username = (string) $user->username;
$this->account = (string) ($user->role->name ?? 'User');
$this->hasPendingRole = (bool) $roleExpiryInfo['has_pending_role'] && $pendingRole !== null && $pendingStart !== null;
$this->pendingRoleName = $this->hasPendingRole ? (string) $pendingRole->name : null;
$this->pendingRoleStartDate = $this->hasPendingRole ? $pendingStart->toFormattedDateString() : null;
$this->siteEmail = (string) config('mail.from.address');
$this->site = (string) config('app.name');
$this->preheader = "Your {$this->account} role expires in {$this->days} day(s).";
$this->preheader = $this->hasPendingRole
? "Your {$this->account} role expires in {$this->days} day(s), then {$this->pendingRoleName} is scheduled."
: "Your {$this->account} role expires in {$this->days} day(s).";
}
public function build(): static
@@ -44,6 +59,9 @@ class AccountWillExpire extends Mailable
'username' => $this->username,
'account' => $this->account,
'days' => $this->days,
'hasPendingRole' => $this->hasPendingRole,
'pendingRoleName' => $this->pendingRoleName,
'pendingRoleStartDate' => $this->pendingRoleStartDate,
'site' => $this->site,
'preheader' => $this->preheader,
]);
+10 -1
View File
@@ -109,6 +109,7 @@ use Spatie\Permission\Traits\HasRoles;
* @property-read Collection<int, UserRoleHistory> $roleHistory
* @property-read Collection<int, Passkey> $passkeys
* @property-read Role|null $role
* @property-read Role|null $pendingRole
* @property-read PasswordSecurity|null $passwordSecurity
*
* @method static Builder|User whereUsername(string $value)
@@ -228,6 +229,14 @@ final class User extends Authenticatable implements HasPasskeys, MustVerifyEmail
return $this->belongsTo(Role::class, 'roles_id');
}
/**
* @return BelongsTo<Role, $this>
*/
public function pendingRole(): BelongsTo
{
return $this->belongsTo(Role::class, 'pending_roles_id');
}
/**
* @return HasMany<UserRequest, $this>
*/
@@ -649,7 +658,7 @@ final class User extends Authenticatable implements HasPasskeys, MustVerifyEmail
return null;
}
return Role::find($this->pending_roles_id);
return $this->pendingRole;
}
/**
@@ -7,7 +7,13 @@ Dear {{ $username }},
**Heads up:** Your **{{ $account }}** role expires in less than **{{ $days }} day(s)**.
@endcomponent
@if($hasPendingRole)
Your **{{ $pendingRoleName }}** role is already scheduled to take effect on **{{ $pendingRoleStartDate }}** after your current role expires.
No renewal action is needed for that pending role. If these details do not look right, please reach out before the expiry date.
@else
To continue enjoying uninterrupted access to all your current features and benefits, please take action before your subscription expires.
@endif
If you have any questions about renewing your account, please don't hesitate to reach out.
+26
View File
@@ -27,6 +27,7 @@ use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Markdown;
use Illuminate\Support\Carbon;
use PHPUnit\Framework\Attributes\DataProvider;
use Spatie\Permission\Models\Role;
use Tests\TestCase;
/**
@@ -122,6 +123,31 @@ class MailRenderingTest extends TestCase
$this->assertStringContainsStringIgnoringCase('color: #ffffff !important', $html);
}
public function test_account_will_expire_includes_pending_role_details_when_present(): void
{
$currentRole = new Role;
$currentRole->name = 'Silver';
$pendingRole = new Role;
$pendingRole->name = 'Gold';
$user = new User;
$user->username = 'tester';
$user->email = 'tester@example.test';
$user->pending_roles_id = 2;
$user->pending_role_start_date = Carbon::create(2026, 6, 4, 12);
$user->setRelation('role', $currentRole);
$user->setRelation('pendingRole', $pendingRole);
$mailable = new AccountWillExpire($user, 5);
$mailable->assertSeeInHtml('Silver');
$mailable->assertSeeInHtml('Gold');
$mailable->assertSeeInHtml('Jun 4, 2026');
$mailable->assertSeeInHtml('No renewal action is needed');
$mailable->assertDontSeeInHtml('please take action before your subscription expires');
}
public function test_invitation_mail_renders_with_branded_subject_and_brand_palette(): void
{
$inviter = new User;