Added Support and Analytics for Release
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Notifications\SupportRequestSubmitted;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class SupportFormController extends Controller
|
||||
{
|
||||
public function view()
|
||||
{
|
||||
return Inertia::render('Contact/Support');
|
||||
}
|
||||
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'reason' => ['required', 'string', 'in:bug_report,general_feedback,missing_data'],
|
||||
'message' => ['required', 'string', 'max:5000'],
|
||||
]);
|
||||
|
||||
Notification::route('mail', config('mail.support_address', 'hello@flightsgoneby.com'))
|
||||
->notify(new SupportRequestSubmitted(
|
||||
name: $request->user()->name,
|
||||
email: $request->user()->email,
|
||||
reason: $validated['reason'],
|
||||
message: $validated['message'],
|
||||
));
|
||||
|
||||
return back()->with('success', 'Your message has been sent.');
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,15 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Observers\AirlineObserver;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[ObservedBy(AirlineObserver::class)]
|
||||
class Airline extends Model
|
||||
{
|
||||
protected $table = 'airlines';
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Observers\NotificationObserver;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
@@ -26,6 +28,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* @method static Builder active()
|
||||
* @method static Builder forAchievements()
|
||||
*/
|
||||
#[ObservedBy(NotificationObserver::class)]
|
||||
class Notification extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
|
||||
+5
-1
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Observers\UserObserver;
|
||||
use App\Settings\SettingsRegistry;
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
@@ -24,7 +27,8 @@ use App\Notifications\ResetPasswordNotification;
|
||||
|
||||
#[Fillable(['name', 'email', 'password', 'distance_unit', 'settings'])]
|
||||
#[Hidden(['password', 'remember_token'])]
|
||||
class User extends Authenticatable
|
||||
#[ObservedBy(UserObserver::class)]
|
||||
class User extends Authenticatable implements MustVerifyEmail
|
||||
{
|
||||
|
||||
/** @use HasFactory<UserFactory> */
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Http\Controllers\Api\AirlineApiController;
|
||||
use App\Observers\FlightObserver;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -10,6 +12,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
#[ObservedBy(FlightObserver::class)]
|
||||
class UserFlight extends Model
|
||||
{
|
||||
protected $table = 'user_flights';
|
||||
@@ -56,6 +59,7 @@ class UserFlight extends Model
|
||||
'scope',
|
||||
'range',
|
||||
'region_range',
|
||||
'class_seat_combined'
|
||||
];
|
||||
|
||||
protected static function booted(): void
|
||||
@@ -95,6 +99,13 @@ class UserFlight extends Model
|
||||
);
|
||||
}
|
||||
|
||||
protected function classSeatCombined(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn() => $this->flightClass?->name
|
||||
);
|
||||
}
|
||||
|
||||
protected function departureTimeDisplay(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class SupportRequestSubmitted extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public string $email,
|
||||
public string $reason,
|
||||
public string $message,
|
||||
) {}
|
||||
|
||||
public function via($notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
public function toMail($notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->theme('flightsgoneby')
|
||||
->subject('New Support Request: ' . $this->reasonLabel())
|
||||
->replyTo($this->email, $this->name)
|
||||
->greeting('New Support Request')
|
||||
->line('Reason: ' . $this->reasonLabel())
|
||||
->line('From: ' . $this->name . ' (' . $this->email . ')')
|
||||
->line($this->message);
|
||||
}
|
||||
|
||||
protected function reasonLabel(): string
|
||||
{
|
||||
return match ($this->reason) {
|
||||
'bug_report' => 'Bug Report',
|
||||
'general_feedback' => 'General Feedback',
|
||||
'missing_data' => 'Missing Data',
|
||||
default => $this->reason,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Notification;
|
||||
use App\Models\User;
|
||||
|
||||
class UserObserver
|
||||
{
|
||||
public function created(User $user): void
|
||||
{
|
||||
User::role('admin')
|
||||
->where('id', '!=', $user->id)
|
||||
->get(['id'])
|
||||
->each(fn (User $admin) => Notification::create([
|
||||
'user_id' => $admin->id,
|
||||
'title' => 'New user registered',
|
||||
'body' => "{$user->name} just signed up.",
|
||||
'url' => null,
|
||||
'is_achievement' => false,
|
||||
'achievement_id' => null,
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -34,9 +34,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
Mail::alwaysTo(config('app.test_email'));
|
||||
}
|
||||
Vite::prefetch(concurrency: 3);
|
||||
UserFlight::observe(FlightObserver::class);
|
||||
Airline::observe(AirlineObserver::class);
|
||||
Notification::observe(NotificationObserver::class);
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return $request->user('sanctum')
|
||||
? Limit::perMinute(60)->by($request->user('sanctum')->id)
|
||||
|
||||
@@ -110,7 +110,10 @@ class SettingsRegistry
|
||||
'label' => 'Which columns to show on the Departure Board',
|
||||
'default' => ['airline', 'flight_number', 'departure_airport', 'arrival_airport', 'departure_date', 'departure_time', 'arrival_time', 'duration', 'distance', 'aircraft', 'registration', 'class_seat_combined'],
|
||||
'options' => [
|
||||
['value' => 'airline', 'label' => 'Airline'],
|
||||
['value' => 'airline', 'label' => 'Airline Logo w/ Info Popup'],
|
||||
['value' => 'airline.name', 'label' => 'Airline Name'],
|
||||
['value' => 'airline.iata_code', 'label' => 'Airline IATA Code'],
|
||||
['value' => 'airline.icao_code', 'label' => 'Airline ICAO Code'],
|
||||
['value' => 'flight_number', 'label' => 'Flight Number'],
|
||||
['value' => 'departure_airport', 'label' => 'From'],
|
||||
['value' => 'arrival_airport', 'label' => 'To'],
|
||||
@@ -119,8 +122,16 @@ class SettingsRegistry
|
||||
['value' => 'arrival_time', 'label' => 'Arrival Time'],
|
||||
['value' => 'duration', 'label' => 'Duration'],
|
||||
['value' => 'distance', 'label' => 'Distance'],
|
||||
['value' => 'aircraft', 'label' => 'Aircraft'],
|
||||
['value' => 'aircraft', 'label' => 'Aircraft Designator w/ Info Popup'],
|
||||
['value' => 'registration', 'label' => 'Aircraft Registration'],
|
||||
['value' => 'aircraft.manufacturer_code', 'label' => 'Aircraft Manufacturer'],
|
||||
['value' => 'aircraft.model_full_name', 'label' => 'Aircraft Model'],
|
||||
['value' => 'flight_class', 'label' => 'Class'],
|
||||
['value' => 'seat_type_id', 'label' => 'Seat Type'],
|
||||
['value' => 'seat_number', 'label' => 'Seat Number'],
|
||||
['value' => 'flight_reason_id', 'label' => 'Reason'],
|
||||
|
||||
['value' => 'aircraft.display_name_short', 'label' => 'Aircraft Full Name'],
|
||||
['value' => 'class_seat_combined', 'label' => 'Class/Seat Type/Seat Number Combined'],
|
||||
],
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user