feat(Membership, FAQ, Relance): update membership form (member type radio,retzien email field, calendar-year pricing), create FAQ page with accordion, wire renewal reminder notification
All checks were successful
Deploy Roxane to Preprod / deploy (push) Successful in 1m23s
All checks were successful
Deploy Roxane to Preprod / deploy (push) Successful in 1m23s
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Models\ListmonkMember;
|
||||
use App\Models\Member;
|
||||
use App\Models\Membership;
|
||||
use App\Models\Package;
|
||||
use App\Notifications\MemberRenewalReminderNotification;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
@@ -17,6 +18,7 @@ use Filament\Forms\Components\Toggle;
|
||||
use Filament\Infolists\Components\RepeatableEntry;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Infolists\Components\ViewEntry;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Schemas\Components\Grid;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
@@ -83,6 +85,11 @@ class MemberForm
|
||||
->default('physical')
|
||||
->required(),
|
||||
|
||||
Select::make('type_id')
|
||||
->label(Member::getAttributeLabel('type_id'))
|
||||
->relationship('type', 'name')
|
||||
->default(null),
|
||||
|
||||
Select::make('group_id')
|
||||
->label(Member::getAttributeLabel('group_id'))
|
||||
->relationship('group', 'name')
|
||||
@@ -98,6 +105,10 @@ class MemberForm
|
||||
->email()
|
||||
->required(),
|
||||
|
||||
TextInput::make('retzien_email')
|
||||
->label(Member::getAttributeLabel('retzien_email'))
|
||||
->email(),
|
||||
|
||||
TextInput::make('phone1')
|
||||
->label(Member::getAttributeLabel('phone1'))
|
||||
->tel(),
|
||||
@@ -366,8 +377,28 @@ class MemberForm
|
||||
->label(__('members.actions.send_renewal_mail'))
|
||||
->icon('heroicon-o-envelope')
|
||||
->color('primary')
|
||||
->action(function () {
|
||||
// Mail de relance à créer (Job)
|
||||
->requiresConfirmation()
|
||||
->modalHeading(__('members.actions.send_renewal_mail'))
|
||||
->modalDescription('Êtes-vous sûr de vouloir envoyer un mail de relance à cet adhérent ?')
|
||||
->action(function (Member $record) {
|
||||
try {
|
||||
$record->notify(new MemberRenewalReminderNotification($record));
|
||||
|
||||
Notification::make()
|
||||
->title('Mail de relance envoyé')
|
||||
->success()
|
||||
->send();
|
||||
} catch (\Throwable $e) {
|
||||
\Log::error('Erreur envoi mail de relance', [
|
||||
'member_id' => $record->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
Notification::make()
|
||||
->title('Erreur lors de l\'envoi du mail')
|
||||
->danger()
|
||||
->send();
|
||||
}
|
||||
}),
|
||||
])
|
||||
->extraAttributes(['class' => 'sticky top-4 h-fit']),
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Forms;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Forms\MembershipRequest;
|
||||
use App\Models\MemberType;
|
||||
use App\Models\Package;
|
||||
use App\Models\Service;
|
||||
use App\Services\MemberService;
|
||||
@@ -18,23 +19,39 @@ class MembershipFormController extends Controller
|
||||
public function create(): Response
|
||||
{
|
||||
$remainingMonths = 13 - now()->month;
|
||||
$currentYear = now()->year;
|
||||
|
||||
$plans = Package::query()
|
||||
->where('is_active', true)
|
||||
->select('id', 'identifier', 'name', 'price', 'description')
|
||||
->get()
|
||||
->map(fn (Package $p) => [
|
||||
'id' => $p->id,
|
||||
'identifier' => $p->identifier,
|
||||
'name' => $p->name,
|
||||
'description' => $p->description,
|
||||
'price' => $p->identifier === 'custom' ? $remainingMonths : (float) $p->price,
|
||||
'months' => $p->identifier === 'custom' ? $remainingMonths : null,
|
||||
]);
|
||||
->map(function (Package $p) use ($remainingMonths, $currentYear) {
|
||||
$months = match ($p->identifier) {
|
||||
'custom' => $remainingMonths,
|
||||
'one-year' => $remainingMonths + 12,
|
||||
'two-years' => $remainingMonths + 24,
|
||||
default => null,
|
||||
};
|
||||
|
||||
return [
|
||||
'id' => $p->id,
|
||||
'identifier' => $p->identifier,
|
||||
'name' => $p->name,
|
||||
'description' => $p->description,
|
||||
'price' => $months ?? (float) $p->price,
|
||||
'months' => $months,
|
||||
];
|
||||
});
|
||||
|
||||
$memberTypes = MemberType::query()
|
||||
->select('id', 'identifier', 'name')
|
||||
->get();
|
||||
|
||||
return Inertia::render('forms/membership', [
|
||||
'plans' => $plans,
|
||||
'services' => Service::query()->select('name', 'description')->get(),
|
||||
'member_types' => $memberTypes,
|
||||
'current_year' => $currentYear,
|
||||
'captcha_question' => $this->generateCaptcha(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ class MembershipRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'member_type' => 'required|string|exists:member_types,identifier',
|
||||
'lastname' => 'required|string|max:255',
|
||||
'firstname' => 'required|string|max:255',
|
||||
'email' => 'required|email|max:255',
|
||||
'company' => 'nullable|string|max:255',
|
||||
'desired_retzien_email' => ['nullable', 'string', 'max:64', 'regex:/^[a-z0-9._-]+$/'],
|
||||
'address' => 'required|string|max:255',
|
||||
'zipcode' => ['required', 'digits:5'],
|
||||
'city' => 'required|string|max:255',
|
||||
|
||||
@@ -133,6 +133,11 @@ class Member extends Model
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function type(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(MemberType::class);
|
||||
}
|
||||
|
||||
public function group(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(MemberGroup::class);
|
||||
|
||||
17
app/Models/MemberType.php
Normal file
17
app/Models/MemberType.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class MemberType extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'identifier',
|
||||
'name',
|
||||
'description',
|
||||
];
|
||||
}
|
||||
51
app/Notifications/MemberRenewalReminderNotification.php
Normal file
51
app/Notifications/MemberRenewalReminderNotification.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Member;
|
||||
use App\Models\NotificationTemplate;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class MemberRenewalReminderNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(
|
||||
public readonly Member $member,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
$template = NotificationTemplate::findByIdentifier('member_renewal_reminder');
|
||||
|
||||
$vars = [
|
||||
'member_name' => $this->member->full_name,
|
||||
'app_name' => config('app.front_name'),
|
||||
];
|
||||
|
||||
return (new MailMessage)
|
||||
->subject($template->renderSubject($vars))
|
||||
->view('notifications.mail-template', [
|
||||
'body' => $template->renderBody($vars),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace App\Services;
|
||||
use App\Events\MemberRegistered;
|
||||
use App\Models\Member;
|
||||
use App\Models\MemberGroup;
|
||||
use App\Models\MemberType;
|
||||
use App\Models\Package;
|
||||
use App\Notifications\MemberDeactivatedAdminNotification;
|
||||
use App\Notifications\MemberDeactivatedMemberNotification;
|
||||
@@ -22,11 +23,14 @@ class MemberService
|
||||
// Check if the member already exists
|
||||
$member = Member::where('email', $data['email'])->first();
|
||||
|
||||
$memberType = MemberType::where('identifier', $data['member_type'])->first();
|
||||
|
||||
if (! $member) {
|
||||
// Create a new member
|
||||
$member = new Member;
|
||||
$member->status = 'pending';
|
||||
$member->nature = 'physical';
|
||||
$member->type_id = $memberType?->id;
|
||||
$member->group_id = MemberGroup::where('identifier', 'website')->first()->id ?? null;
|
||||
$member->lastname = $data['lastname'];
|
||||
$member->firstname = $data['firstname'];
|
||||
@@ -37,6 +41,11 @@ class MemberService
|
||||
$member->city = $data['city'];
|
||||
$member->country = 'FR';
|
||||
$member->phone1 = $data['phone1'];
|
||||
|
||||
if (! empty($data['desired_retzien_email'])) {
|
||||
$member->retzien_email = $data['desired_retzien_email'].'@retzien.fr';
|
||||
}
|
||||
|
||||
$member->save();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user