Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 116 additions & 63 deletions app/Livewire/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@
use Illuminate\Support\Facades\Http;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\View;
use Filament\Support\Enums\Alignment;
use Filament\Forms\Contracts\HasForms;
use Filament\Schemas\Components\Group;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Contracts\HasTable;
use App\Notifications\VerifyEmailChange;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Actions;
use Filament\Schemas\Components\Tabs\Tab;
use Illuminate\Database\Eloquent\Builder;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Components\CheckboxList;
Expand Down Expand Up @@ -71,63 +74,127 @@ public function mount(): void
protected function getFormSchema(): array
{
return [
Section::make(trans('auth.profile'))
->columns()
->schema([
TextInput::make('name')->label(trans('auth.name'))->required(),
TextInput::make('username')
->label(trans('profile.username'))
->helperText(trans('profile.username_description'))
->required()
->rules([
'alpha_dash'
])
->unique(table: User::class, column: 'username', ignorable: auth()->user()),
TextInput::make('email')
->label(trans('auth.email'))
->required()
->email()
->unique(table: User::class, column: 'email', ignorable: auth()->user()),
Select::make('locale')->label(trans('auth.locale'))->options($this->locales)->placeholder(trans('auth.locale_null_value')),
Select::make('date_locale')->label(trans('auth.date_locale'))->options($this->locales)->placeholder(trans('auth.date_locale_null_value')),
])->collapsible(),

Grid::make(2)
->schema([
Section::make(trans('profile.notifications'))
->columnSpan(1)
Tabs::make('profile')
->persistTabInQueryString()
->tabs([
Tab::make(trans('profile.tabs.account'))
->key('account', isInheritable: false)
->icon('heroicon-o-user')
->columns()
->schema([
TextInput::make('name')->label(trans('auth.name'))->required(),
TextInput::make('username')
->label(trans('profile.username'))
->helperText(trans('profile.username_description'))
->required()
->rules([
'alpha_dash'
])
->unique(table: User::class, column: 'username', ignorable: auth()->user()),
TextInput::make('email')
->label(trans('auth.email'))
->required()
->email()
->unique(table: User::class, column: 'email', ignorable: auth()->user()),
Select::make('locale')->label(trans('auth.locale'))->options($this->locales)->placeholder(trans('auth.locale_null_value'))->searchable(),
Select::make('date_locale')->label(trans('auth.date_locale'))->options($this->locales)->placeholder(trans('auth.date_locale_null_value'))->searchable(),
$this->getSaveFormActions(),
View::make('livewire.profile.delete-account')->columnSpanFull(),
]),

Tab::make(trans('profile.tabs.preferences'))
->key('preferences', isInheritable: false)
->icon('heroicon-o-adjustments-horizontal')
->columns()
->schema([
CheckboxList::make('notification_settings')
->label(trans('profile.notification_settings'))
->options([
'receive_mention_notifications' => trans('profile.receive_mention_notifications'),
'receive_comment_reply_notifications' => trans('profile.receive_comment_reply_notifications'),
]),
])->collapsible(),

Section::make(trans('profile.settings'))
->columnSpan(1)
Group::make([
Select::make('per_page_setting')
->label(trans('profile.per-page-setting'))
->multiple()
->options([
5 => '5',
10 => '10',
15 => '15',
25 => '25',
50 => '50',
])
->required()
->helperText(trans('profile.per-page-setting-helper'))
->rules(['array', 'in:5,10,15,25,50']),

Toggle::make('hide_from_leaderboard')
->label(trans('profile.hide-from-leaderboard'))
->helperText(trans('profile.hide-from-leaderboard-helper')),
]),

$this->getSaveFormActions(),
]),

Tab::make(trans('profile.tabs.security'))
->key('security', isInheritable: false)
->icon('heroicon-o-shield-check')
->schema([
Select::make('per_page_setting')
->label(trans('profile.per-page-setting'))
->multiple()
->options([
5 => '5',
10 => '10',
15 => '15',
25 => '25',
50 => '50',
])
->required()
->helperText(trans('profile.per-page-setting-helper'))
->rules(['array', 'in:5,10,15,25,50']),
View::make('livewire.profile.two-factor')
->viewData(fn (): array => $this->getTwoFactorViewData()),
]),

Tab::make(trans('profile.mcp.heading'))
->key('mcp', isInheritable: false)
->icon('heroicon-o-command-line')
->visible(fn (): bool => app(GeneralSettings::class)->enable_mcp)
->schema([
View::make('livewire.profile.mcp-tokens')
->viewData(fn (): array => [
'mcpTokens' => $this->user->tokens()->latest()->get(),
]),
]),

Toggle::make('hide_from_leaderboard')
->label(trans('profile.hide-from-leaderboard'))
->helperText(trans('profile.hide-from-leaderboard-helper'))
])->collapsible(),
])
Tab::make(trans('profile.social-login'))
->key('social-login', isInheritable: false)
->icon('heroicon-o-link')
->visible(fn (): bool => SsoProvider::isEnabled())
->schema([
View::make('livewire.profile.social-login'),
]),
]),
];
}

/**
* The save button shown at the bottom of each tab that holds form fields.
*/
protected function getSaveFormActions(): Actions
{
return Actions::make([
Action::make('save')
->label(trans('profile.save'))
->submit('submit'),
])->columnSpanFull();
}

/**
* @return array{twoFactorEnabled: bool, twoFactorConfirmed: bool, twoFactorQrCode: ?string, twoFactorSetupKey: ?string, recoveryCodes: array<int, string>}
*/
protected function getTwoFactorViewData(): array
{
$twoFactorEnabled = ! is_null($this->user->two_factor_secret);
$twoFactorConfirmed = ! is_null($this->user->two_factor_confirmed_at);

return [
'twoFactorEnabled' => $twoFactorEnabled,
'twoFactorConfirmed' => $twoFactorConfirmed,
'twoFactorQrCode' => $twoFactorEnabled ? $this->user->twoFactorQrCodeSvg() : null,
'twoFactorSetupKey' => $twoFactorEnabled
? Fortify::currentEncrypter()->decrypt($this->user->two_factor_secret)
: null,
'recoveryCodes' => $twoFactorConfirmed ? $this->user->recoveryCodes() : [],
];
}

Expand Down Expand Up @@ -436,21 +503,7 @@ public function getLocalesProperty(): array

public function render()
{
$twoFactorEnabled = ! is_null($this->user->two_factor_secret);
$twoFactorConfirmed = ! is_null($this->user->two_factor_confirmed_at);

return view('livewire.profile', [
'hasSsoLoginAvailable' => SsoProvider::isEnabled(),
'twoFactorEnabled' => $twoFactorEnabled,
'twoFactorConfirmed' => $twoFactorConfirmed,
'twoFactorQrCode' => $twoFactorEnabled ? $this->user->twoFactorQrCodeSvg() : null,
'twoFactorSetupKey' => $twoFactorEnabled
? Fortify::currentEncrypter()->decrypt($this->user->two_factor_secret)
: null,
'recoveryCodes' => $twoFactorConfirmed ? $this->user->recoveryCodes() : [],
'mcpEnabled' => app(GeneralSettings::class)->enable_mcp,
'mcpTokens' => $this->user->tokens()->latest()->get(),
]);
return view('livewire.profile');
}

protected function getTableQuery(): Builder
Expand Down
6 changes: 6 additions & 0 deletions lang/en/profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,10 @@
'token_created_notification' => 'Token created.',
'token_revoked_notification' => 'Token revoked.',
],

'tabs' => [
'account' => 'Account',
'preferences' => 'Preferences',
'security' => 'Security',
],
];
6 changes: 6 additions & 0 deletions lang/es/profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@
'per-page-setting' => 'Configuración por página',
'per-page-setting-helper' => 'Determina cuántas páginas deben estar disponibles para los elementos en la página "Mis elementos", por ejemplo.',
'settings' => 'Configuraciones',

'tabs' => [
'account' => 'Cuenta',
'preferences' => 'Preferencias',
'security' => 'Seguridad',
],
];
6 changes: 6 additions & 0 deletions lang/hu/profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@
'settings' => 'Beállítások',
'hide-from-leaderboard' => 'Elrejtés a ranglistáról',
'hide-from-leaderboard-helper' => 'Eltüntet téged a nyilvános ranglistáról.',

'tabs' => [
'account' => 'Fiók',
'preferences' => 'Beállítások',
'security' => 'Biztonság',
],
];
8 changes: 7 additions & 1 deletion lang/it/profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,11 @@
'social-login-description' => 'Qui troverai le tue credenziali d\'accesso sociali utilizzate per accedere al tuo account.',
'per-page-setting' => 'Impostazioni pagina per pagina',
'per-page-setting-helper' => 'Determina quanti elementi saranno disponibili per la pagina "Il mio" per esempio.',
'settings' => 'Impostazioni'
'settings' => 'Impostazioni',

'tabs' => [
'account' => 'Account',
'preferences' => 'Preferenze',
'security' => 'Sicurezza',
],
];
6 changes: 6 additions & 0 deletions lang/nl/profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,10 @@
'hide-from-leaderboard' => 'Verbergen op ranglijst',
'hide-from-leaderboard-helper' => 'Verberg jezelf op de publieke ranglijst.',
'view-public-profile' => 'Bekijk publieke profiel',

'tabs' => [
'account' => 'Account',
'preferences' => 'Voorkeuren',
'security' => 'Beveiliging',
],
];
4 changes: 2 additions & 2 deletions resources/views/components/app.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ function updateTheme() {
<div class="flex mx-auto py-5 lg:space-x-10 h-full px-4 sm:px-6 md:px-8 max-w-[1500px]">
@include('partials.navbar')

{{-- The horizontal padding leaves room for card shadows, which overflow-x-hidden would otherwise clip. --}}
<main class="flex-1 h-full lg:border-l border-gray-200 px-1 lg:pl-5 dark:lg:border-white/10 overflow-x-hidden">
{{-- overflow-x-clip (not hidden) keeps overflow-y visible, so card rings at the bottom aren't cut off. The horizontal padding leaves room for card shadows on the sides. --}}
<main class="flex-1 h-full lg:border-l border-gray-200 px-1 lg:pl-5 dark:lg:border-white/10 overflow-x-clip">
<div class="pb-4">
<ul class="flex items-center space-x-0.5 text-sm font-medium text-gray-600 dark:text-gray-500">
@foreach(array_filter($breadcrumbs) as $breadcrumb)
Expand Down
Loading
Loading