Compare commits

...

13 Commits

Author SHA1 Message Date
Mekan1206
a5bc322170 Enhance MigrationController and ShieldSeeder for improved data migration and role management
- Added new migrators: ModelHasRolesMigrator and OnlinePaymentsMigrator to MigrationController.
- Introduced a test method in MigrationController to facilitate online payments migration.
- Updated ShieldSeeder to include role IDs for better role management and added new roles with specific IDs.
2025-12-21 20:58:10 +05:00
Mekan1206
749208ac97 Add new migrators to MigrationController for enhanced data handling
- Included CardOrdersMigrator, CardPinOrdersMigrator, and VisaMasterSettingsMigrator to the MigrationController.
- Updated the index method to incorporate new migrators for improved migration processes.
2025-12-21 20:00:14 +05:00
Mekan1206
1870583441 Add Laravel Sanctum for API authentication and update routes
- Included `laravel/sanctum` in `composer.json` for lightweight API authentication.
- Updated `User` model to use `HasApiTokens` trait for token management.
- Configured API routing in `bootstrap/app.php`.
- Modified `DatabaseSeeder` to include `ShieldSeeder` and adjusted `FillJsonData` seeder method.
- Changed JSON data path in `ProvincesMigrator` for testing purposes.
- Updated web routes to utilize `MigrationController` for better organization.
2025-12-21 19:50:38 +05:00
Mekan1206
76c05ebe7c Refactor ActivityLogModule and clean up seeders
- Adjusted indentation in ActivityLogModule methods for consistency.
- Simplified ActivityLogRepository class by removing unnecessary lines.
- Updated FillJsonData seeder to streamline the run method.
- Modified various Migrator classes to change JSON data paths for testing and added sequence reset statements for better database integrity.
2025-12-21 19:16:26 +05:00
Mekan1206
515731003c Remove activity log migration files and update FillJsonData seeder to include ActionEventsMigrator. Clean up LoanOrdersMigrator comments for clarity. 2025-12-21 18:57:21 +05:00
Mekan1206
a9c7ec6b80 Remove pxlrbt/filament-activity-log dependency from composer.json and update composer.lock. Enhance LoginController validation by adding a rule to exclude a specific username. Minor adjustments in migration files for activity log to improve code organization. 2025-12-21 17:51:38 +05:00
Mekan1206
4038d47582 add composer require spatie/laravel-activitylog 2025-12-21 06:42:41 +05:00
Mekan1206
326987d6de Add phone or username placeholder in login view and update Turkish translations
- Updated the login view to include a placeholder for phone or username input.
- Added a new Turkish translation for the phone or username placeholder to enhance user guidance.
2025-12-21 06:20:41 +05:00
Mekan1206
f433fc3e41 Remove unused Blade components and templates from the Filament package to streamline the codebase. This includes deleting various components related to forms, notifications, pagination, and widgets, enhancing maintainability and reducing clutter. 2025-12-21 06:15:33 +05:00
Mekan1206
5361c00e7b images better 2025-12-21 05:31:08 +05:00
Mekan1206
5e37bd1a76 Enhance ListRecords pages with tab functionality and default sorting
- Added getTabs method to ListCardPinOrders, ListLoanOrders, and ListLoanOrderMobiles pages to display order statuses for system users.
- Implemented default sorting by 'created_at' in LoanOrdersTable and LoanOrderMobilesTable for improved data organization.
- Updated ManageCards page to ensure proper type declaration for getTitle method.
2025-12-21 05:21:53 +05:00
Mekan1206
5a53b90272 Add default sorting to CardPinOrdersTable by creation date
- Updated CardPinOrdersTable to default sort by 'created_at' in descending order for improved data visibility.
2025-12-21 05:11:21 +05:00
Mekan1206
59548a486f Enhance CardOrder model and SMS functionality
- Added unique ID generation and SMS notification upon CardOrder creation.
- Updated CardOrdersTable to default sort by creation date.
- Implemented logging for SMS sending in SmsRepository for better debugging.
2025-12-21 05:05:28 +05:00
249 changed files with 1996 additions and 15099 deletions

View File

@@ -26,6 +26,7 @@ class CardOrdersTable
->modifyQueryUsing(function (Builder $query) { ->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query); DefaultQueryForResourceIndexRepository::make($query);
}) })
->defaultSort('created_at', 'desc')
->columns([ ->columns([
TextColumn::make('unique_id') TextColumn::make('unique_id')
->label(__('ID')) ->label(__('ID'))

View File

@@ -11,7 +11,7 @@ class ManageCards extends ManageRecords
{ {
protected static string $resource = CardResource::class; protected static string $resource = CardResource::class;
public function getTitle(): string | Htmlable public function getTitle(): string|Htmlable
{ {
return __('My cards'); return __('My cards');
} }

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages; namespace App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages;
use App\Filament\Clusters\Cards\Resources\CardPinOrders\CardPinOrderResource; use App\Filament\Clusters\Cards\Resources\CardPinOrders\CardPinOrderResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListCardPinOrders extends ListRecords class ListCardPinOrders extends ListRecords
{ {
@@ -16,4 +18,23 @@ class ListCardPinOrders extends ListRecords
CreateAction::make(), CreateAction::make(),
]; ];
} }
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
} }

View File

@@ -20,6 +20,7 @@ class CardPinOrdersTable
->modifyQueryUsing(function (Builder $query) { ->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query); DefaultQueryForResourceIndexRepository::make($query);
}) })
->defaultSort('created_at', 'desc')
->columns([ ->columns([
TextColumn::make('id') TextColumn::make('id')
->label('ID'), ->label('ID'),

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Loans\LoanOrders\Pages; namespace App\Filament\Clusters\Loans\LoanOrders\Pages;
use App\Filament\Clusters\Loans\LoanOrders\LoanOrderResource; use App\Filament\Clusters\Loans\LoanOrders\LoanOrderResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListLoanOrders extends ListRecords class ListLoanOrders extends ListRecords
{ {
@@ -16,4 +18,23 @@ class ListLoanOrders extends ListRecords
CreateAction::make(), CreateAction::make(),
]; ];
} }
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
} }

View File

@@ -25,6 +25,7 @@ class LoanOrdersTable
DefaultQueryForResourceIndexRepository::make($query); DefaultQueryForResourceIndexRepository::make($query);
}) })
->defaultSort('created_at', 'desc')
->columns([ ->columns([
TextColumn::make('id') TextColumn::make('id')
->label('ID') ->label('ID')

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages; namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages;
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\LoanOrderMobileResource; use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\LoanOrderMobileResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListLoanOrderMobiles extends ListRecords class ListLoanOrderMobiles extends ListRecords
{ {
@@ -16,4 +18,23 @@ class ListLoanOrderMobiles extends ListRecords
CreateAction::make(), CreateAction::make(),
]; ];
} }
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
} }

View File

@@ -25,6 +25,7 @@ class LoanOrderMobilesTable
DefaultQueryForResourceIndexRepository::make($query); DefaultQueryForResourceIndexRepository::make($query);
}) })
->defaultSort('created_at', 'desc')
->columns([ ->columns([
TextColumn::make('id') TextColumn::make('id')
->label('ID') ->label('ID')

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages; namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages;
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\LoanPaidOffLetterResource; use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\LoanPaidOffLetterResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListLoanPaidOffLetters extends ListRecords class ListLoanPaidOffLetters extends ListRecords
{ {
@@ -16,4 +18,23 @@ class ListLoanPaidOffLetters extends ListRecords
CreateAction::make(), CreateAction::make(),
]; ];
} }
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
} }

View File

@@ -20,6 +20,7 @@ class LoanPaidOffLettersTable
->modifyQueryUsing(function (Builder $query) { ->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query); DefaultQueryForResourceIndexRepository::make($query);
}) })
->defaultSort('created_at', 'desc')
->columns([ ->columns([
TextColumn::make('id') TextColumn::make('id')
->label('ID') ->label('ID')

View File

@@ -2,6 +2,7 @@
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Tables; namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Tables;
use App\Modules\DefaultQueryForResourceIndex\Repositories\DefaultQueryForResourceIndexRepository;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository; use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use App\Modules\Region\Repositories\RegionRepository; use App\Modules\Region\Repositories\RegionRepository;
use Filament\Actions\BulkActionGroup; use Filament\Actions\BulkActionGroup;
@@ -14,6 +15,7 @@ use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\TrashedFilter; use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class VisaMasterPaymentOrdersTable class VisaMasterPaymentOrdersTable
@@ -21,6 +23,9 @@ class VisaMasterPaymentOrdersTable
public static function configure(Table $table): Table public static function configure(Table $table): Table
{ {
return $table return $table
->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query);
})
->defaultSort('created_at', direction: 'desc') ->defaultSort('created_at', direction: 'desc')
->columns([ ->columns([
TextColumn::make('id') TextColumn::make('id')

View File

@@ -32,7 +32,7 @@ class UserForm
->unique(ignoreRecord: true) ->unique(ignoreRecord: true)
->mask('99 99 99 99') ->mask('99 99 99 99')
->prefix('+993') ->prefix('+993')
->dehydrateStateUsing(fn($state) => unMaskTurkmenNumber($state)) ->dehydrateStateUsing(fn ($state) => unMaskTurkmenNumber($state))
->rules([ ->rules([
new PhoneNumberVerificationRule, new PhoneNumberVerificationRule,
]) ])

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Database\Seeders\Migrators\ActionEventsMigrator;
use Database\Seeders\Migrators\BranchUserMigrator;
use Database\Seeders\Migrators\CurrencyRatesMigrator;
use Database\Seeders\Migrators\LoanOrderRequiredDocsMigrator;
use Database\Seeders\Migrators\LoanOrdersMigrator;
use Database\Seeders\Migrators\LoanTypesMigrator;
use Database\Seeders\Migrators\MediaMigrator;
use Database\Seeders\Migrators\ProvincesMigrator;
use Database\Seeders\Migrators\BranchesMigrator;
use Database\Seeders\Migrators\UsersMigrator;
use Database\Seeders\Migrators\CardStatesMigrator;
use Database\Seeders\Migrators\CardTypesMigrator;
use Database\Seeders\Migrators\VisaMasterPaymentOrdersMigrator;
use Database\Seeders\Migrators\VerificationsMigrator;
use Database\Seeders\Migrators\PersonalAccessTokensMigrator;
use Database\Seeders\Migrators\CardOrdersMigrator;
use Database\Seeders\Migrators\VisaMasterSettingsMigrator;
use Database\Seeders\Migrators\CardPinOrdersMigrator;
use Database\Seeders\Migrators\ModelHasRolesMigrator;
use Database\Seeders\Migrators\OnlinePaymentsMigrator;
class MigrationController extends Controller
{
public function index()
{
return $this->test();
$migrators = [
new ActionEventsMigrator(),
new UsersMigrator(),
new ProvincesMigrator(),
new BranchesMigrator(),
new BranchUserMigrator(),
new CardStatesMigrator(),
new CardTypesMigrator(),
new VerificationsMigrator(),
new CurrencyRatesMigrator(),
new LoanOrderRequiredDocsMigrator(),
new PersonalAccessTokensMigrator(),
new LoanTypesMigrator(),
new CardOrdersMigrator(),
new CardPinOrdersMigrator(),
new LoanOrdersMigrator(),
new ModelHasRolesMigrator(),
new VisaMasterPaymentOrdersMigrator(),
new OnlinePaymentsMigrator(),
new MediaMigrator(),
];
foreach ($migrators as $migrator) {
$migrator->migrate();
}
return 'done';
}
public function test()
{
(new OnlinePaymentsMigrator())->migrate();
return 'done';
}
}

View File

@@ -4,12 +4,13 @@ namespace App\Models;
use App\Modules\UserAdjustments\Traits\UserAdjustments; use App\Modules\UserAdjustments\Traits\UserAdjustments;
use Filament\Models\Contracts\FilamentUser; use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasAvatar;
use Filament\Panel; use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Filament\Models\Contracts\HasAvatar;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Date;
use Laravel\Sanctum\HasApiTokens;
/** /**
* @property int $id * @property int $id
@@ -28,6 +29,7 @@ class User extends Authenticatable implements FilamentUser, HasAvatar
use Notifiable; use Notifiable;
use UserAdjustments; use UserAdjustments;
use HasApiTokens;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Modules\ActivityLog;
use App\Modules\Makeable;
use App\Modules\ModuleContract;
class ActivityLogModule implements ModuleContract
{
use Makeable;
/**
* Module is enabled
*/
protected bool $enabled = true;
/**
* Check if is module enabled
*/
public function isEnabled(): bool
{
return $this->enabled;
}
/**
* Disable module
*/
public function disable(): void
{
$this->enabled = false;
}
/**
* Enable module
*/
public function enable(): void
{
$this->enabled = true;
}
/**
* Check if module has a filament resource
*/
public function hasFilamentResource(): bool
{
return false;
}
/**
* Get module composer requirements
*/
public function getComposerRequirements(): array
{
return [];
}
/**
* Get module composer suggestions
*/
public function getComposerSuggestions(): array
{
return [];
}
}

View File

@@ -0,0 +1,5 @@
<?php
namespace App\Modules\ActivityLog\Repositories;
class ActivityLogRepository {}

View File

@@ -14,6 +14,7 @@ use Illuminate\Http\Response;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
class LoginController extends Controller class LoginController extends Controller
{ {
@@ -113,7 +114,7 @@ class LoginController extends Controller
protected function validateLogin(Request $request): void protected function validateLogin(Request $request): void
{ {
$request->validate([ $request->validate([
$this->username() => ['required', 'string', 'max:250'], $this->username() => ['required', 'string', 'max:250', Rule::notIn('65999990', 'ulanyjy_ady')],
'password' => ['required', 'string', 'max:250'], 'password' => ['required', 'string', 'max:250'],
]); ]);
} }

View File

@@ -30,4 +30,5 @@ return [
'go_back' => 'Yza', 'go_back' => 'Yza',
'successfully_changed_phone' => 'Telefon belgiňiz üýtgedildi', 'successfully_changed_phone' => 'Telefon belgiňiz üýtgedildi',
'resend' => 'Täze tassyklaýyş belgi ugratmak', 'resend' => 'Täze tassyklaýyş belgi ugratmak',
'phone_or_username_placeholder' => 'meselem: 65999990 yada ulanyjy_ady',
]; ];

View File

@@ -49,11 +49,12 @@ async function login(event) {
id="username" id="username"
type="text" type="text"
name="username" name="username"
placeholder="+99365999990 {{ __('or') }} {{ __('module.base-auth::base.username') }}" placeholder="65999990 {{ __('or') }} {{ __('module.base-auth::base.username') }}"
autofocus="" autofocus=""
value="{{ old('username') }}" value="{{ old('username') }}"
> >
<span class="text-gray-500 text-xs">{{ __('module.base-auth::base.phone_or_username_placeholder') }}</span>
<span id="username-error-box" class="text-red-500 text-italic error-box"></span> <span id="username-error-box" class="text-red-500 text-italic error-box"></span>
</div> </div>

View File

@@ -109,7 +109,16 @@ class CardOrder extends Model implements BelongsToBranch, HasStatus
parent::boot(); parent::boot();
static::creating(LoanOrderRepository::creating()); static::creating(LoanOrderRepository::creating());
static::created(LoanOrderRepository::created());
static::created(function ($model) {
$uniqueId = LoanOrderRepository::generateUniqueId($model);
$model->update(['unique_id' => $uniqueId]);
sendSMS(
$model->phone,
__('module.card-order::base.card_order_created', ['order_id' => $uniqueId])
);
});
} }
/** /**

View File

@@ -0,0 +1,5 @@
<?php
return [
'card_order_created' => 'Kart sargydyňyz :order_id belgi bilen hasaba alyndy. Sargydy tassyklamak üçin operatorymyz habarlaşar.',
];

View File

@@ -47,4 +47,3 @@ class OnlinePaymentPolicy
return $user->can('ForceDelete:OnlinePayment'); return $user->can('ForceDelete:OnlinePayment');
} }
} }

View File

@@ -15,6 +15,8 @@ class SmsRepository
public static function sendSMS(string|int $phone, string|int $message): mixed public static function sendSMS(string|int $phone, string|int $message): mixed
{ {
if (app()->environment('local')) { if (app()->environment('local')) {
info('Sending SMS to '.$phone.' with message: '.$message);
return true; return true;
} }

View File

@@ -37,7 +37,7 @@ use Spatie\MediaLibrary\InteractsWithMedia;
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at * @property \Illuminate\Support\Carbon|null $deleted_at
*/ */
class VisaMasterPaymentOrder extends Model implements HasMedia, BelongsToBranch class VisaMasterPaymentOrder extends Model implements BelongsToBranch, HasMedia
{ {
use InteractsWithMedia; use InteractsWithMedia;
use SoftDeletes; use SoftDeletes;

View File

@@ -47,4 +47,3 @@ class VisaMasterPaymentOrderItemPolicy
return $user->can('ForceDelete:VisaMasterPaymentOrderItem'); return $user->can('ForceDelete:VisaMasterPaymentOrderItem');
} }
} }

View File

@@ -47,4 +47,3 @@ class VisaMasterPaymentOrderPolicy
return $user->can('ForceDelete:VisaMasterPaymentOrder'); return $user->can('ForceDelete:VisaMasterPaymentOrder');
} }
} }

View File

@@ -47,4 +47,3 @@ class VisaMasterSettingsPolicy
return $user->can('ForceDelete:VisaMasterSettings'); return $user->can('ForceDelete:VisaMasterSettings');
} }
} }

View File

@@ -16,6 +16,7 @@ use Filament\Panel;
use Filament\PanelProvider; use Filament\PanelProvider;
use Filament\Support\Colors\Color; use Filament\Support\Colors\Color;
use Filament\Widgets\AccountWidget; use Filament\Widgets\AccountWidget;
use Filament\Widgets\FilamentInfoWidget;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies; use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
@@ -29,8 +30,6 @@ class WorkPanelProvider extends PanelProvider
{ {
public function panel(Panel $panel): Panel public function panel(Panel $panel): Panel
{ {
// #content\.form-actions > div
return $panel return $panel
->default() ->default()
->id('work') ->id('work')
@@ -47,6 +46,7 @@ class WorkPanelProvider extends PanelProvider
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets') ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
->widgets([ ->widgets([
AccountWidget::class, AccountWidget::class,
FilamentInfoWidget::class,
]) ])
->middleware([ ->middleware([
EncryptCookies::class, EncryptCookies::class,
@@ -75,6 +75,7 @@ class WorkPanelProvider extends PanelProvider
]), ]),
FilamentUpload::make(), FilamentUpload::make(),
]) ])
->authMiddleware([ ->authMiddleware([
Authenticate::class, Authenticate::class,

View File

@@ -7,6 +7,7 @@ use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__)) return Application::configure(basePath: dirname(__DIR__))
->withRouting( ->withRouting(
web: __DIR__.'/../routes/web.php', web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php', commands: __DIR__.'/../routes/console.php',
health: '/up', health: '/up',
) )

View File

@@ -15,11 +15,13 @@
"halaxa/json-machine": "^1.2", "halaxa/json-machine": "^1.2",
"joaopaulolndev/filament-edit-profile": "^2.0", "joaopaulolndev/filament-edit-profile": "^2.0",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.10.1", "laravel/tinker": "^2.10.1",
"laravel/ui": "^4.6", "laravel/ui": "^4.6",
"mpdf/mpdf": "^8.2", "mpdf/mpdf": "^8.2",
"phpoffice/phpword": "dev-master", "phpoffice/phpword": "dev-master",
"ralphjsmit/laravel-filament-upload": "^1.1", "ralphjsmit/laravel-filament-upload": "^1.1",
"spatie/laravel-activitylog": "^4.10",
"spatie/laravel-medialibrary": "^11.17", "spatie/laravel-medialibrary": "^11.17",
"spatie/laravel-translatable": "^6.11", "spatie/laravel-translatable": "^6.11",
"stevebauman/location": "^7.6" "stevebauman/location": "^7.6"

156
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "28304e2033c8e05f63b010bb15ecec8e", "content-hash": "018635a80495002683ac3d2f58dd6eaf",
"packages": [ "packages": [
{ {
"name": "abdulmajeed-jamaan/filament-translatable-tabs", "name": "abdulmajeed-jamaan/filament-translatable-tabs",
@@ -3355,6 +3355,69 @@
}, },
"time": "2025-11-21T20:52:52+00:00" "time": "2025-11-21T20:52:52+00:00"
}, },
{
"name": "laravel/sanctum",
"version": "v4.2.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
"reference": "f5fb373be39a246c74a060f2cf2ae2c2145b3664"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/f5fb373be39a246c74a060f2cf2ae2c2145b3664",
"reference": "f5fb373be39a246c74a060f2cf2ae2c2145b3664",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^11.0|^12.0",
"illuminate/contracts": "^11.0|^12.0",
"illuminate/database": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"php": "^8.2",
"symfony/console": "^7.0"
},
"require-dev": {
"mockery/mockery": "^1.6",
"orchestra/testbench": "^9.15|^10.8",
"phpstan/phpstan": "^1.10"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Sanctum\\SanctumServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Sanctum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.",
"keywords": [
"auth",
"laravel",
"sanctum"
],
"support": {
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
"time": "2025-11-21T13:59:03+00:00"
},
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v2.0.7", "version": "v2.0.7",
@@ -7358,6 +7421,97 @@
], ],
"time": "2024-05-17T09:06:10+00:00" "time": "2024-05-17T09:06:10+00:00"
}, },
{
"name": "spatie/laravel-activitylog",
"version": "4.10.2",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-activitylog.git",
"reference": "bb879775d487438ed9a99e64f09086b608990c10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-activitylog/zipball/bb879775d487438ed9a99e64f09086b608990c10",
"reference": "bb879775d487438ed9a99e64f09086b608990c10",
"shasum": ""
},
"require": {
"illuminate/config": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
"illuminate/database": "^8.69 || ^9.27 || ^10.0 || ^11.0 || ^12.0",
"illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
"php": "^8.1",
"spatie/laravel-package-tools": "^1.6.3"
},
"require-dev": {
"ext-json": "*",
"orchestra/testbench": "^6.23 || ^7.0 || ^8.0 || ^9.0 || ^10.0",
"pestphp/pest": "^1.20 || ^2.0 || ^3.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Activitylog\\ActivitylogServiceProvider"
]
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Spatie\\Activitylog\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
},
{
"name": "Sebastian De Deyne",
"email": "sebastian@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
},
{
"name": "Tom Witkowski",
"email": "dev.gummibeer@gmail.com",
"homepage": "https://gummibeer.de",
"role": "Developer"
}
],
"description": "A very simple activity logger to monitor the users of your website or application",
"homepage": "https://github.com/spatie/activitylog",
"keywords": [
"activity",
"laravel",
"log",
"spatie",
"user"
],
"support": {
"issues": "https://github.com/spatie/laravel-activitylog/issues",
"source": "https://github.com/spatie/laravel-activitylog/tree/4.10.2"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2025-06-15T06:59:49+00:00"
},
{ {
"name": "spatie/laravel-medialibrary", "name": "spatie/laravel-medialibrary",
"version": "11.17.7", "version": "11.17.7",

52
config/activitylog.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
return [
/*
* If set to false, no activities will be saved to the database.
*/
'enabled' => env('ACTIVITY_LOGGER_ENABLED', true),
/*
* When the clean-command is executed, all recording activities older than
* the number of days specified here will be deleted.
*/
'delete_records_older_than_days' => 365,
/*
* If no log name is passed to the activity() helper
* we use this default log name.
*/
'default_log_name' => 'default',
/*
* You can specify an auth driver here that gets user models.
* If this is null we'll use the current Laravel auth driver.
*/
'default_auth_driver' => null,
/*
* If set to true, the subject returns soft deleted models.
*/
'subject_returns_soft_deleted_models' => false,
/*
* This model will be used to log activity.
* It should implement the Spatie\Activitylog\Contracts\Activity interface
* and extend Illuminate\Database\Eloquent\Model.
*/
'activity_model' => \Spatie\Activitylog\Models\Activity::class,
/*
* This is the name of the table that will be created by the migration and
* used by the Activity model shipped with this package.
*/
'table_name' => env('ACTIVITY_LOGGER_TABLE_NAME', 'activity_log'),
/*
* This is the database connection that will be used by the migration and
* the Activity model shipped with this package. In case it's not set
* Laravel's database.default will be used instead.
*/
'database_connection' => env('ACTIVITY_LOGGER_DB_CONNECTION'),
];

84
config/sanctum.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort(),
// Sanctum::currentRequestHost(),
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of numerous
| security scanning initiatives maintained by open source platforms
| that notify developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
],
];

View File

@@ -0,0 +1,47 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('action_events', function (Blueprint $table) {
$table->id();
$table->string('batch_id')->nullable();
$table->unsignedBigInteger('user_id')->nullable()->index();
$table->string('name')->index();
$table->string('actionable_type')->nullable()->index();
$table->unsignedBigInteger('actionable_id')->nullable()->index();
$table->string('target_type')->nullable()->index();
$table->unsignedBigInteger('target_id')->nullable()->index();
$table->string('model_type')->nullable()->index();
$table->unsignedBigInteger('model_id')->nullable()->index();
$table->text('fields')->nullable();
$table->string('status')->index()->default('finished');
$table->text('exception')->nullable();
$table->json('original')->nullable();
$table->json('changes')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('action_events');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->text('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable()->index();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_access_tokens');
}
};

View File

@@ -13,9 +13,7 @@ class DatabaseSeeder extends Seeder
public function run(): void public function run(): void
{ {
$this->call([ $this->call([
FillJsonData::class, ShieldSeeder::class,
// UsersTableSeeder::class,
// ShieldSeeder::class,
]); ]);
} }
} }

View File

@@ -11,7 +11,7 @@ class FillJsonData extends Seeder
*/ */
public function run(): void public function run(): void
{ {
$this->seedVisaMasterPaymentOrders();
} }
protected function seedUsers(): void protected function seedUsers(): void
@@ -68,4 +68,19 @@ class FillJsonData extends Seeder
{ {
(new Migrators\VisaMasterPaymentOrdersMigrator)->migrate(); (new Migrators\VisaMasterPaymentOrdersMigrator)->migrate();
} }
protected function seedActionEvents(): void
{
(new Migrators\ActionEventsMigrator)->migrate();
}
protected function seedBranchUser(): void
{
(new Migrators\BranchUserMigrator)->migrate();
}
protected function seedCurrencyRates(): void
{
(new Migrators\CurrencyRatesMigrator)->migrate();
}
} }

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class ActionEventsMigrator
{
public function migrate(): void
{
DB::table('action_events')->truncate();
$path = database_path('data/tested/action_events.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('action_events')->insert((array) $item);
}
DB::statement("SELECT setval('action_events_id_seq', (SELECT MAX(id) from action_events));");
DB::statement("SELECT nextval('action_events_id_seq');");
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class BranchUserMigrator
{
public function migrate(): void
{
DB::table('branch_user')->truncate();
$path = database_path('data/tested/branch_user.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('branch_user')->insert((array) $item);
DB::statement("SELECT setval('branch_user_id_seq', (SELECT MAX(id) from branch_user));");
DB::statement("SELECT nextval('branch_user_id_seq');");
}
}
}

View File

@@ -11,7 +11,7 @@ class BranchesMigrator
{ {
DB::table('branches')->truncate(); DB::table('branches')->truncate();
$path = database_path('data/nurmuhammetsdb/branches.json'); $path = database_path('data/tested/branches.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -19,5 +19,8 @@ class BranchesMigrator
DB::table('branches') DB::table('branches')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('branches_id_seq', (SELECT MAX(id) from branches));");
DB::statement("SELECT nextval('branches_id_seq');");
} }
} }

View File

@@ -11,7 +11,7 @@ class CardOrdersMigrator
{ {
DB::table('card_orders')->truncate(); DB::table('card_orders')->truncate();
$path = database_path('data/nurmuhammetsdb/card_orders.json'); $path = database_path('data/tested/card_orders.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -19,5 +19,8 @@ class CardOrdersMigrator
DB::table('card_orders') DB::table('card_orders')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('card_orders_id_seq', (SELECT MAX(id) from card_orders));");
DB::statement("SELECT nextval('card_orders_id_seq');");
} }
} }

View File

@@ -11,7 +11,7 @@ class CardPinOrdersMigrator
{ {
DB::table('card_pin_orders')->truncate(); DB::table('card_pin_orders')->truncate();
$path = database_path('data/nurmuhammetsdb/card_pins.json'); $path = database_path('data/tested/card_pins.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -25,5 +25,8 @@ class CardPinOrdersMigrator
DB::table('card_pin_orders') DB::table('card_pin_orders')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('card_pin_orders_id_seq', (SELECT MAX(id) from card_pin_orders));");
DB::statement("SELECT nextval('card_pin_orders_id_seq');");
} }
} }

View File

@@ -11,7 +11,7 @@ class CardStatesMigrator
{ {
DB::table('card_states')->truncate(); DB::table('card_states')->truncate();
$path = database_path('data/nurmuhammetsdb/card_states.json'); $path = database_path('data/tested/card_states.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -19,5 +19,8 @@ class CardStatesMigrator
DB::table('card_states') DB::table('card_states')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('card_states_id_seq', (SELECT MAX(id) from card_states));");
DB::statement("SELECT nextval('card_states_id_seq');");
} }
} }

View File

@@ -11,7 +11,7 @@ class CardTypesMigrator
{ {
DB::table('card_types')->truncate(); DB::table('card_types')->truncate();
$path = database_path('data/nurmuhammetsdb/card_types.json'); $path = database_path('data/tested/card_types.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -19,5 +19,8 @@ class CardTypesMigrator
DB::table('card_types') DB::table('card_types')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('card_types_id_seq', (SELECT MAX(id) from card_types));");
DB::statement("SELECT nextval('card_types_id_seq');");
} }
} }

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class CurrencyRatesMigrator
{
public function migrate(): void
{
DB::table('currency_rates')->truncate();
$path = database_path('data/tested/currency_rates.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('currency_rates')->insert((array) $item);
}
DB::statement("SELECT setval('currency_rates_id_seq', (SELECT MAX(id) from currency_rates));");
DB::statement("SELECT nextval('currency_rates_id_seq');");
}
}

View File

@@ -11,7 +11,7 @@ class LoanOrderRequiredDocsMigrator
{ {
DB::table('loan_order_required_docs')->truncate(); DB::table('loan_order_required_docs')->truncate();
$path = database_path('data/nurmuhammetsdb/loan_order_required_docs.json'); $path = database_path('data/tested/loan_order_required_docs.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -19,5 +19,8 @@ class LoanOrderRequiredDocsMigrator
DB::table('loan_order_required_docs') DB::table('loan_order_required_docs')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('loan_order_required_docs_id_seq', (SELECT MAX(id) from loan_order_required_docs));");
DB::statement("SELECT nextval('loan_order_required_docs_id_seq');");
} }
} }

View File

@@ -2,22 +2,16 @@
namespace Database\Seeders\Migrators; namespace Database\Seeders\Migrators;
use JsonMachine\JsonMachine;
use JsonMachine\Items;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File; use JsonMachine\Items;
use Illuminate\Support\LazyCollection;
use Cerbero\LazyJson\LazyJson;
class LoanOrdersMigrator class LoanOrdersMigrator
{ {
public function migrate(): void public function migrate(): void
{ {
// Running on seeder file, may not work.
DB::table('loan_orders')->truncate(); DB::table('loan_orders')->truncate();
$path = database_path('data/nurmuhammetsdb/loan_orders.json'); $path = database_path('data/tested/loan_orders.json');
$items = Items::fromFile($path); $items = Items::fromFile($path);
@@ -28,5 +22,8 @@ class LoanOrdersMigrator
DB::table('loan_orders')->insert((array) $item); DB::table('loan_orders')->insert((array) $item);
} }
DB::statement("SELECT setval('loan_orders_id_seq', (SELECT MAX(id) from loan_orders));");
DB::statement("SELECT nextval('loan_orders_id_seq');");
} }
} }

View File

@@ -11,7 +11,7 @@ class LoanTypesMigrator
{ {
DB::table('loan_types')->truncate(); DB::table('loan_types')->truncate();
$path = database_path('data/nurmuhammetsdb/loan_types.json'); $path = database_path('data/tested/loan_types.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -19,5 +19,8 @@ class LoanTypesMigrator
DB::table('loan_types') DB::table('loan_types')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('loan_types_id_seq', (SELECT MAX(id) from loan_types));");
DB::statement("SELECT nextval('loan_types_id_seq');");
} }
} }

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class MediaMigrator
{
public function migrate(): void
{
DB::table('media')->truncate();
$path = database_path('data/tested/media.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('media')->insert((array) $item);
}
DB::statement("SELECT setval('media_id_seq', (SELECT MAX(id) from media));");
DB::statement("SELECT nextval('media_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class ModelHasRolesMigrator
{
public function migrate(): void
{
DB::table('model_has_roles')->truncate();
$path = database_path('data/tested/model_has_roles.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('model_has_roles')
->insert($data);
}
DB::statement("SELECT setval('model_has_roles_id_seq', (SELECT MAX(id) from model_has_roles));");
DB::statement("SELECT nextval('model_has_roles_id_seq');");
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Database\Seeders\Migrators;
use App\Modules\CardOrder\Models\CardOrder;
use App\Modules\CardPinOrder\Models\CardPinOrder;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class OnlinePaymentsMigrator
{
public function migrate(): void
{
DB::table('online_payments')->truncate();
$path = database_path('data/tested/online_payment_histories.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
if ($data['online_paymantable_type']) {
if ($data['online_paymantable_type'] == 'App\Models\Order\Card\Requisite\CardRequisite') {
continue;
}
$data['online_paymantable_type'] = match ($data['online_paymantable_type']) {
'App\Models\Order\Card\CardOrder' => CardOrder::class,
'App\Models\Order\Card\CardPin\CardPin' => CardPinOrder::class,
// 'App\Modules\SberPaymentOrder\Models\SberPaymentOrder' => SberPaymentOrder::class,
'App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder' => VisaMasterPaymentOrder::class,
'\App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder' => VisaMasterPaymentOrder::class,
};
}
DB::table('online_payments')
->insert($data);
}
DB::statement("SELECT setval('online_payments_id_seq', (SELECT MAX(id) from online_payments));");
DB::statement("SELECT nextval('online_payments_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class PersonalAccessTokensMigrator
{
public function migrate(): void
{
DB::table('personal_access_tokens')->truncate();
$path = database_path('data/tested/personal_access_tokens.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('personal_access_tokens')
->insert($data);
}
DB::statement("SELECT setval('personal_access_tokens_id_seq', (SELECT MAX(id) from personal_access_tokens));");
DB::statement("SELECT nextval('personal_access_tokens_id_seq');");
}
}

View File

@@ -11,7 +11,7 @@ class ProvincesMigrator
{ {
DB::table('provinces')->truncate(); DB::table('provinces')->truncate();
$path = database_path('data/nurmuhammetsdb/provinces.json'); $path = database_path('data/tested/provinces.json');
$rawData = File::json($path); $rawData = File::json($path);
@@ -19,5 +19,8 @@ class ProvincesMigrator
DB::table('provinces') DB::table('provinces')
->insert($data); ->insert($data);
} }
DB::statement("SELECT setval('provinces_id_seq', (SELECT MAX(id) from provinces));");
DB::statement("SELECT nextval('provinces_id_seq');");
} }
} }

View File

@@ -39,6 +39,9 @@ class UsersMigrator
'active' => $user['active'], 'active' => $user['active'],
]); ]);
} }
DB::statement("SELECT setval('users_id_seq', (SELECT MAX(id) from users));");
DB::statement("SELECT nextval('users_id_seq');");
} }
protected function extractFirstName(string $name): string protected function extractFirstName(string $name): string

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class VerificationsMigrator
{
public function migrate(): void
{
DB::table('verifications')->truncate();
$path = database_path('data/tested/verifications.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('verifications')
->insert($data);
}
DB::statement("SELECT setval('verifications_id_seq', (SELECT MAX(id) from verifications));");
DB::statement("SELECT nextval('verifications_id_seq');");
}
}

View File

@@ -3,7 +3,6 @@
namespace Database\Seeders\Migrators; namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use JsonMachine\JsonMachine;
use JsonMachine\Items; use JsonMachine\Items;
class VisaMasterPaymentOrdersMigrator class VisaMasterPaymentOrdersMigrator
@@ -21,7 +20,6 @@ class VisaMasterPaymentOrdersMigrator
continue; continue;
} }
$sender_datas = json_decode($item->sender_datas); $sender_datas = json_decode($item->sender_datas);
$payment_reciever = json_decode($item->payment_reciever); $payment_reciever = json_decode($item->payment_reciever);
@@ -62,5 +60,8 @@ class VisaMasterPaymentOrdersMigrator
'deleted_at' => $item->deleted_at, 'deleted_at' => $item->deleted_at,
]); ]);
} }
DB::statement("SELECT setval('visa_master_payment_orders_id_seq', (SELECT MAX(id) from visa_master_payment_orders));");
DB::statement("SELECT nextval('visa_master_payment_orders_id_seq');");
} }
} }

View File

@@ -13,7 +13,7 @@ class ShieldSeeder extends Seeder
{ {
app()[PermissionRegistrar::class]->forgetCachedPermissions(); app()[PermissionRegistrar::class]->forgetCachedPermissions();
$rolesWithPermissions = '[{"name":"super_admin","guard_name":"web","permissions":["ViewAny:Role","View:Role","Create:Role","Update:Role","Delete:Role","Restore:Role","ForceDelete:Role","ForceDeleteAny:Role","RestoreAny:Role","Replicate:Role","Reorder:Role"]}]'; $rolesWithPermissions = '[{"id":2,"name":"super_admin","guard_name":"web","permissions":["ViewAny:Role","View:Role","Create:Role","Update:Role","Delete:Role","Restore:Role","ForceDelete:Role","ForceDeleteAny:Role","RestoreAny:Role","Replicate:Role","Reorder:Role"]}]';
$directPermissions = '[]'; $directPermissions = '[]';
static::makeRolesWithPermissions($rolesWithPermissions); static::makeRolesWithPermissions($rolesWithPermissions);
@@ -32,26 +32,32 @@ class ShieldSeeder extends Seeder
$additionalRoles = collect([ $additionalRoles = collect([
[ [
'id' => 3,
'name' => 'admin', 'name' => 'admin',
'guard_name' => 'web', 'guard_name' => 'web',
], ],
[ [
'id' => 4,
'name' => 'operator', 'name' => 'operator',
'guard_name' => 'web', 'guard_name' => 'web',
], ],
[ [
'id' => 10,
'name' => 'operator_card', 'name' => 'operator_card',
'guard_name' => 'web', 'guard_name' => 'web',
], ],
[ [
'id' => 11,
'name' => 'operator_loan', 'name' => 'operator_loan',
'guard_name' => 'web', 'guard_name' => 'web',
], ],
[ [
'id' => 12,
'name' => 'client', 'name' => 'client',
'guard_name' => 'web', 'guard_name' => 'web',
], ],
[ [
'id' => 6,
'name' => 'currency_maintainer', 'name' => 'currency_maintainer',
'guard_name' => 'web', 'guard_name' => 'web',
], ],
@@ -74,6 +80,7 @@ class ShieldSeeder extends Seeder
foreach ($rolePlusPermissions as $rolePlusPermission) { foreach ($rolePlusPermissions as $rolePlusPermission) {
$role = $roleModel::firstOrCreate([ $role = $roleModel::firstOrCreate([
'id' => $rolePlusPermission['id'],
'name' => $rolePlusPermission['name'], 'name' => $rolePlusPermission['name'],
'guard_name' => $rolePlusPermission['guard_name'], 'guard_name' => $rolePlusPermission['guard_name'],
]); ]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"resources/css/filament/work/theme.css": { "resources/css/filament/work/theme.css": {
"file": "assets/theme-N6DF4L1Y.css", "file": "assets/theme-D6od5FeK.css",
"src": "resources/css/filament/work/theme.css", "src": "resources/css/filament/work/theme.css",
"isEntry": true, "isEntry": true,
"name": "theme", "name": "theme",

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
{"/livewire.js":"df3a17f2"} {"/livewire.js":"0f6341c0"}

View File

@@ -16,18 +16,52 @@
> >
@foreach ($media as $item) @foreach ($media as $item)
@if (str_starts_with($item->mime_type, 'image/')) @if (str_starts_with($item->mime_type, 'image/'))
<div class="flex flex-col items-center gap-2"> <div class="flex items-center gap-3 rounded-xl border border-gray-200 bg-white p-2 shadow-sm dark:border-white/10 dark:bg-white/5">
<img <div class="flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-gray-100 dark:bg-white/10 overflow-hidden">
src="{{ $entry->getMediaUrl($item, $media->count() > 1 ? 'thumb' : null) }}" <img
class="w-full rounded-lg" src="{{ $entry->getMediaUrl($item, $media->count() > 1 ? 'thumb' : null) }}"
/> class="w-full h-full object-cover"
<button />
type="button" </div>
class="text-sm font-medium text-primary-600 decoration-2 center underline focus:outline-none dark:text-primary-500"
@click="$dispatch('open-modal', { id: 'preview-image-{{ $item->id }}' })" <div class="flex-grow overflow-hidden">
> <p class="truncate text-sm font-medium text-gray-950 dark:text-white" title="{{ $item->name }}">
{{ __('Watch Full') }} {{ $item->name }}
</button> </p>
<p class="text-xs text-gray-500 dark:text-gray-400">
{{ $item->human_readable_size }}
<span class="text-gray-300 dark:text-gray-600 px-1"></span>
<span class="uppercase">{{ $item->extension }}</span>
</p>
</div>
<div class="flex shrink-0 items-center gap-2 pr-2">
<button
type="button"
class="flex items-center justify-center h-8 w-8 rounded-full hover:bg-gray-50 dark:hover:bg-white/10 text-gray-500 hover:text-primary-600 dark:text-gray-400 dark:hover:text-primary-500 transition-colors"
@click="$dispatch('open-modal', { id: 'preview-image-{{ $item->id }}' })"
title="{{ __('View') }}"
>
<x-filament::icon
icon="heroicon-m-eye"
class="h-5 w-5"
/>
</button>
@if ($entry->isDownloadable())
<a
href="{{ $entry->getMediaUrl($item) }}"
download
class="flex items-center justify-center h-8 w-8 rounded-full hover:bg-gray-50 dark:hover:bg-white/10 text-gray-500 hover:text-primary-600 dark:text-gray-400 dark:hover:text-primary-500 transition-colors"
title="{{ __('Download') }}"
>
<x-filament::icon
icon="heroicon-m-arrow-down-tray"
class="h-5 w-5"
/>
</a>
@endif
</div>
</div> </div>
<x-filament::modal id="preview-image-{{ $item->id }}" width="5xl" :close-button="true"> <x-filament::modal id="preview-image-{{ $item->id }}" width="5xl" :close-button="true">
@@ -37,7 +71,7 @@
<img <img
src="{{ $entry->getMediaUrl($item) }}" src="{{ $entry->getMediaUrl($item) }}"
class="w-full h-full object-contain" class="max-h-[400px] w-fit"
/> />
</x-filament::modal> </x-filament::modal>
@else @else

View File

@@ -1,67 +0,0 @@
@php
use Filament\Actions\View\ActionsRenderHook;
use Filament\Support\Facades\FilamentView;
$actionModalAlignment = $action->getModalAlignment();
$actionIsModalAutofocused = $action->isModalAutofocused();
$actionHasModalCloseButton = $action->hasModalCloseButton();
$actionIsModalClosedByClickingAway = $action->isModalClosedByClickingAway();
$actionIsModalClosedByEscaping = $action->isModalClosedByEscaping();
$actionModalDescription = $action->getModalDescription();
$actionExtraModalWindowAttributeBag = $action->getExtraModalWindowAttributeBag();
$actionModalFooterActions = $action->getVisibleModalFooterActions();
$actionModalFooterActionsAlignment = $action->getModalFooterActionsAlignment();
$actionModalHeading = $action->getModalHeading();
$actionModalIcon = $action->getModalIcon();
$actionModalIconColor = $action->getModalIconColor();
$actionModalId = "fi-{$this->getId()}-action-{$action->getNestingIndex()}";
$actionIsModalSlideOver = $action->isModalSlideOver();
$actionIsModalFooterSticky = $action->isModalFooterSticky();
$actionIsModalHeaderSticky = $action->isModalHeaderSticky();
$actionModalWidth = $action->getModalWidth();
$actionLivewireCallMountedActionName = $action->hasFormWrapper() ? $action->getLivewireCallMountedActionName() : null;
$actionModalWireKey = "{$this->getId()}.actions.{$action->getName()}.modal";
@endphp
<x-filament::modal
:alignment="$actionModalAlignment"
:autofocus="$actionIsModalAutofocused"
:close-button="$actionHasModalCloseButton"
:close-by-clicking-away="$actionIsModalClosedByClickingAway"
:close-by-escaping="$actionIsModalClosedByEscaping"
:description="$actionModalDescription"
:extra-modal-window-attribute-bag="$actionExtraModalWindowAttributeBag"
:footer-actions="$actionModalFooterActions"
:footer-actions-alignment="$actionModalFooterActionsAlignment"
:heading="$actionModalHeading"
:icon="$actionModalIcon"
:icon-color="$actionModalIconColor"
:id="$actionModalId"
:slide-over="$actionIsModalSlideOver"
:sticky-footer="$actionIsModalFooterSticky"
:sticky-header="$actionIsModalHeaderSticky"
:width="$actionModalWidth"
:wire:key="$actionModalWireKey"
:wire:submit.prevent="$actionLivewireCallMountedActionName"
:x-on:modal-closed="'if ($event.detail.id === ' . \Illuminate\Support\Js::from($actionModalId) . ') $wire.unmountAction(false)'"
>
{{ FilamentView::renderHook(ActionsRenderHook::MODAL_CUSTOM_CONTENT_BEFORE, scopes: static::class, data: ['action' => $action]) }}
{{ $action->getModalContent() }}
{{ FilamentView::renderHook(ActionsRenderHook::MODAL_CUSTOM_CONTENT_AFTER, scopes: static::class, data: ['action' => $action]) }}
@if ($this->mountedActionHasSchema(mountedAction: $action))
{{ FilamentView::renderHook(ActionsRenderHook::MODAL_SCHEMA_BEFORE, scopes: static::class, data: ['action' => $action]) }}
{{ $this->getMountedActionSchema(mountedAction: $action) }}
{{ FilamentView::renderHook(ActionsRenderHook::MODAL_SCHEMA_AFTER, scopes: static::class, data: ['action' => $action]) }}
@endif
{{ FilamentView::renderHook(ActionsRenderHook::MODAL_CUSTOM_CONTENT_FOOTER_BEFORE, scopes: static::class, data: ['action' => $action]) }}
{{ $action->getModalContentFooter() }}
{{ FilamentView::renderHook(ActionsRenderHook::MODAL_CUSTOM_CONTENT_FOOTER_AFTER, scopes: static::class, data: ['action' => $action]) }}
</x-filament::modal>

View File

@@ -1,59 +0,0 @@
@props([
'actions' => [],
'badge' => null,
'badgeColor' => null,
'button' => false,
'color' => null,
'dropdownMaxHeight' => null,
'dropdownOffset' => null,
'dropdownPlacement' => null,
'dropdownWidth' => null,
'group' => null,
'icon' => null,
'iconSize' => null,
'iconButton' => false,
'label' => null,
'link' => false,
'size' => null,
'tooltip' => null,
'triggerView' => null,
'view' => null,
])
@php
$group ??= \Filament\Actions\ActionGroup::make($actions)
->badgeColor($badgeColor)
->color($color)
->dropdownMaxHeight($dropdownMaxHeight)
->dropdownOffset($dropdownOffset)
->dropdownPlacement($dropdownPlacement)
->dropdownWidth($dropdownWidth)
->icon($icon)
->iconSize($iconSize)
->label($label)
->size($size)
->tooltip($tooltip)
->triggerView($triggerView)
->view($view);
$badge === true
? $group->badge()
: $group->badge($badge);
if ($button) {
$group
->button()
->iconPosition($attributes->get('iconPosition') ?? $attributes->get('icon-position'))
->outlined($attributes->get('outlined') ?? false);
}
if ($iconButton) {
$group->iconButton();
}
if ($link) {
$group->link();
}
@endphp
{{ $group }}

View File

@@ -1,19 +0,0 @@
@if ($this instanceof \Filament\Actions\Contracts\HasActions && (! $this->hasActionsModalRendered))
<div
wire:partial="action-modals"
x-data="filamentActionModals({
livewireId: @js($this->getId()),
})"
style="height: 0"
>
@foreach ($this->getMountedActions() as $action)
@if ((! $loop->last) || $this->mountedActionShouldOpenModal())
{{ $action->toModalHtmlable() }}
@endif
@endforeach
</div>
@php
$this->hasActionsModalRendered = true;
@endphp
@endif

View File

@@ -1,7 +0,0 @@
<x-filament-panels::page>
@foreach ($this->getRegisteredCustomProfileComponents() as $component)
@unless(is_null($component))
@livewire($component)
@endunless
@endforeach
</x-filament-panels::page>

View File

@@ -1,54 +0,0 @@
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<div>
<div class="">
<div class="text-sm text-gray-600 fi-in-entry">
<div class="text-sm text-gray-600 dark:text-gray-400">
{{ __('filament-edit-profile::default.browser_sessions_content') }}
</div>
@if (count($data) > 0)
<div class="fi-in-entry">
@foreach ($data as $session)
<div class="fi-sc fi-inline fi-sc-has-gap">
<div>
@if ($session->device['desktop'])
<x-filament::icon
icon="heroicon-o-computer-desktop"
class="w-8 h-8 text-gray-500 dark:text-gray-400"
/>
@else
<x-filament::icon
icon="heroicon-o-device-phone-mobile"
class="w-8 h-8 text-gray-500 dark:text-gray-400"
/>
@endif
</div>
<div class="ms-3">
<div class="text-sm text-gray-600 dark:text-gray-400">
{{ $session->device['platform'] ? $session->device['platform'] : __('Unknown') }} - {{ $session->device['browser'] ? $session->device['browser'] : __('Unknown') }}
</div>
<div>
<div class="text-xs text-gray-500">
{{ $session->ip_address }},
@if ($session->is_current_device)
<span class="font-semibold text-primary-500">{{ __('filament-edit-profile::default.browser_sessions_device') }}</span>
@else
{{ __('filament-edit-profile::default.browser_sessions_last_active') }} {{ $session->last_active }}
@endif
</div>
</div>
</div>
</div>
@endforeach
</div>
@endif
</div>
</div>
</div>
</x-dynamic-component>

View File

@@ -1,12 +0,0 @@
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<div x-data="{ state: $wire.$entangle('{{ $getStatePath() }}') }">
<div class="text-start">
<div class="text-sm text-gray-600 dark:text-gray-400">
{{ __('filament-edit-profile::default.delete_account_card_description') }}
</div>
</div>
</div>
</x-dynamic-component>

View File

@@ -1,7 +0,0 @@
<div>
<form class="fi-sc-form">
{{ $this->form }}
</form>
<x-filament-actions::modals />
</div>

View File

@@ -1,9 +0,0 @@
<form wire:submit="updateCustomFields" class="fi-sc-form">
{{ $this->form }}
<div class="fi-ac fi-align-end">
<x-filament::button type="submit">
{{ __('filament-edit-profile::default.save') }}
</x-filament::button>
</div>
</form>

View File

@@ -1,7 +0,0 @@
<div>
<form class="fi-sc-form">
{{ $this->form }}
</form>
<x-filament-actions::modals />
</div>

View File

@@ -1,9 +0,0 @@
<form wire:submit="updatePassword" class="fi-sc-form">
{{ $this->form }}
<div class="fi-ac fi-align-end">
<x-filament::button type="submit">
{{ __('filament-edit-profile::default.save') }}
</x-filament::button>
</div>
</form>

View File

@@ -1,9 +0,0 @@
<form wire:submit="updateProfile" class="fi-sc-form">
{{ $this->form }}
<div class="fi-ac fi-align-end">
<x-filament::button type="submit">
{{ __('filament-edit-profile::default.save') }}
</x-filament::button>
</div>
</form>

View File

@@ -1,7 +0,0 @@
<div>
<form class="fi-sc-form">
{{ $this->content }}
</form>
<x-filament-actions::modals />
</div>

View File

@@ -1,11 +0,0 @@
<x-filament::section aside>
<x-slot name="heading">
{{ __('filament-edit-profile::default.token_section_title') }}
</x-slot>
<x-slot name="description">
{{ __('filament-edit-profile::default.token_section_description') }}
</x-slot>
{{ $this->table }}
</x-filament::section>

View File

@@ -1,328 +0,0 @@
@php
use Filament\Actions\Action;
use Filament\Support\Enums\Alignment;
$fieldWrapperView = $getFieldWrapperView();
$items = $getItems();
$blockPickerBlocks = $getBlockPickerBlocks();
$blockPickerColumns = $getBlockPickerColumns();
$blockPickerWidth = $getBlockPickerWidth();
$hasBlockPreviews = $hasBlockPreviews();
$hasInteractiveBlockPreviews = $hasInteractiveBlockPreviews();
$addAction = $getAction($getAddActionName());
$addActionAlignment = $getAddActionAlignment();
$addBetweenAction = $getAction($getAddBetweenActionName());
$cloneAction = $getAction($getCloneActionName());
$collapseAllAction = $getAction($getCollapseAllActionName());
$editAction = $getAction($getEditActionName());
$expandAllAction = $getAction($getExpandAllActionName());
$deleteAction = $getAction($getDeleteActionName());
$moveDownAction = $getAction($getMoveDownActionName());
$moveUpAction = $getAction($getMoveUpActionName());
$reorderAction = $getAction($getReorderActionName());
$extraItemActions = $getExtraItemActions();
$isAddable = $isAddable();
$isCloneable = $isCloneable();
$isCollapsible = $isCollapsible();
$isDeletable = $isDeletable();
$isReorderableWithButtons = $isReorderableWithButtons();
$isReorderableWithDragAndDrop = $isReorderableWithDragAndDrop();
$collapseAllActionIsVisible = $isCollapsible && $collapseAllAction->isVisible();
$expandAllActionIsVisible = $isCollapsible && $expandAllAction->isVisible();
$key = $getKey();
$statePath = $getStatePath();
$blockLabelHeadingTag = $getHeadingTag();
$isBlockLabelTruncated = $isBlockLabelTruncated();
$labelBetweenItems = $getLabelBetweenItems();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-fo-builder',
'fi-collapsible' => $isCollapsible,
])
}}
>
@if ($collapseAllActionIsVisible || $expandAllActionIsVisible)
<div
@class([
'fi-fo-builder-actions',
'fi-hidden' => count($items) < 2,
])
>
@if ($collapseAllActionIsVisible)
<span
x-on:click="$dispatch('builder-collapse', '{{ $statePath }}')"
>
{{ $collapseAllAction }}
</span>
@endif
@if ($expandAllActionIsVisible)
<span
x-on:click="$dispatch('builder-expand', '{{ $statePath }}')"
>
{{ $expandAllAction }}
</span>
@endif
</div>
@endif
@if (count($items))
<ul
x-sortable
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
x-on:end.stop="
$event.oldDraggableIndex !== $event.newDraggableIndex &&
$wire.mountAction(
'reorder',
{ items: $event.target.sortable.toArray() },
{ schemaComponent: '{{ $key }}' },
)
"
class="fi-fo-builder-items"
>
@php
$hasBlockLabels = $hasBlockLabels();
$hasBlockIcons = $hasBlockIcons();
$hasBlockNumbers = $hasBlockNumbers();
$hasBlockHeaders = $hasBlockHeaders();
@endphp
@foreach ($items as $itemKey => $item)
@php
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
$deleteAction = $deleteAction(['item' => $itemKey]);
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
$editAction = $editAction(['item' => $itemKey]);
$editActionIsVisible = $hasBlockPreviews && $editAction->isVisible();
$moveDownAction = $moveDownAction(['item' => $itemKey])->disabled($loop->last);
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
$hasItemHeader = $hasBlockHeaders && ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || $hasBlockIcons || $hasBlockLabels || $editActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions);
@endphp
<li
wire:ignore.self
wire:key="{{ $item->getLivewireKey() }}.item"
x-data="{
isCollapsed: @js($isCollapsed($item)),
}"
x-on:builder-expand.window="$event.detail === '{{ $statePath }}' && (isCollapsed = false)"
x-on:builder-collapse.window="$event.detail === '{{ $statePath }}' && (isCollapsed = true)"
x-on:expand="isCollapsed = false"
x-sortable-item="{{ $itemKey }}"
{{
$item->getParentComponent()->getExtraAttributeBag()
->class([
'fi-fo-builder-item',
'fi-fo-builder-item-has-header' => $hasItemHeader,
])
}}
x-bind:class="{ 'fi-collapsed': isCollapsed }"
>
@if ($hasItemHeader)
<div
@if ($isCollapsible)
x-on:click.stop="isCollapsed = !isCollapsed"
@endif
class="fi-fo-builder-item-header"
>
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
<ul
class="fi-fo-builder-item-header-start-actions"
>
@if ($reorderActionIsVisible)
<li x-on:click.stop>
{{ $reorderAction->extraAttributes(['x-sortable-handle' => true], merge: true) }}
</li>
@endif
@if ($moveUpActionIsVisible || $moveDownActionIsVisible)
<li x-on:click.stop>
{{ $moveUpAction }}
</li>
<li x-on:click.stop>
{{ $moveDownAction }}
</li>
@endif
</ul>
@endif
@php
$blockIcon = $item->getParentComponent()->getIcon($item->getRawState(), $itemKey);
@endphp
@if ($hasBlockIcons && filled($blockIcon))
{{ \Filament\Support\generate_icon_html($blockIcon, (new \Illuminate\View\ComponentAttributeBag)->class(['fi-fo-builder-item-header-icon'])) }}
@endif
@if ($hasBlockLabels)
<{{ $blockLabelHeadingTag }}
@class([
'fi-fo-builder-item-header-label',
'fi-truncated' => $isBlockLabelTruncated,
])
>
{{ $item->getParentComponent()->getLabel($item->getRawState(), $itemKey) }}
@if ($hasBlockNumbers)
{{ $loop->iteration }}
@endif
</{{ $blockLabelHeadingTag }}>
@endif
@if ($editActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
<ul
class="fi-fo-builder-item-header-end-actions"
>
@foreach ($visibleExtraItemActions as $extraItemAction)
<li x-on:click.stop>
{{ $extraItemAction(['item' => $itemKey]) }}
</li>
@endforeach
@if ($editActionIsVisible)
<li x-on:click.stop>
{{ $editAction }}
</li>
@endif
@if ($cloneActionIsVisible)
<li x-on:click.stop>
{{ $cloneAction }}
</li>
@endif
@if ($deleteActionIsVisible)
<li x-on:click.stop>
{{ $deleteAction }}
</li>
@endif
@if ($isCollapsible)
<li
class="fi-fo-builder-item-header-collapsible-actions"
x-on:click.stop="isCollapsed = !isCollapsed"
>
<div
class="fi-fo-builder-item-header-collapse-action"
>
{{ $getAction('collapse') }}
</div>
<div
class="fi-fo-builder-item-header-expand-action"
>
{{ $getAction('expand') }}
</div>
</li>
@endif
</ul>
@endif
</div>
@endif
<div
x-show="! isCollapsed"
@class([
'fi-fo-builder-item-content',
'fi-fo-builder-item-content-has-preview' => $hasBlockPreviews && $item->getParentComponent()->hasPreview(),
])
>
@if ($hasBlockPreviews && $item->getParentComponent()->hasPreview())
<div
@class([
'fi-fo-builder-item-preview',
'fi-interactive' => $hasInteractiveBlockPreviews,
])
>
{{ $item->getParentComponent()->renderPreview($item->getRawState()) }}
</div>
@if ($editActionIsVisible && (! $hasInteractiveBlockPreviews))
<div
class="fi-fo-builder-item-preview-edit-overlay"
role="button"
x-on:click.stop="{{ '$wire.mountAction(\'edit\', { item: \'' . $itemKey . '\' }, { schemaComponent: \'' . $key . '\' })' }}"
></div>
@endif
@else
{{ $item }}
@endif
</div>
</li>
@if (! $loop->last)
@if ($isAddable && $addBetweenAction(['afterItem' => $itemKey])->isVisible())
<li class="fi-fo-builder-add-between-items-ctn">
<div class="fi-fo-builder-add-between-items">
<div class="fi-fo-builder-block-picker-ctn">
<x-filament-forms::builder.block-picker
:action="$addBetweenAction"
:after-item="$itemKey"
:columns="$blockPickerColumns"
:blocks="$blockPickerBlocks"
:key="$key"
:width="$blockPickerWidth"
>
<x-slot name="trigger">
{{ $addBetweenAction(['afterItem' => $itemKey]) }}
</x-slot>
</x-filament-forms::builder.block-picker>
</div>
</div>
</li>
@elseif (filled($labelBetweenItems))
<li class="fi-fo-builder-label-between-items-ctn">
<div
class="fi-fo-builder-label-between-items-divider-before"
></div>
<span class="fi-fo-builder-label-between-items">
{{ $labelBetweenItems }}
</span>
<div
class="fi-fo-builder-label-between-items-divider-after"
></div>
</li>
@endif
@endif
@endforeach
</ul>
@endif
@if ($isAddable && $addAction->isVisible())
<x-filament-forms::builder.block-picker
:action="$addAction"
:action-alignment="$addActionAlignment"
:blocks="$blockPickerBlocks"
:columns="$blockPickerColumns"
:key="$key"
:width="$blockPickerWidth"
>
<x-slot name="trigger">
{{ $addAction }}
</x-slot>
</x-filament-forms::builder.block-picker>
@endif
</div>
</x-dynamic-component>

View File

@@ -1,70 +0,0 @@
@php
use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\GridDirection;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'action',
'actionAlignment' => null,
'afterItem' => null,
'blocks',
'columns' => null,
'key',
'trigger',
'width' => null,
])
<x-filament::dropdown
:placement="
match ($actionAlignment) {
Alignment::Start, Alignment::Left => 'bottom-start',
Alignment::End, Alignment::Right => 'bottom-end',
default => null,
}
"
shift
:width="$width"
:attributes="
\Filament\Support\prepare_inherited_attributes(
$attributes->class([
'fi-fo-builder-block-picker',
($actionAlignment instanceof Alignment) ? ('fi-align-' . $actionAlignment->value) : $actionAlignment => $actionAlignment,
]),
)
"
>
<x-slot name="trigger">
{{ $trigger }}
</x-slot>
<x-filament::dropdown.list>
<div
{{ (new ComponentAttributeBag)->grid($columns, GridDirection::Column) }}
>
@foreach ($blocks as $block)
@php
$blockIcon = $block->getIcon();
$wireClickActionArguments = ['block' => $block->getName()];
if (filled($afterItem)) {
$wireClickActionArguments['afterItem'] = $afterItem;
}
$wireClickActionArguments = \Illuminate\Support\Js::from($wireClickActionArguments);
$wireClickAction = "mountAction('{$action->getName()}', {$wireClickActionArguments}, { schemaComponent: '{$key}' })";
@endphp
<x-filament::dropdown.list.item
:icon="$blockIcon"
x-on:click="close"
:wire:click="$wireClickAction"
>
{{ $block->getLabel() }}
</x-filament::dropdown.list.item>
@endforeach
</div>
</x-filament::dropdown.list>
</x-filament::dropdown>

View File

@@ -1,151 +0,0 @@
@php
use Filament\Support\Enums\GridDirection;
$fieldWrapperView = $getFieldWrapperView();
$extraInputAttributeBag = $getExtraInputAttributeBag();
$isHtmlAllowed = $isHtmlAllowed();
$gridDirection = $getGridDirection() ?? GridDirection::Column;
$isBulkToggleable = $isBulkToggleable();
$isDisabled = $isDisabled();
$isSearchable = $isSearchable();
$statePath = $getStatePath();
$options = $getOptions();
$livewireKey = $getLivewireKey();
$wireModelAttribute = $applyStateBindingModifiers('wire:model');
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('checkbox-list', 'filament/forms') }}"
x-data="checkboxListFormComponent({
livewireId: @js($this->getId()),
})"
{{ $getExtraAlpineAttributeBag()->class(['fi-fo-checkbox-list']) }}
>
@if (! $isDisabled)
@if ($isSearchable)
<x-filament::input.wrapper
inline-prefix
:prefix-icon="\Filament\Support\Icons\Heroicon::MagnifyingGlass"
:prefix-icon-alias="\Filament\Forms\View\FormsIconAlias::COMPONENTS_CHECKBOX_LIST_SEARCH_FIELD"
class="fi-fo-checkbox-list-search-input-wrp"
>
<input
placeholder="{{ $getSearchPrompt() }}"
type="search"
x-model.debounce.{{ $getSearchDebounce() }}="search"
class="fi-input fi-input-has-inline-prefix"
/>
</x-filament::input.wrapper>
@endif
@if ($isBulkToggleable && count($options))
<div
x-cloak
class="fi-fo-checkbox-list-actions"
wire:key="{{ $livewireKey }}.actions"
>
<span
x-show="! areAllCheckboxesChecked"
x-on:click="toggleAllCheckboxes()"
wire:key="{{ $livewireKey }}.actions.select-all"
>
{{ $getAction('selectAll') }}
</span>
<span
x-show="areAllCheckboxesChecked"
x-on:click="toggleAllCheckboxes()"
wire:key="{{ $livewireKey }}.actions.deselect-all"
>
{{ $getAction('deselectAll') }}
</span>
</div>
@endif
@endif
<div
{{
$getExtraAttributeBag()
->grid($getColumns(), $gridDirection)
->merge([
'x-show' => $isSearchable ? 'visibleCheckboxListOptions.length' : null,
], escape: false)
->class([
'fi-fo-checkbox-list-options',
])
}}
>
@forelse ($options as $value => $label)
<div
wire:key="{{ $livewireKey }}.options.{{ $value }}"
@if ($isSearchable)
x-show="
$el
.querySelector('.fi-fo-checkbox-list-option-label')
?.innerText.toLowerCase()
.includes(search.toLowerCase()) ||
$el
.querySelector('.fi-fo-checkbox-list-option-description')
?.innerText.toLowerCase()
.includes(search.toLowerCase())
"
@endif
class="fi-fo-checkbox-list-option-ctn"
>
<label class="fi-fo-checkbox-list-option">
<input
type="checkbox"
{{
$extraInputAttributeBag
->merge([
'disabled' => $isDisabled || $isOptionDisabled($value, $label),
'value' => $value,
'wire:loading.attr' => 'disabled',
$wireModelAttribute => $statePath,
'x-on:change' => $isBulkToggleable ? 'checkIfAllCheckboxesAreChecked()' : null,
], escape: false)
->class([
'fi-checkbox-input',
'fi-valid' => ! $errors->has($statePath),
'fi-invalid' => $errors->has($statePath),
])
}}
/>
<div class="fi-fo-checkbox-list-option-text">
<span class="fi-fo-checkbox-list-option-label">
@if ($isHtmlAllowed)
{!! $label !!}
@else
{{ $label }}
@endif
</span>
@if ($hasDescription($value))
<p
class="fi-fo-checkbox-list-option-description"
>
{{ $getDescription($value) }}
</p>
@endif
</div>
</label>
</div>
@empty
<div wire:key="{{ $livewireKey }}.empty"></div>
@endforelse
</div>
@if ($isSearchable)
<div
x-cloak
x-show="search && ! visibleCheckboxListOptions.length"
class="fi-fo-checkbox-list-no-search-results-message"
>
{{ $getNoSearchResultsMessage() }}
</div>
@endif
</div>
</x-dynamic-component>

View File

@@ -1,34 +0,0 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$statePath = $getStatePath();
$attributes = $attributes
->merge([
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled(),
'id' => $getId(),
'required' => $isRequired() && (! $isConcealed()),
'wire:loading.attr' => 'disabled',
$applyStateBindingModifiers('wire:model') => $statePath,
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraInputAttributes(), escape: false)
->class([
'fi-checkbox-input',
'fi-valid' => ! $errors->has($statePath),
'fi-invalid' => $errors->has($statePath),
]);
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
@if ($isInline())
<x-slot name="labelPrefix">
<input type="checkbox" {{ $attributes }} />
</x-slot>
@else
<input type="checkbox" {{ $attributes }} />
@endif
</x-dynamic-component>

View File

@@ -1,40 +0,0 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$extraAttributeBag = $getExtraAttributeBag();
$isDisabled = $isDisabled();
$key = $getKey();
$language = $getLanguage();
$statePath = $getStatePath();
$livewireKey = $getLivewireKey();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<x-filament::input.wrapper
:disabled="$isDisabled"
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-code-editor'])
"
>
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('code-editor', 'filament/forms') }}"
x-data="codeEditorFormComponent({
isDisabled: @js($isDisabled),
language: @js($language?->value),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
$language?->value,
])), 0, 64)
}}"
{{ $getExtraAlpineAttributeBag() }}
>
<div x-ref="editor" x-cloak></div>
</div>
</x-filament::input.wrapper>
</x-dynamic-component>

View File

@@ -1,115 +0,0 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$extraAttributeBag = $getExtraAttributeBag();
$isDisabled = $isDisabled();
$isLive = $isLive();
$isLiveOnBlur = $isLiveOnBlur();
$isLiveDebounced = $isLiveDebounced();
$isPrefixInline = $isPrefixInline();
$isSuffixInline = $isSuffixInline();
$liveDebounce = $getLiveDebounce();
$prefixActions = $getPrefixActions();
$prefixIcon = $getPrefixIcon();
$prefixIconColor = $getPrefixIconColor();
$prefixLabel = $getPrefixLabel();
$suffixActions = $getSuffixActions();
$suffixIcon = $getSuffixIcon();
$suffixIconColor = $getSuffixIconColor();
$suffixLabel = $getSuffixLabel();
$statePath = $getStatePath();
$placeholder = $getPlaceholder();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:inline-prefix="$isPrefixInline"
:inline-suffix="$isSuffixInline"
:prefix="$prefixLabel"
:prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon"
:prefix-icon-color="$prefixIconColor"
:suffix="$suffixLabel"
:suffix-actions="$suffixActions"
:suffix-icon="$suffixIcon"
:suffix-icon-color="$suffixIconColor"
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class('fi-fo-color-picker')
"
>
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('color-picker', 'filament/forms') }}"
x-data="colorPickerFormComponent({
isAutofocused: @js($isAutofocused()),
isDisabled: @js($isDisabled),
isLive: @js($isLive),
isLiveDebounced: @js($isLiveDebounced),
isLiveOnBlur: @js($isLiveOnBlur),
liveDebounce: @js($liveDebounce),
state: $wire.$entangle('{{ $statePath }}'),
})"
x-on:keydown.esc="isOpen() && $event.stopPropagation()"
{{ $getExtraAlpineAttributeBag()->class(['fi-input-wrp-content']) }}
>
<input
x-on:focus="$refs.panel.open($refs.input)"
x-on:keydown.enter.prevent.stop="togglePanelVisibility()"
x-ref="input"
{{
$getExtraInputAttributeBag()
->merge([
'autocomplete' => 'off',
'disabled' => $isDisabled,
'id' => $getId(),
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'required' => $isRequired() && (! $isConcealed()),
'type' => 'text',
'x-model' . ($isLiveDebounced ? '.debounce.' . $liveDebounce : null) => 'state',
'x-on:blur' => $isLiveOnBlur ? 'isOpen() ? null : commitState()' : null,
], escape: false)
->class([
'fi-input',
'fi-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
])
}}
/>
<div
class="fi-fo-color-picker-preview my-auto me-3 size-5 shrink-0 rounded-full select-none"
x-on:click="togglePanelVisibility()"
x-bind:class="{
'fi-empty': ! state,
}"
x-bind:style="{ 'background-color': state }"
></div>
<div
wire:ignore.self
wire:key="{{ $getLivewireKey() }}.panel"
x-cloak
x-float.placement.bottom-start.offset.flip.shift="{ offset: 8 }"
x-ref="panel"
class="fi-fo-color-picker-panel"
>
@php
$tag = match ($getFormat()) {
'hsl' => 'hsl-string',
'rgb' => 'rgb-string',
'rgba' => 'rgba-string',
default => 'hex',
} . '-color-picker';
@endphp
<{{ $tag }} color="{{ $getState() }}" />
</div>
</div>
</x-filament::input.wrapper>
</x-dynamic-component>

View File

@@ -1,294 +0,0 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$datalistOptions = $getDatalistOptions();
$disabledDates = $getDisabledDates();
$extraAlpineAttributes = $getExtraAlpineAttributes();
$extraAttributeBag = $getExtraAttributeBag();
$extraInputAttributeBag = $getExtraInputAttributeBag();
$hasDate = $hasDate();
$hasTime = $hasTime();
$hasSeconds = $hasSeconds();
$id = $getId();
$isDisabled = $isDisabled();
$isAutofocused = $isAutofocused();
$isPrefixInline = $isPrefixInline();
$isSuffixInline = $isSuffixInline();
$maxDate = $getMaxDate();
$minDate = $getMinDate();
$prefixActions = $getPrefixActions();
$prefixIcon = $getPrefixIcon();
$prefixIconColor = $getPrefixIconColor();
$prefixLabel = $getPrefixLabel();
$suffixActions = $getSuffixActions();
$suffixIcon = $getSuffixIcon();
$suffixIconColor = $getSuffixIconColor();
$suffixLabel = $getSuffixLabel();
$statePath = $getStatePath();
$placeholder = $getPlaceholder();
$isReadOnly = $isReadOnly();
$isRequired = $isRequired();
$isConcealed = $isConcealed();
$step = $getStep();
$type = $getType();
$livewireKey = $getLivewireKey();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:inline-prefix="$isPrefixInline"
:inline-suffix="$isSuffixInline"
:prefix="$prefixLabel"
:prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon"
:prefix-icon-color="$prefixIconColor"
:suffix="$suffixLabel"
:suffix-actions="$suffixActions"
:suffix-icon="$suffixIcon"
:suffix-icon-color="$suffixIconColor"
:valid="! $errors->has($statePath)"
:attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class(['fi-fo-date-time-picker'])"
>
@if ($isNative())
<input
{{
$extraInputAttributeBag
->merge($extraAlpineAttributes, escape: false)
->merge([
'autofocus' => $isAutofocused,
'disabled' => $isDisabled,
'id' => $id,
'list' => $datalistOptions ? $id . '-list' : null,
'max' => $hasTime ? $maxDate : ($maxDate ? \Carbon\Carbon::parse($maxDate)->toDateString() : null),
'min' => $hasTime ? $minDate : ($minDate ? \Carbon\Carbon::parse($minDate)->toDateString() : null),
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly,
'required' => $isRequired && (! $isConcealed),
'step' => $step,
'type' => $type,
$applyStateBindingModifiers('wire:model') => $statePath,
'x-data' => count($extraAlpineAttributes) ? '{}' : null,
], escape: false)
->class([
'fi-input',
'fi-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
])
}}
/>
@else
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('date-time-picker', 'filament/forms') }}"
x-data="dateTimePickerFormComponent({
defaultFocusedDate: @js($defaultFocusedDate),
displayFormat:
'{{ convert_date_format($getDisplayFormat())->to('day.js') }}',
firstDayOfWeek: {{ $getFirstDayOfWeek() }},
isAutofocused: @js($isAutofocused),
locale: @js($getLocale()),
shouldCloseOnDateSelection: @js($shouldCloseOnDateSelection()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$disabledDates,
$isDisabled,
$isReadOnly,
$maxDate,
$minDate,
$hasDate,
$hasTime,
$hasSeconds,
])), 0, 64)
}}"
x-on:keydown.esc="isOpen() && $event.stopPropagation()"
{{ $getExtraAlpineAttributeBag() }}
>
<input x-ref="maxDate" type="hidden" value="{{ $maxDate }}" />
<input x-ref="minDate" type="hidden" value="{{ $minDate }}" />
<input
x-ref="disabledDates"
type="hidden"
value="{{ json_encode($disabledDates) }}"
/>
<button
x-ref="button"
x-on:click="togglePanelVisibility()"
x-on:keydown.enter.prevent.stop="
if (! $el.disabled) {
isOpen() ? selectDate() : togglePanelVisibility()
}
"
x-on:keydown.arrow-left.prevent.stop="if (! $el.disabled) focusPreviousDay()"
x-on:keydown.arrow-right.prevent.stop="if (! $el.disabled) focusNextDay()"
x-on:keydown.arrow-up.prevent.stop="if (! $el.disabled) focusPreviousWeek()"
x-on:keydown.arrow-down.prevent.stop="if (! $el.disabled) focusNextWeek()"
x-on:keydown.backspace.prevent.stop="if (! $el.disabled) clearState()"
x-on:keydown.clear.prevent.stop="if (! $el.disabled) clearState()"
x-on:keydown.delete.prevent.stop="if (! $el.disabled) clearState()"
aria-label="{{ $placeholder }}"
type="button"
tabindex="-1"
@disabled($isDisabled || $isReadOnly)
{{
$getExtraTriggerAttributeBag()->class([
'fi-fo-date-time-picker-trigger',
])
}}
>
<input
@disabled($isDisabled)
readonly
placeholder="{{ $placeholder }}"
wire:key="{{ $livewireKey }}.display-text"
x-model="displayText"
@if ($id = $getId()) id="{{ $id }}" @endif
@class([
'fi-fo-date-time-picker-display-text-input',
])
/>
</button>
<div
x-ref="panel"
x-cloak
x-float.placement.bottom-start.offset.flip.shift="{ offset: 8 }"
wire:ignore
wire:key="{{ $livewireKey }}.panel"
@class([
'fi-fo-date-time-picker-panel',
])
>
@if ($hasDate)
<div class="fi-fo-date-time-picker-panel-header">
<select
x-model="focusedMonth"
class="fi-fo-date-time-picker-month-select"
>
<template x-for="(month, index) in months">
<option
x-bind:value="index"
x-text="month"
></option>
</template>
</select>
<input
type="number"
inputmode="numeric"
x-model.debounce="focusedYear"
class="fi-fo-date-time-picker-year-input"
/>
</div>
<div class="fi-fo-date-time-picker-calendar-header">
<template
x-for="(day, index) in dayLabels"
x-bind:key="index"
>
<div
x-text="day"
class="fi-fo-date-time-picker-calendar-header-day"
></div>
</template>
</div>
<div
role="grid"
class="fi-fo-date-time-picker-calendar"
>
<template
x-for="day in emptyDaysInFocusedMonth"
x-bind:key="day"
>
<div></div>
</template>
<template
x-for="day in daysInFocusedMonth"
x-bind:key="day"
>
<div
x-text="day"
x-on:click="dayIsDisabled(day) || selectDate(day)"
x-on:mouseenter="setFocusedDay(day)"
role="option"
x-bind:aria-selected="focusedDate.date() === day"
x-bind:class="{
'fi-fo-date-time-picker-calendar-day-today': dayIsToday(day),
'fi-focused': focusedDate.date() === day,
'fi-selected': dayIsSelected(day),
'fi-disabled': dayIsDisabled(day),
}"
class="fi-fo-date-time-picker-calendar-day"
></div>
</template>
</div>
@endif
@if ($hasTime)
<div class="fi-fo-date-time-picker-time-inputs">
<input
max="23"
min="0"
step="{{ $getHoursStep() }}"
type="number"
inputmode="numeric"
x-model.debounce="hour"
/>
<span
class="fi-fo-date-time-picker-time-input-separator"
>
:
</span>
<input
max="59"
min="0"
step="{{ $getMinutesStep() }}"
type="number"
inputmode="numeric"
x-model.debounce="minute"
/>
@if ($hasSeconds)
<span
class="fi-fo-date-time-picker-time-input-separator"
>
:
</span>
<input
max="59"
min="0"
step="{{ $getSecondsStep() }}"
type="number"
inputmode="numeric"
x-model.debounce="second"
/>
@endif
</div>
@endif
</div>
</div>
@endif
</x-filament::input.wrapper>
@if ($datalistOptions)
<datalist id="{{ $id }}-list">
@foreach ($datalistOptions as $option)
<option value="{{ $option }}" />
@endforeach
</datalist>
@endif
</x-dynamic-component>

View File

@@ -1,197 +0,0 @@
@php
use Filament\Support\Enums\VerticalAlignment;
@endphp
@props([
'areHtmlErrorMessagesAllowed' => null,
'errorMessage' => null,
'errorMessages' => null,
'field' => null,
'hasErrors' => true,
'hasInlineLabel' => null,
'hasNestedRecursiveValidationRules' => null,
'id' => null,
'inlineLabelVerticalAlignment' => VerticalAlignment::Start,
'isDisabled' => null,
'label' => null,
'labelPrefix' => null,
'labelSrOnly' => null,
'labelSuffix' => null,
'labelTag' => 'label',
'required' => null,
'shouldShowAllValidationMessages' => null,
'statePath' => null,
])
@php
use Illuminate\Support\Arr;
if ($field) {
$hasInlineLabel ??= $field->hasInlineLabel();
$hasNestedRecursiveValidationRules ??= $field instanceof \Filament\Forms\Components\Contracts\HasNestedRecursiveValidationRules;
$id ??= $field->getId();
$isDisabled ??= $field->isDisabled();
$label ??= $field->getLabel();
$labelSrOnly ??= $field->isLabelHidden();
$required ??= $field->isMarkedAsRequired();
$statePath ??= $field->getStatePath();
$areHtmlErrorMessagesAllowed ??= $field->areHtmlValidationMessagesAllowed();
$shouldShowAllValidationMessages ??= $field->shouldShowAllValidationMessages();
}
$aboveLabelSchema = $field?->getChildSchema($field::ABOVE_LABEL_SCHEMA_KEY)?->toHtmlString();
$belowLabelSchema = $field?->getChildSchema($field::BELOW_LABEL_SCHEMA_KEY)?->toHtmlString();
$beforeLabelSchema = $field?->getChildSchema($field::BEFORE_LABEL_SCHEMA_KEY)?->toHtmlString();
$afterLabelSchema = $field?->getChildSchema($field::AFTER_LABEL_SCHEMA_KEY)?->toHtmlString();
$aboveContentSchema = $field?->getChildSchema($field::ABOVE_CONTENT_SCHEMA_KEY)?->toHtmlString();
$belowContentSchema = $field?->getChildSchema($field::BELOW_CONTENT_SCHEMA_KEY)?->toHtmlString();
$beforeContentSchema = $field?->getChildSchema($field::BEFORE_CONTENT_SCHEMA_KEY)?->toHtmlString();
$afterContentSchema = $field?->getChildSchema($field::AFTER_CONTENT_SCHEMA_KEY)?->toHtmlString();
$aboveErrorMessageSchema = $field?->getChildSchema($field::ABOVE_ERROR_MESSAGE_SCHEMA_KEY)?->toHtmlString();
$belowErrorMessageSchema = $field?->getChildSchema($field::BELOW_ERROR_MESSAGE_SCHEMA_KEY)?->toHtmlString();
$hasError = $hasErrors && (filled($errorMessage) || filled($errorMessages) || (filled($statePath) && ($errors->has($statePath) || ($hasNestedRecursiveValidationRules && $errors->has("{$statePath}.*")))));
if ($hasError && filled($statePath) && blank($errorMessage) && blank($errorMessages)) {
if ($shouldShowAllValidationMessages) {
$errorMessages = $errors->has($statePath) ? $errors->get($statePath) : ($hasNestedRecursiveValidationRules ? $errors->get("{$statePath}.*") : []);
if (count($errorMessages) === 1) {
$errorMessage = Arr::first($errorMessages);
$errorMessages = [];
}
} else {
$errorMessage = $errors->has($statePath) ? $errors->first($statePath) : ($hasNestedRecursiveValidationRules ? $errors->first("{$statePath}.*") : null);
}
}
@endphp
<div
data-field-wrapper
{{
$attributes
->merge($field?->getExtraFieldWrapperAttributes() ?? [], escape: false)
->class([
'fi-fo-field',
'fi-fo-field-has-inline-label' => $hasInlineLabel,
])
}}
>
@if (filled($label) && $labelSrOnly)
<{{ $labelTag }}
@if ($labelTag === 'label')
for="{{ $id }}"
@else
id="{{ $id }}-label"
@endif
class="fi-fo-field-label fi-sr-only"
>
{{ $label }}
</{{ $labelTag }}>
@endif
@if ((filled($label) && (! $labelSrOnly)) || $hasInlineLabel || $aboveLabelSchema || $belowLabelSchema || $beforeLabelSchema || $afterLabelSchema || $labelPrefix || $labelSuffix)
<div
@class([
'fi-fo-field-label-col',
"fi-vertical-align-{$inlineLabelVerticalAlignment->value}" => $hasInlineLabel,
])
>
{{ $aboveLabelSchema }}
<div
@class([
'fi-fo-field-label-ctn',
($label instanceof \Illuminate\View\ComponentSlot) ? $label->attributes->get('class') : null,
])
>
{{ $beforeLabelSchema }}
@if ((filled($label) && (! $labelSrOnly)) || $labelPrefix || $labelSuffix)
<{{ $labelTag }}
@if ($labelTag === 'label')
for="{{ $id }}"
@else
id="{{ $id }}-label"
@endif
class="fi-fo-field-label"
>
{{ $labelPrefix }}
@if (filled($label) && (! $labelSrOnly))
<span class="fi-fo-field-label-content">
{{ $label }}@if ($required && (! $isDisabled))<sup class="fi-fo-field-label-required-mark">*</sup>
@endif
</span>
@endif
{{ $labelSuffix }}
</{{ $labelTag }}>
@endif
{{ $afterLabelSchema }}
</div>
{{ $belowLabelSchema }}
</div>
@endif
@if ((! \Filament\Support\is_slot_empty($slot)) || $hasError || $aboveContentSchema || $belowContentSchema || $beforeContentSchema || $afterContentSchema || $aboveErrorMessageSchema || $belowErrorMessageSchema)
<div class="fi-fo-field-content-col">
{{ $aboveContentSchema }}
@if ($beforeContentSchema || $afterContentSchema)
<div class="fi-fo-field-content-ctn">
{{ $beforeContentSchema }}
<div class="fi-fo-field-content">
{{ $slot }}
</div>
{{ $afterContentSchema }}
</div>
@else
{{ $slot }}
@endif
{{ $belowContentSchema }}
@if ($hasError)
{{ $aboveErrorMessageSchema }}
@if (filled($errorMessages))
<ul
data-validation-error
class="fi-fo-field-wrp-error-list"
>
@foreach ($errorMessages as $errorMessage)
<li class="fi-fo-field-wrp-error-message">
@if ($areHtmlErrorMessagesAllowed)
{!! $errorMessage !!}
@else
{{ $errorMessage }}
@endif
</li>
@endforeach
</ul>
@elseif ($areHtmlErrorMessagesAllowed)
<div
data-validation-error
class="fi-fo-field-wrp-error-message"
>
{!! $errorMessage !!}
</div>
@else
<p
data-validation-error
class="fi-fo-field-wrp-error-message"
>
{{ $errorMessage }}
</p>
@endif
{{ $belowErrorMessageSchema }}
@endif
</div>
@endif
</div>

View File

@@ -1,344 +0,0 @@
@php
use Filament\Support\Enums\Alignment;
$fieldWrapperView = $getFieldWrapperView();
$id = $getId();
$imageCropAspectRatio = $getImageCropAspectRatio();
$imageResizeTargetHeight = $getImageResizeTargetHeight();
$imageResizeTargetWidth = $getImageResizeTargetWidth();
$isAvatar = $isAvatar();
$isMultiple = $isMultiple();
$key = $getKey();
$statePath = $getStatePath();
$isDisabled = $isDisabled();
$hasImageEditor = $hasImageEditor();
$hasCircleCropper = $hasCircleCropper();
$livewireKey = $getLivewireKey();
$alignment = $getAlignment() ?? Alignment::Start;
if (! $alignment instanceof Alignment) {
$alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
}
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
label-tag="div"
>
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('file-upload', 'filament/forms') }}"
x-data="fileUploadFormComponent({
acceptedFileTypes: @js($getAcceptedFileTypes()),
imageEditorEmptyFillColor: @js($getImageEditorEmptyFillColor()),
imageEditorMode: @js($getImageEditorMode()),
imageEditorViewportHeight: @js($getImageEditorViewportHeight()),
imageEditorViewportWidth: @js($getImageEditorViewportWidth()),
deleteUploadedFileUsing: async (fileKey) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'deleteUploadedFile',
{ fileKey },
)
},
getUploadedFilesUsing: async () => {
return await $wire.callSchemaComponentMethod(
@js($key),
'getUploadedFiles',
)
},
hasImageEditor: @js($hasImageEditor),
hasCircleCropper: @js($hasCircleCropper),
canEditSvgs: @js($canEditSvgs()),
isSvgEditingConfirmed: @js($isSvgEditingConfirmed()),
confirmSvgEditingMessage: @js(__('filament-forms::components.file_upload.editor.svg.messages.confirmation')),
disabledSvgEditingMessage: @js(__('filament-forms::components.file_upload.editor.svg.messages.disabled')),
imageCropAspectRatio: @js($imageCropAspectRatio),
imagePreviewHeight: @js($getImagePreviewHeight()),
imageResizeMode: @js($getImageResizeMode()),
imageResizeTargetHeight: @js($imageResizeTargetHeight),
imageResizeTargetWidth: @js($imageResizeTargetWidth),
imageResizeUpscale: @js($getImageResizeUpscale()),
isAvatar: @js($isAvatar),
isDeletable: @js($isDeletable()),
isDisabled: @js($isDisabled),
isDownloadable: @js($isDownloadable()),
isMultiple: @js($isMultiple),
isOpenable: @js($isOpenable()),
isPasteable: @js($isPasteable()),
isPreviewable: @js($isPreviewable()),
isReorderable: @js($isReorderable()),
itemPanelAspectRatio: @js($getItemPanelAspectRatio()),
loadingIndicatorPosition: @js($getLoadingIndicatorPosition()),
locale: @js(app()->getLocale()),
panelAspectRatio: @js($getPanelAspectRatio()),
panelLayout: @js($getPanelLayout()),
placeholder: @js($getPlaceholder()),
maxFiles: @js($maxFiles = $getMaxFiles()),
maxFilesValidationMessage: @js($maxFiles ? trans_choice('validation.max.array', $maxFiles, ['attribute' => $getValidationAttribute(), 'max' => $maxFiles]) : null),
maxSize: @js(($size = $getMaxSize()) ? "{$size}KB" : null),
minSize: @js(($size = $getMinSize()) ? "{$size}KB" : null),
mimeTypeMap: @js($getMimeTypeMap()),
maxParallelUploads: @js($getMaxParallelUploads()),
removeUploadedFileUsing: async (fileKey) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'removeUploadedFile',
{ fileKey },
)
},
removeUploadedFileButtonPosition: @js($getRemoveUploadedFileButtonPosition()),
reorderUploadedFilesUsing: async (fileKeys) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'reorderUploadedFiles',
{ fileKeys },
)
},
shouldAppendFiles: @js($shouldAppendFiles()),
shouldOrientImageFromExif: @js($shouldOrientImagesFromExif()),
shouldTransformImage: @js($imageCropAspectRatio || $imageResizeTargetHeight || $imageResizeTargetWidth),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
uploadButtonPosition: @js($getUploadButtonPosition()),
uploadingMessage: @js($getUploadingMessage()),
uploadProgressIndicatorPosition: @js($getUploadProgressIndicatorPosition()),
uploadUsing: (fileKey, file, success, error, progress) => {
$wire.upload(
`{{ $statePath }}.${fileKey}`,
file,
() => {
success(fileKey)
},
error,
(progressEvent) => {
progress(true, progressEvent.detail.progress, 100)
},
)
},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
])), 0, 64)
}}"
{{
$attributes
->merge([
'aria-labelledby' => "{$id}-label",
'id' => $id,
'role' => 'group',
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->class([
'fi-fo-file-upload',
'fi-fo-file-upload-avatar' => $isAvatar,
($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : $alignment,
])
}}
>
<div class="fi-fo-file-upload-input-ctn">
<input
x-ref="input"
{{
$getExtraInputAttributeBag()
->merge([
'aria-labelledby' => "{$id}-label",
'disabled' => $isDisabled,
'multiple' => $isMultiple,
'type' => 'file',
], escape: false)
}}
/>
</div>
<div
x-show="error"
x-text="error"
x-cloak
class="fi-fo-file-upload-error-message"
></div>
@if ($hasImageEditor && (! $isDisabled))
<div
x-show="isEditorOpen"
x-cloak
x-on:click.stop=""
x-trap.noscroll="isEditorOpen"
x-on:keydown.escape.prevent.stop="closeEditor"
@class([
'fi-fo-file-upload-editor',
'fi-fo-file-upload-editor-circle-cropper' => $hasCircleCropper,
])
>
<div
aria-hidden="true"
class="fi-fo-file-upload-editor-overlay"
></div>
<div class="fi-fo-file-upload-editor-window">
<div class="fi-fo-file-upload-editor-image-ctn">
<img
x-ref="editor"
class="fi-fo-file-upload-editor-image"
/>
</div>
<div class="fi-fo-file-upload-editor-control-panel">
<div
class="fi-fo-file-upload-editor-control-panel-main"
>
<div
class="fi-fo-file-upload-editor-control-panel-group"
>
@foreach ([
[
'label' => __('filament-forms::components.file_upload.editor.fields.x_position.label'),
'ref' => 'xPositionInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.x_position.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), x: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.y_position.label'),
'ref' => 'yPositionInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.y_position.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), y: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.width.label'),
'ref' => 'widthInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.width.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), width: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.height.label'),
'ref' => 'heightInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.height.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), height: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.rotation.label'),
'ref' => 'rotationInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.rotation.unit'),
'alpineSaveHandler' => 'editor.rotateTo(+$el.value)',
],
] as $input)
<label>
<x-filament::input.wrapper>
<x-slot name="prefix">
{{ $input['label'] }}
</x-slot>
<input
x-on:keyup.enter.prevent.stop="editor && {!! $input['alpineSaveHandler'] !!}"
x-on:blur="editor && {!! $input['alpineSaveHandler'] !!}"
x-ref="{{ $input['ref'] }}"
x-on:keydown.enter.prevent
type="text"
class="fi-input"
/>
<x-slot name="suffix">
{{ $input['unit'] }}
</x-slot>
</x-filament::input.wrapper>
</label>
@endforeach
</div>
<div
class="fi-fo-file-upload-editor-control-panel-group"
>
@foreach ($getImageEditorActions() as $groupedActions)
<div class="fi-btn-group">
@foreach ($groupedActions as $action)
<button
aria-label="{{ $action['label'] }}"
type="button"
x-on:click.prevent.stop="{{ $action['alpineClickHandler'] }}"
x-tooltip="{ content: @js($action['label']), theme: $store.theme }"
class="fi-btn"
>
{{ $action['iconHtml'] }}
</button>
@endforeach
</div>
@endforeach
</div>
@if (count($aspectRatios = $getImageEditorAspectRatiosForJs()))
<div
class="fi-fo-file-upload-editor-control-panel-group"
>
<div
class="fi-fo-file-upload-editor-control-panel-group-title"
>
{{ __('filament-forms::components.file_upload.editor.aspect_ratios.label') }}
</div>
@foreach (collect($aspectRatios)->chunk(5) as $ratiosChunk)
<div class="fi-btn-group">
@foreach ($ratiosChunk as $label => $ratio)
<button
type="button"
x-on:click.prevent.stop="
currentRatio = @js($label) {!! ';' !!}
editor.setAspectRatio(@js($ratio))
"
x-tooltip="{ content: @js(__('filament-forms::components.file_upload.editor.actions.set_aspect_ratio.label', ['ratio' => $label])), theme: $store.theme }"
x-bind:class="{ 'fi-active': currentRatio === @js($label) }"
class="fi-btn"
>
{{ $label }}
</button>
@endforeach
</div>
@endforeach
</div>
@endif
</div>
<div
class="fi-fo-file-upload-editor-control-panel-footer"
>
<button
type="button"
x-on:click.prevent="pond.imageEditEditor.oncancel"
class="fi-btn"
>
{{ __('filament-forms::components.file_upload.editor.actions.cancel.label') }}
</button>
<button
type="button"
x-on:click.prevent.stop="editor.reset()"
{{
(new \Illuminate\View\ComponentAttributeBag)
->color(\Filament\Support\View\Components\ButtonComponent::class, 'danger')
->class(['fi-btn fi-fo-file-upload-editor-control-panel-reset-action'])
}}
>
{{ __('filament-forms::components.file_upload.editor.actions.reset.label') }}
</button>
<button
type="button"
x-on:click.prevent="saveEditor"
{{
(new \Illuminate\View\ComponentAttributeBag)
->color(\Filament\Support\View\Components\ButtonComponent::class, 'success')
->class(['fi-btn'])
}}
>
{{ __('filament-forms::components.file_upload.editor.actions.save.label') }}
</button>
</div>
</div>
</div>
</div>
@endif
</div>
</x-dynamic-component>

View File

@@ -1,12 +0,0 @@
<input
{{
$attributes
->merge([
'id' => $getId(),
'type' => 'hidden',
$applyStateBindingModifiers('wire:model') => $getStatePath(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class(['fi-fo-hidden'])
}}
/>

View File

@@ -1,148 +0,0 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$extraAttributeBag = $getExtraAttributeBag();
$canEditKeys = $canEditKeys();
$canEditValues = $canEditValues();
$keyPlaceholder = $getKeyPlaceholder();
$valuePlaceholder = $getValuePlaceholder();
$debounce = $getLiveDebounce();
$isAddable = $isAddable();
$isDeletable = $isDeletable();
$isDisabled = $isDisabled();
$isReorderable = $isReorderable();
$statePath = $getStatePath();
$livewireKey = $getLivewireKey();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
class="fi-fo-key-value-wrp"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-key-value'])
"
>
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('key-value', 'filament/forms') }}"
x-data="keyValueFormComponent({
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
])), 0, 64)
}}"
{{
$attributes
->merge($getExtraAlpineAttributes(), escape: false)
->class(['fi-fo-key-value-table-ctn'])
}}
>
<table class="fi-fo-key-value-table">
<thead>
<tr>
@if ($isReorderable && (! $isDisabled))
<th
scope="col"
x-show="rows.length"
class="fi-has-action"
></th>
@endif
<th scope="col">
{{ $getKeyLabel() }}
</th>
<th scope="col">
{{ $getValueLabel() }}
</th>
@if ($isDeletable && (! $isDisabled))
<th
scope="col"
x-show="rows.length"
class="fi-has-action"
></th>
@endif
</tr>
</thead>
<tbody
@if ($isReorderable)
x-on:end.stop="reorderRows($event)"
x-sortable
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
@endif
>
<template
x-bind:key="index"
x-for="(row, index) in rows"
>
<tr
@if ($isReorderable)
x-bind:x-sortable-item="row.key"
@endif
>
@if ($isReorderable && (! $isDisabled))
<td class="fi-has-action">
<div
x-sortable-handle
class="fi-fo-key-value-table-row-sortable-handle"
>
{{ $getAction('reorder') }}
</div>
</td>
@endif
<td>
<input
@disabled((! $canEditKeys) || $isDisabled)
placeholder="{{ $keyPlaceholder }}"
type="text"
x-model="row.key"
x-on:input.debounce.{{ $debounce ?? '500ms' }}="updateState"
class="fi-input"
/>
</td>
<td>
<input
@disabled((! $canEditValues) || $isDisabled)
placeholder="{{ $valuePlaceholder }}"
type="text"
x-model="row.value"
x-on:input.debounce.{{ $debounce ?? '500ms' }}="updateState"
class="fi-input"
/>
</td>
@if ($isDeletable && (! $isDisabled))
<td class="fi-has-action">
<div x-on:click="deleteRow(index)">
{{ $getAction('delete') }}
</div>
</td>
@endif
</tr>
</template>
</tbody>
</table>
@if ($isAddable && (! $isDisabled))
<div
x-on:click="addRow"
class="fi-fo-key-value-add-action-ctn"
>
{{ $getAction('add') }}
</div>
@endif
</div>
</x-filament::input.wrapper>
</x-dynamic-component>

View File

@@ -1,30 +0,0 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$extraAttributes = $getExtraAttributes();
$id = $getId();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
@if (filled($id) || filled($extraAttributes))
{!! '<div' !!}
{{-- Avoid formatting issues with unclosed elements --}}
{{
$attributes
->merge([
'id' => $id,
], escape: false)
->merge($extraAttributes, escape: false)
}}
>
@endif
@if (filled($key = $getLivewireKey()))
@livewire($getComponent(), $getComponentProperties(), key($key))
@else
@livewire($getComponent(), $getComponentProperties())
@endif
@if (filled($id) || filled($extraAttributes))
{!! '</div>' !!}
{{-- Avoid formatting issues with unclosed elements --}}
@endif
</x-dynamic-component>

View File

@@ -1,77 +0,0 @@
@php
$id = $getId();
$fieldWrapperView = $getFieldWrapperView();
$extraAttributeBag = $getExtraAttributeBag();
$key = $getKey();
$statePath = $getStatePath();
$fileAttachmentsMaxSize = $getFileAttachmentsMaxSize();
$fileAttachmentsAcceptedFileTypes = $getFileAttachmentsAcceptedFileTypes();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
@if ($isDisabled())
<div id="{{ $id }}" class="fi-fo-markdown-editor fi-disabled fi-prose">
{!! str($getState())->markdown($getCommonMarkOptions(), $getCommonMarkExtensions())->sanitizeHtml() !!}
</div>
@else
<x-filament::input.wrapper
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-markdown-editor'])
"
>
<div
aria-labelledby="{{ $id }}-label"
id="{{ $id }}"
role="group"
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('markdown-editor', 'filament/forms') }}"
x-data="markdownEditorFormComponent({
canAttachFiles: @js($hasToolbarButton('attachFiles')),
isLiveDebounced: @js($isLiveDebounced()),
isLiveOnBlur: @js($isLiveOnBlur()),
liveDebounce: @js($getNormalizedLiveDebounce()),
maxHeight: @js($getMaxHeight()),
minHeight: @js($getMinHeight()),
placeholder: @js($getPlaceholder()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')", isOptimisticallyLive: false) }},
toolbarButtons: @js($getToolbarButtons()),
translations: @js(__('filament-forms::components.markdown_editor')),
uploadFileAttachmentUsing: async (file, onSuccess, onError) => {
const acceptedTypes = @js($fileAttachmentsAcceptedFileTypes)
if (acceptedTypes && ! acceptedTypes.includes(file.type)) {
return onError(@js($fileAttachmentsAcceptedFileTypes ? __('filament-forms::components.markdown_editor.file_attachments_accepted_file_types_message', ['values' => implode(', ', $fileAttachmentsAcceptedFileTypes)]) : null))
}
const maxSize = @js($fileAttachmentsMaxSize)
if (maxSize && file.size > +maxSize * 1024) {
return onError(@js($fileAttachmentsMaxSize ? trans_choice('filament-forms::components.markdown_editor.file_attachments_max_size_message', $fileAttachmentsMaxSize, ['max' => $fileAttachmentsMaxSize]) : null))
}
$wire.upload(`componentFileAttachments.{{ $statePath }}`, file, () => {
$wire
.callSchemaComponentMethod(
'{{ $key }}',
'saveUploadedFileAttachmentAndGetUrl',
)
.then((url) => {
if (! url) {
return onError()
}
onSuccess(url)
})
})
},
})"
wire:ignore
{{ $getExtraAlpineAttributeBag() }}
>
<textarea x-ref="editor" x-cloak></textarea>
</div>
</x-filament::input.wrapper>
@endif
</x-dynamic-component>

View File

@@ -1,69 +0,0 @@
@php
use Filament\Forms\Components\TableSelect\Livewire\TableSelectLivewireComponent;
$fieldWrapperView = $getFieldWrapperView();
$extraAttributes = $getExtraAttributes();
$id = $getId();
$isDisabled = $isDisabled();
$isMultiple = $isMultiple();
$hasBadges = $hasBadges();
$badgeColor = $getBadgeColor();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge([
'id' => $id,
], escape: false)
->merge($extraAttributes, escape: false)
->class([
'fi-fo-modal-table-select',
'fi-fo-modal-table-select-disabled' => $isDisabled,
'fi-fo-modal-table-select-multiple' => $isMultiple,
])
}}
>
@if (((! $isMultiple) && filled($optionLabel = $getOptionLabel())) ||
($isMultiple && filled($optionLabels = $getOptionLabels())))
@if ($isMultiple && $hasBadges)
<div class="fi-fo-modal-table-select-badges-ctn">
@foreach ($optionLabels as $optionLabel)
@if ($hasBadges)
<x-filament::badge :color="$badgeColor">
{{ $optionLabel }}
</x-filament::badge>
@else
{{ $optionLabel }}
@endif
@endforeach
</div>
@else
<div>
@if ($hasBadges)
<x-filament::badge :color="$badgeColor">
{{ $optionLabel }}
</x-filament::badge>
@elseif ($isMultiple)
@foreach ($optionLabels as $optionLabel)
{{ $optionLabel . ($loop->last ? '' : ', ') }}
@endforeach
@else
{{ $optionLabel }}
@endif
</div>
@endif
@elseif (filled($placeholder = $getPlaceholder()))
<div class="fi-fo-modal-table-select-placeholder">
{{ $placeholder }}
</div>
@endif
@if (! $isDisabled)
<div>
{{ $getAction('select') }}
</div>
@endif
</div>
</x-dynamic-component>

View File

@@ -1,24 +0,0 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$placeholder = $getPlaceholder();
$extraAttributes = $getExtraAttributeBag()
->merge($getExtraInputAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->merge([
'autocomplete' => false,
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled(),
'id' => $getId(),
'length' => $getLength(),
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly(),
'required' => $isRequired() && (! $isConcealed()),
$applyStateBindingModifiers('wire:model') => $getStatePath(),
], escape: false);
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<x-filament::input.one-time-code
:attributes="\Filament\Support\prepare_inherited_attributes($extraAttributes)"
/>
</x-dynamic-component>

View File

@@ -1,41 +0,0 @@
@props([
'field' => null,
'id' => null,
'label' => null,
'labelTag' => 'label',
])
@php
use Illuminate\View\ComponentAttributeBag;
if ($field) {
$id ??= $field->getId();
$label ??= $field->getLabel();
}
@endphp
<div
data-field-wrapper
{{
(new ComponentAttributeBag)
->merge($field?->getExtraFieldWrapperAttributes() ?? [], escape: false)
->class([
'fi-fo-field',
])
}}
>
@if (filled($label))
<{{ $labelTag }}
@if ($labelTag === 'label')
for="{{ $id }}"
@else
id="{{ $id }}-label"
@endif
class="fi-fo-field-label fi-sr-only"
>
{{ $label }}
</{{ $labelTag }}>
@endif
{{ $slot }}
</div>

View File

@@ -1,64 +0,0 @@
@php
use Filament\Support\Enums\GridDirection;
use Illuminate\View\ComponentAttributeBag;
$fieldWrapperView = $getFieldWrapperView();
$extraInputAttributeBag = $getExtraInputAttributeBag();
$gridDirection = $getGridDirection() ?? GridDirection::Column;
$id = $getId();
$isDisabled = $isDisabled();
$isInline = $isInline();
$statePath = $getStatePath();
$wireModelAttribute = $applyStateBindingModifiers('wire:model');
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$getExtraAttributeBag()
->when(! $isInline, fn (ComponentAttributeBag $attributes) => $attributes->grid($getColumns(), $gridDirection))
->class([
'fi-fo-radio',
'fi-inline' => $isInline,
])
}}
>
@foreach ($getOptions() as $value => $label)
@php
$inputAttributes = $extraInputAttributeBag
->merge([
'disabled' => $isDisabled || $isOptionDisabled($value, $label),
'id' => $id . '-' . $value,
'name' => $id,
'value' => $value,
$wireModelAttribute => $statePath,
], escape: false);
@endphp
<label class="fi-fo-radio-label">
<input
type="radio"
{{
$inputAttributes->class([
'fi-radio-input',
'fi-valid' => ! $errors->has($statePath),
'fi-invalid' => $errors->has($statePath),
])
}}
/>
<div class="fi-fo-radio-label-text">
<p>
{{ $label }}
</p>
@if ($hasDescription($value))
<p class="fi-fo-radio-label-description">
{{ $getDescription($value) }}
</p>
@endif
</div>
</label>
@endforeach
</div>
</x-dynamic-component>

View File

@@ -1,263 +0,0 @@
@php
use Filament\Actions\Action;
use Filament\Support\Enums\Alignment;
use Illuminate\View\ComponentAttributeBag;
$fieldWrapperView = $getFieldWrapperView();
$items = $getItems();
$addAction = $getAction($getAddActionName());
$addActionAlignment = $getAddActionAlignment();
$addBetweenAction = $getAction($getAddBetweenActionName());
$cloneAction = $getAction($getCloneActionName());
$collapseAllAction = $getAction($getCollapseAllActionName());
$expandAllAction = $getAction($getExpandAllActionName());
$deleteAction = $getAction($getDeleteActionName());
$moveDownAction = $getAction($getMoveDownActionName());
$moveUpAction = $getAction($getMoveUpActionName());
$reorderAction = $getAction($getReorderActionName());
$extraItemActions = $getExtraItemActions();
$hasItemNumbers = $hasItemNumbers();
$hasItemHeaders = $hasItemHeaders();
$isAddable = $isAddable();
$isCloneable = $isCloneable();
$isCollapsible = $isCollapsible();
$isDeletable = $isDeletable();
$isReorderableWithButtons = $isReorderableWithButtons();
$isReorderableWithDragAndDrop = $isReorderableWithDragAndDrop();
$collapseAllActionIsVisible = $isCollapsible && $collapseAllAction->isVisible();
$expandAllActionIsVisible = $isCollapsible && $expandAllAction->isVisible();
$key = $getKey();
$statePath = $getStatePath();
$itemLabelHeadingTag = $getHeadingTag();
$isItemLabelTruncated = $isItemLabelTruncated();
$labelBetweenItems = $getLabelBetweenItems();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-fo-repeater',
'fi-collapsible' => $isCollapsible,
])
}}
>
@if ($collapseAllActionIsVisible || $expandAllActionIsVisible)
<div
@class([
'fi-fo-repeater-actions',
'fi-hidden' => count($items) < 2,
])
>
@if ($collapseAllActionIsVisible)
<span
x-on:click="$dispatch('repeater-collapse', '{{ $statePath }}')"
>
{{ $collapseAllAction }}
</span>
@endif
@if ($expandAllActionIsVisible)
<span
x-on:click="$dispatch('repeater-expand', '{{ $statePath }}')"
>
{{ $expandAllAction }}
</span>
@endif
</div>
@endif
@if (count($items))
<ul
x-sortable
{{
(new ComponentAttributeBag)
->grid($getGridColumns())
->merge([
'data-sortable-animation-duration' => $getReorderAnimationDuration(),
'x-on:end.stop' => '$event.oldDraggableIndex !== $event.newDraggableIndex && $wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' . $key . '\' })',
], escape: false)
->class(['fi-fo-repeater-items'])
}}
>
@foreach ($items as $itemKey => $item)
@php
$itemLabel = $getItemLabel($itemKey);
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
$deleteAction = $deleteAction(['item' => $itemKey]);
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
$moveDownAction = $moveDownAction(['item' => $itemKey])->disabled($loop->last);
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
$hasItemHeader = $hasItemHeaders && ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || filled($itemLabel) || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions);
@endphp
<li
wire:ignore.self
wire:key="{{ $item->getLivewireKey() }}.item"
x-data="{
isCollapsed: @js($isCollapsed($item)),
}"
x-on:repeater-expand.window="$event.detail === '{{ $statePath }}' && (isCollapsed = false)"
x-on:repeater-collapse.window="$event.detail === '{{ $statePath }}' && (isCollapsed = true)"
x-on:expand="isCollapsed = false"
x-sortable-item="{{ $itemKey }}"
@class([
'fi-fo-repeater-item',
'fi-fo-repeater-item-has-header' => $hasItemHeader,
])
x-bind:class="{ 'fi-collapsed': isCollapsed }"
>
@if ($hasItemHeader)
<div
@if ($isCollapsible)
x-on:click.stop="isCollapsed = !isCollapsed"
@endif
class="fi-fo-repeater-item-header"
>
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
<ul
class="fi-fo-repeater-item-header-start-actions"
>
@if ($reorderActionIsVisible)
<li x-on:click.stop>
{{ $reorderAction->extraAttributes(['x-sortable-handle' => true], merge: true) }}
</li>
@endif
@if ($moveUpActionIsVisible || $moveDownActionIsVisible)
<li x-on:click.stop>
{{ $moveUpAction }}
</li>
<li x-on:click.stop>
{{ $moveDownAction }}
</li>
@endif
</ul>
@endif
@if (filled($itemLabel))
<{{ $itemLabelHeadingTag }}
@class([
'fi-fo-repeater-item-header-label',
'fi-truncated' => $isItemLabelTruncated,
])
>
{{ $itemLabel }}
@if ($hasItemNumbers)
{{ $loop->iteration }}
@endif
</{{ $itemLabelHeadingTag }}>
@endif
@if ($cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
<ul
class="fi-fo-repeater-item-header-end-actions"
>
@foreach ($visibleExtraItemActions as $extraItemAction)
<li x-on:click.stop>
{{ $extraItemAction(['item' => $itemKey]) }}
</li>
@endforeach
@if ($cloneActionIsVisible)
<li x-on:click.stop>
{{ $cloneAction }}
</li>
@endif
@if ($deleteActionIsVisible)
<li x-on:click.stop>
{{ $deleteAction }}
</li>
@endif
@if ($isCollapsible)
<li
class="fi-fo-repeater-item-header-collapsible-actions"
x-on:click.stop="isCollapsed = !isCollapsed"
>
<div
class="fi-fo-repeater-item-header-collapse-action"
>
{{ $getAction('collapse') }}
</div>
<div
class="fi-fo-repeater-item-header-expand-action"
>
{{ $getAction('expand') }}
</div>
</li>
@endif
</ul>
@endif
</div>
@endif
<div
x-show="! isCollapsed"
class="fi-fo-repeater-item-content"
>
{{ $item }}
</div>
</li>
@if (! $loop->last)
@if ($isAddable && $addBetweenAction(['afterItem' => $itemKey])->isVisible())
<li class="fi-fo-repeater-add-between-items-ctn">
<div class="fi-fo-repeater-add-between-items">
{{ $addBetweenAction(['afterItem' => $itemKey]) }}
</div>
</li>
@elseif (filled($labelBetweenItems))
<li class="fi-fo-repeater-label-between-items-ctn">
<div
class="fi-fo-repeater-label-between-items-divider-before"
></div>
<span
class="fi-fo-repeater-label-between-items"
>
{{ $labelBetweenItems }}
</span>
<div
class="fi-fo-repeater-label-between-items-divider-after"
></div>
</li>
@endif
@endif
@endforeach
</ul>
@endif
@if ($isAddable && $addAction->isVisible())
<div
@class([
'fi-fo-repeater-add',
($addActionAlignment instanceof Alignment) ? ('fi-align-' . $addActionAlignment->value) : $addActionAlignment,
])
>
{{ $addAction }}
</div>
@endif
</div>
</x-dynamic-component>

View File

@@ -1,129 +0,0 @@
@php
use Filament\Actions\Action;
use Filament\Support\Enums\Alignment;
use Illuminate\View\ComponentAttributeBag;
$fieldWrapperView = $getFieldWrapperView();
$items = $getItems();
$addAction = $getAction($getAddActionName());
$addActionAlignment = $getAddActionAlignment();
$cloneAction = $getAction($getCloneActionName());
$deleteAction = $getAction($getDeleteActionName());
$moveDownAction = $getAction($getMoveDownActionName());
$moveUpAction = $getAction($getMoveUpActionName());
$reorderAction = $getAction($getReorderActionName());
$extraItemActions = $getExtraItemActions();
$isAddable = $isAddable();
$isCloneable = $isCloneable();
$isDeletable = $isDeletable();
$isReorderableWithButtons = $isReorderableWithButtons();
$isReorderableWithDragAndDrop = $isReorderableWithDragAndDrop();
$key = $getKey();
$statePath = $getStatePath();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class(['fi-fo-simple-repeater'])
}}
>
@if (count($items))
<ul
x-sortable
{{
(new ComponentAttributeBag)
->grid($getGridColumns())
->merge([
'data-sortable-animation-duration' => $getReorderAnimationDuration(),
'x-on:end.stop' => '$event.oldDraggableIndex !== $event.newDraggableIndex && $wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' . $key . '\' })',
], escape: false)
->class(['fi-fo-simple-repeater-items'])
}}
>
@foreach ($items as $itemKey => $item)
@php
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
$deleteAction = $deleteAction(['item' => $itemKey]);
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
$moveDownAction = $moveDownAction(['item' => $itemKey])->disabled($loop->last);
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
@endphp
<li
wire:key="{{ $item->getLivewireKey() }}.item"
x-sortable-item="{{ $itemKey }}"
class="fi-fo-simple-repeater-item"
>
<div class="fi-fo-simple-repeater-item-content">
{{ $item }}
</div>
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $visibleExtraItemActions)
<ul class="fi-fo-simple-repeater-item-actions">
@if ($reorderActionIsVisible)
<li x-on:click.stop>
{{ $reorderAction->extraAttributes(['x-sortable-handle' => true], merge: true) }}
</li>
@endif
@if ($moveUpActionIsVisible || $moveDownActionIsVisible)
<li x-on:click.stop>
{{ $moveUpAction }}
</li>
<li x-on:click.stop>
{{ $moveDownAction }}
</li>
@endif
@foreach ($visibleExtraItemActions as $extraItemAction)
<li x-on:click.stop>
{{ $extraItemAction(['item' => $itemKey]) }}
</li>
@endforeach
@if ($cloneActionIsVisible)
<li x-on:click.stop>
{{ $cloneAction }}
</li>
@endif
@if ($deleteActionIsVisible)
<li x-on:click.stop>
{{ $deleteAction }}
</li>
@endif
</ul>
@endif
</li>
@endforeach
</ul>
@endif
@if ($isAddable && $addAction->isVisible())
<div
@class([
'fi-fo-simple-repeater-add',
($addActionAlignment instanceof Alignment) ? ('fi-align-' . $addActionAlignment->value) : $addActionAlignment,
])
>
{{ $addAction }}
</div>
@endif
</div>
</x-dynamic-component>

View File

@@ -1,231 +0,0 @@
@php
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Support\Enums\Alignment;
use Illuminate\Support\Js;
use Illuminate\View\ComponentAttributeBag;
$fieldWrapperView = $getFieldWrapperView();
$items = $getItems();
$addAction = $getAction($getAddActionName());
$addActionAlignment = $getAddActionAlignment();
$addBetweenAction = $getAction($getAddBetweenActionName());
$cloneAction = $getAction($getCloneActionName());
$deleteAction = $getAction($getDeleteActionName());
$moveDownAction = $getAction($getMoveDownActionName());
$moveUpAction = $getAction($getMoveUpActionName());
$reorderAction = $getAction($getReorderActionName());
$extraItemActions = $getExtraItemActions();
$isAddable = $isAddable();
$isCloneable = $isCloneable();
$isDeletable = $isDeletable();
$isReorderableWithButtons = $isReorderableWithButtons();
$isReorderableWithDragAndDrop = $isReorderableWithDragAndDrop();
$key = $getKey();
$statePath = $getStatePath();
$tableColumns = $getTableColumns();
$isCompact = $isCompact();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{ $attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-fo-table-repeater',
'fi-compact' => $isCompact,
]) }}
>
@if (count($items))
<table>
<thead>
<tr>
@if ((count($items) > 1) && ($isReorderableWithButtons || $isReorderableWithDragAndDrop))
<th
class="fi-fo-table-repeater-empty-header-cell"
></th>
@endif
@foreach ($tableColumns as $column)
<th
@class([
'fi-wrapped' => $column->canHeaderWrap(),
(($columnAlignment = $column->getAlignment()) instanceof Alignment) ? ('fi-align-' . $columnAlignment->value) : $columnAlignment,
])
@style([
('width: ' . ($columnWidth = $column->getWidth())) => filled($columnWidth),
])
>
@if (! $column->isHeaderLabelHidden())
{{ $column->getLabel() }}@if ($column->isMarkedAsRequired())<sup class="fi-fo-table-repeater-header-required-mark">*</sup>
@endif
@else
<span class="fi-sr-only">
{{ $column->getLabel() }}
</span>
@endif
</th>
@endforeach
@if (count($extraItemActions) || $isCloneable || $isDeletable)
<th
class="fi-fo-table-repeater-empty-header-cell"
></th>
@endif
</tr>
</thead>
<tbody
x-sortable
{{ (new ComponentAttributeBag)
->merge([
'data-sortable-animation-duration' => $getReorderAnimationDuration(),
'x-on:end.stop' => '$event.oldDraggableIndex !== $event.newDraggableIndex && $wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' . $key . '\' })',
], escape: false) }}
>
@foreach ($items as $itemKey => $item)
@php
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
$deleteAction = $deleteAction(['item' => $itemKey]);
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
$moveDownAction = $moveDownAction(['item' => $itemKey])->disabled($loop->last);
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
$itemStatePath = $item->getStatePath();
@endphp
<tr
wire:key="{{ $item->getLivewireKey() }}.item"
x-sortable-item="{{ $itemKey }}"
>
@if ((count($items) > 1) && ($isReorderableWithButtons || $isReorderableWithDragAndDrop))
<td>
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
<div
class="fi-fo-table-repeater-actions"
>
@if ($reorderActionIsVisible)
<div x-on:click.stop>
{{ $reorderAction->extraAttributes(['x-sortable-handle' => true], merge: true) }}
</div>
@endif
@if ($moveUpActionIsVisible || $moveDownActionIsVisible)
<div x-on:click.stop>
{{ $moveUpAction }}
</div>
<div x-on:click.stop>
{{ $moveDownAction }}
</div>
@endif
</div>
@endif
</td>
@endif
@php
$counter = 0
@endphp
@foreach ($item->getComponents(withHidden: true) as $schemaComponent)
@php
throw_unless(
$schemaComponent instanceof \Filament\Schemas\Components\Component,
new \Exception('Table repeaters must only contain schema components, but [' . $schemaComponent::class . '] was used.'),
);
@endphp
@if (count($tableColumns) > $counter)
@if ($schemaComponent instanceof \Filament\Forms\Components\Hidden)
{{ $schemaComponent }}
@else
@php
$counter++
@endphp
@if ($schemaComponent->isVisible())
@php
$schemaComponentStatePath = $schemaComponent->getStatePath();
@endphp
<td
x-data="filamentSchemaComponent({
path: @js($schemaComponentStatePath),
containerPath: @js($itemStatePath),
$wire,
})"
@if ($afterStateUpdatedJs = $schemaComponent->getAfterStateUpdatedJs())
x-init="{{ implode(';', array_map(
fn (string $js): string => '$wire.watch(' . Js::from($schemaComponentStatePath) . ', ($state, $old) => isStateChanged($state, $old) && eval(' . Js::from($js) . '))',
$afterStateUpdatedJs,
)) }}"
@endif
>
{{ $schemaComponent }}
</td>
@else
<td class="fi-hidden"></td>
@endif
@endif
@endif
@endforeach
@if (count($extraItemActions) || $isCloneable || $isDeletable)
<td>
@if ($visibleExtraItemActions || $cloneActionIsVisible || $deleteActionIsVisible)
<div
class="fi-fo-table-repeater-actions"
>
@foreach ($visibleExtraItemActions as $extraItemAction)
<div x-on:click.stop>
{{ $extraItemAction(['item' => $itemKey]) }}
</div>
@endforeach
@if ($cloneActionIsVisible)
<div x-on:click.stop>
{{ $cloneAction }}
</div>
@endif
@if ($deleteActionIsVisible)
<div x-on:click.stop>
{{ $deleteAction }}
</div>
@endif
</div>
@endif
</td>
@endif
</tr>
@endforeach
</tbody>
</table>
@endif
@if ($isAddable && $addAction->isVisible())
<div
@class([
'fi-fo-table-repeater-add',
($addActionAlignment instanceof Alignment) ? ('fi-align-' . $addActionAlignment->value) : $addActionAlignment,
])
>
{{ $addAction }}
</div>
@endif
</div>
</x-dynamic-component>

Some files were not shown because too many files have changed in this diff Show More