label(__('panel.applications.actions.reply')) ->icon('heroicon-o-envelope') ->color('primary') ->authorize('update') ->modalHeading(fn (Application $record) => __('panel.replies.heading', ['name' => $record->name])) ->modalDescription(fn () => Replier::canSendMail() ? __('panel.replies.sends') : __('panel.replies.hands_over')) ->modalSubmitActionLabel(fn () => Replier::canSendMail() ? __('panel.replies.send') : __('panel.replies.open_mail')) ->schema([ Select::make('template_id') ->label(__('panel.replies.fields.template')) ->options(fn (Application $record) => ReplyTemplate::query()->for($record->kind)->pluck('name', 'id')->all()) ->placeholder(__('panel.replies.no_template')) ->live() ->afterStateUpdated(function (?string $state, callable $set, Application $record): void { $template = $state ? ReplyTemplate::find($state) : null; if ($template !== null) { $text = $template->renderFor($record, Auth::user()); $set('subject', $text['subject']); $set('body', $text['body']); } }), TextInput::make('subject') ->label(__('panel.replies.fields.subject')) ->default(fn (Application $record) => __('panel.applications.reply_subject', ['subject' => $record->subject()], $record->locale)) ->required() ->maxLength(255), Textarea::make('body') ->label(__('panel.replies.fields.body')) ->helperText(fn (Application $record) => __('panel.replies.in_language', [ 'language' => config("locales.supported.{$record->locale}.native", $record->locale), ])) ->required() ->rows(12), ]) ->action(function (Application $record, array $data, $livewire): void { $reply = Replier::reply($record, $data['subject'], $data['body'], Auth::user()); if ($reply->channel === ApplicationReply::MAILTO) { $livewire->js('window.location.href = '.json_encode(Replier::mailto($record, $data['subject'], $data['body']))); } Notification::make() ->title($reply->channel === ApplicationReply::MAIL ? __('panel.replies.sent') : __('panel.replies.recorded')) ->success() ->send(); }), // The way it always worked: an empty message in your own mail // program, for an answer that fits no template. Action::make('reply_elsewhere') ->label(__('panel.replies.elsewhere')) ->icon('heroicon-o-arrow-top-right-on-square') ->color('gray') ->url(fn (Application $record) => 'mailto:'.$record->email.'?subject=' .rawurlencode(__('panel.applications.reply_subject', [ 'subject' => $record->subject(), ]))) ->openUrlInNewTab(), Action::make('notes') ->label(__('panel.applications.actions.notes')) ->icon('heroicon-o-pencil-square') ->color('gray') ->authorize('update') ->schema([ Textarea::make('notes') ->label(__('panel.applications.fields.notes')) ->helperText(__('panel.applications.fields.notes_hint')) ->rows(6), ]) ->fillForm(fn (Application $record) => ['notes' => $record->notes]) ->action(function (Application $record, array $data): void { // Notes are outside the model's fillable list on purpose — // nothing arriving from the public form may ever land in // them — so they are written explicitly here. $record->forceFill(['notes' => $data['notes']])->save(); Notification::make() ->title(__('panel.applications.saved')) ->success() ->send(); }), ...ApplicationsTable::statusActions(), DeleteAction::make(), RestoreAction::make(), ForceDeleteAction::make(), ]; } }