Skip to content

Commit 7eeb3e8

Browse files
committed
Merge branch 'main' into v3
2 parents a557a24 + b4d6327 commit 7eeb3e8

11 files changed

+577
-7
lines changed

app/Console/Kernel.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@ class Kernel extends ConsoleKernel
1212
*/
1313
protected function schedule(Schedule $schedule): void
1414
{
15-
// Send license expiry warnings daily at 9 AM UTC
16-
$schedule->command('licenses:send-expiry-warnings')
17-
->dailyAt('09:00')
18-
->onOneServer()
19-
->runInBackground();
20-
2115
// Remove GitHub access for users with expired Max licenses
2216
$schedule->command('github:remove-expired-access')
2317
->dailyAt('10:00')

app/Filament/Resources/WallOfLoveSubmissionResource.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,48 @@ public static function form(Form $form): Form
4949
->maxLength(1000)
5050
->rows(4),
5151
]),
52+
53+
Forms\Components\Section::make('Status & Promotion')
54+
->schema([
55+
Forms\Components\Toggle::make('is_approved')
56+
->label('Approved')
57+
->helperText('Approved submissions appear on the Wall of Love.')
58+
->formatStateUsing(fn (?WallOfLoveSubmission $record) => $record?->isApproved() ?? false)
59+
->dehydrated(false)
60+
->afterStateUpdated(function (bool $state, ?WallOfLoveSubmission $record) {
61+
if (! $record) {
62+
return;
63+
}
64+
65+
if ($state) {
66+
$record->update([
67+
'approved_at' => now(),
68+
'approved_by' => auth()->id(),
69+
]);
70+
} else {
71+
$record->update([
72+
'approved_at' => null,
73+
'approved_by' => null,
74+
'promoted' => false,
75+
'promoted_testimonial' => null,
76+
]);
77+
}
78+
})
79+
->live(),
80+
81+
Forms\Components\Toggle::make('promoted')
82+
->label('Promoted to Homepage')
83+
->helperText('Promoted submissions appear in the feedback section on the homepage.')
84+
->visible(fn (Forms\Get $get) => $get('is_approved'))
85+
->live(),
86+
87+
Forms\Components\Textarea::make('promoted_testimonial')
88+
->label('Promoted Testimonial (optional override)')
89+
->helperText('Leave empty to use the original testimonial, or enter a clipped version for the homepage.')
90+
->rows(4)
91+
->visible(fn (Forms\Get $get) => $get('is_approved') && $get('promoted')),
92+
])
93+
->columns(1),
5294
]);
5395
}
5496

@@ -84,6 +126,15 @@ public static function table(Table $table): Table
84126
->falseColor('warning')
85127
->sortable(),
86128

129+
Tables\Columns\IconColumn::make('promoted')
130+
->label('Promoted')
131+
->boolean()
132+
->trueIcon('heroicon-o-star')
133+
->falseIcon('heroicon-o-star')
134+
->trueColor('warning')
135+
->falseColor('gray')
136+
->sortable(),
137+
87138
Tables\Columns\TextColumn::make('approvedBy.name')
88139
->label('Approved By')
89140
->toggleable(),
@@ -104,6 +155,12 @@ public static function table(Table $table): Table
104155
true: fn (Builder $query) => $query->whereNotNull('approved_at'),
105156
false: fn (Builder $query) => $query->whereNull('approved_at'),
106157
),
158+
159+
Tables\Filters\TernaryFilter::make('promoted')
160+
->label('Promoted')
161+
->placeholder('All')
162+
->trueLabel('Promoted')
163+
->falseLabel('Not Promoted'),
107164
])
108165
->actions([
109166
Tables\Actions\Action::make('approve')
@@ -130,6 +187,33 @@ public static function table(Table $table): Table
130187
->modalHeading('Unapprove Submission')
131188
->modalDescription('Are you sure you want to unapprove this submission?'),
132189

190+
Tables\Actions\Action::make('promote')
191+
->icon('heroicon-o-star')
192+
->color('warning')
193+
->visible(fn (WallOfLoveSubmission $record) => $record->isApproved() && ! $record->isPromoted())
194+
->form([
195+
Forms\Components\Textarea::make('promoted_testimonial')
196+
->label('Testimonial Text (optional override)')
197+
->helperText('Leave empty to use the original testimonial, or enter a clipped version.')
198+
->rows(4)
199+
->default(fn (WallOfLoveSubmission $record) => $record->testimonial),
200+
])
201+
->action(fn (WallOfLoveSubmission $record, array $data) => $record->update([
202+
'promoted' => true,
203+
'promoted_testimonial' => $data['promoted_testimonial'] !== $record->testimonial ? $data['promoted_testimonial'] : null,
204+
]))
205+
->modalHeading('Promote to Homepage')
206+
->modalDescription('This will display this testimonial in the feedback section on the homepage.'),
207+
208+
Tables\Actions\Action::make('unpromote')
209+
->icon('heroicon-o-x-mark')
210+
->color('gray')
211+
->visible(fn (WallOfLoveSubmission $record) => $record->isPromoted())
212+
->action(fn (WallOfLoveSubmission $record) => $record->update(['promoted' => false]))
213+
->requiresConfirmation()
214+
->modalHeading('Remove from Homepage')
215+
->modalDescription('This will remove this testimonial from the homepage feedback section.'),
216+
133217
Tables\Actions\EditAction::make(),
134218
Tables\Actions\DeleteAction::make(),
135219
])

app/Models/WallOfLoveSubmission.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Models;
44

5+
use Illuminate\Database\Eloquent\Builder;
56
use Illuminate\Database\Eloquent\Factories\HasFactory;
67
use Illuminate\Database\Eloquent\Model;
78
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -19,10 +20,13 @@ class WallOfLoveSubmission extends Model
1920
'testimonial',
2021
'approved_at',
2122
'approved_by',
23+
'promoted',
24+
'promoted_testimonial',
2225
];
2326

2427
protected $casts = [
2528
'approved_at' => 'datetime',
29+
'promoted' => 'boolean',
2630
];
2731

2832
public function user(): BelongsTo
@@ -44,4 +48,27 @@ public function isPending(): bool
4448
{
4549
return $this->approved_at === null;
4650
}
51+
52+
public function isPromoted(): bool
53+
{
54+
return $this->promoted;
55+
}
56+
57+
/**
58+
* @param Builder<WallOfLoveSubmission> $query
59+
* @return Builder<WallOfLoveSubmission>
60+
*/
61+
public function scopeApproved(Builder $query): Builder
62+
{
63+
return $query->whereNotNull('approved_at');
64+
}
65+
66+
/**
67+
* @param Builder<WallOfLoveSubmission> $query
68+
* @return Builder<WallOfLoveSubmission>
69+
*/
70+
public function scopePromoted(Builder $query): Builder
71+
{
72+
return $query->where('promoted', true);
73+
}
4774
}

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"guzzlehttp/guzzle": "^7.2",
1818
"laravel/cashier": "^15.6",
1919
"laravel/framework": "^10.10",
20+
"laravel/nightwatch": "^1.21",
2021
"laravel/pennant": "^1.18",
2122
"laravel/sanctum": "^3.3",
2223
"laravel/socialite": "^5.24",

composer.lock

Lines changed: 175 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

database/factories/WallOfLoveSubmissionFactory.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,14 @@ public function pending(): static
4949
'approved_by' => null,
5050
]);
5151
}
52+
53+
/**
54+
* Indicate that the submission is promoted to the homepage.
55+
*/
56+
public function promoted(): static
57+
{
58+
return $this->state(fn (array $attributes) => [
59+
'promoted' => true,
60+
]);
61+
}
5262
}

0 commit comments

Comments
 (0)