Work work work

orders
Nisse Lommerde 1 month ago
parent 3e2c5d5fac
commit b9346c4466

@ -0,0 +1,9 @@
const {join} = require('path');
/**
* @type {import("puppeteer").Configuration}
*/
module.exports = {
// Changes the cache location for Puppeteer.
cacheDirectory: join(__dirname, '.cache', 'puppeteer'),
};

@ -10,6 +10,7 @@ use App\Models\Contact;
use App\Models\Customer; use App\Models\Customer;
use App\Models\Order; use App\Models\Order;
use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
@ -36,24 +37,6 @@ class OrderResource extends Resource
public static function form(Form $form): Form public static function form(Form $form): Form
{ {
return $form->schema([ return $form->schema([
// Wizard::make([
// Wizard\Step::make('Order Details')
// ->schema(self::getOrderDetails())
// ->columns(2),
// Wizard\Step::make('Garment Details')
// ->schema(self::getGarmentDetails()),
// Wizard\Step::make('Production Details')
// ->schema(self::getProductionDetails()),
// ])
// ->skippable()
// ->submitAction(new HtmlString(Blade::render(<<<'BLADE'
// <x-filament::button
// type="submit"
// size="sm"
// >
// Submit
// </x-filament::button>
// BLADE))),
Section::make([ Section::make([
Section::make([ Section::make([
@ -111,12 +94,9 @@ class OrderResource extends Resource
->relationship('orderProducts') ->relationship('orderProducts')
->label('Garments') ->label('Garments')
->schema([ ->schema([
TextInput::make('sku') TextInput::make('sku'),
->columnSpan(1), TextInput::make('product_name'),
TextInput::make('product_name') TextInput::make('color'),
->columnSpan(2),
TextInput::make('color')
->columnSpan(1),
Cluster::make([ Cluster::make([
TextInput::make('xs') TextInput::make('xs')
->placeholder('xs'), ->placeholder('xs'),
@ -135,8 +115,7 @@ class OrderResource extends Resource
TextInput::make('osfa') TextInput::make('osfa')
->placeholder('osfa'), ->placeholder('osfa'),
]) ])
->label('Sizes') ->label('Sizes'),
->columnSpan(5),
]) ])
->reorderable() ->reorderable()
->cloneable(), ->cloneable(),
@ -145,29 +124,61 @@ class OrderResource extends Resource
->relationship('productServices') ->relationship('productServices')
->label('Production Details') ->label('Production Details')
->schema([ ->schema([
TextInput::make('service_type') Grid::make(19)
->datalist([ ->schema([
'Embroidery', TextInput::make('service_type')
'Screen Printing', ->datalist([
'Vinyl', 'Embroidery',
'Editing', 'SCP',
'Digitizing', 'Vinyl',
]) 'Editing',
->grow(false), 'Digitizing',
TextInput::make('placement'), ])
TextInput::make('serviceFile.name') ->columnSpan(2),
->label('Logo Name'), TextInput::make('placement')
->columnSpan(3),
TextInput::make('serviceFile.code'), TextInput::make('service_file_name')
TextInput::make('serviceFile.setup_number'), ->columnSpan(3)
TextInput::make('serviceFile.width'), ->label('Logo Name'),
TextInput::make('serviceFile.height'), TextInput::make('service_file_setup_number')
TextInput::make('amount') ->label('Setup')
->label('Quantity'), ->columnSpan(1),
TextInput::make('amount_price'),
Cluster::make([
Textarea::make('notes') TextInput::make('service_file_width')
->placeholder('Thread colors...'), ->prefix('w')
->placeholder('Width'),
TextInput::make('service_file_height')
->prefix('h')
->placeholder('Height'),
])
->label('Dimensions')
->columnSpan(4),
TextInput::make('amount')
->label('Quantity')
->prefix('#')
->columnSpan(2),
TextInput::make('amount_price')
->prefix('$')
->columnSpan(2),
TextInput::make('total_price')
->prefix('$')
->readOnly()
->columnSpan(2),
]),
Grid::make(9)
->schema([
TextInput::make('service_file_code')
->label('Code')
->columnSpan(1)
->placeholder('A1234'),
Textarea::make('notes')
->placeholder('Thread colors...')
->columnSpan(8),
]),
]) ])
->reorderable() ->reorderable()
->cloneable() ->cloneable()
@ -229,7 +240,6 @@ class OrderResource extends Resource
public static function getRelations(): array public static function getRelations(): array
{ {
return [ return [
// OrderProductsRelationManager::class,
]; ];
} }
@ -238,135 +248,8 @@ class OrderResource extends Resource
return [ return [
'index' => Pages\ListOrders::route('/'), 'index' => Pages\ListOrders::route('/'),
'create' => Pages\CreateOrder::route('/create'), 'create' => Pages\CreateOrder::route('/create'),
'edit' => Pages\EditOrder::route('/{record}/edit'), // 'view' => Pages\ViewOrder::route('/{record}'),
]; 'edit' => Pages\EditOrder::route('/{record}/edit'),
}
private static function getOrderDetails(): array
{
return [
Section::make([
Select::make('order_type')
->required()
->options(OrderType::class)
->searchable(),
Split::make([
Select::make('customer_id')
->required()
->label('Customer')
->options(Customer::all()->pluck('company_name', 'id'))
->reactive()
->searchable(),
Select::make('contact_id')
->label('Contact')
->options(fn ($get): array => Contact::where('customer_id', $get('customer_id') ?? null)->get()->pluck('full_name', 'id')->toArray())
->searchable(),
]),
TextInput::make('customer_po')
->required()
->label('Customer PO'),
Split::make([
DatePicker::make('order_date')
->required()
->default(today()),
DatePicker::make('due_date')
->required()
->default(today()->add('10 days')),
]),
])->columnSpan(1),
Section::make([
ToggleButtons::make('status')
->required()
->options(OrderStatus::class)
->inline(),
ToggleButtons::make('order_attributes')
->options(OrderAttributes::class)
->multiple()
->inline(),
Textarea::make('notes')
->rows(3),
])->columnSpan(1),
];
}
private static function getGarmentDetails(): array
{
return [
Repeater::make('Garments')
->relationship('orderProducts')
->schema([
Split::make([
TextInput::make('sku')->grow(true),
TextInput::make('product_name')->grow(false),
TextInput::make('color')->grow(true),
]),
Split::make([
Cluster::make([
TextInput::make('xs')
->placeholder('xs'),
TextInput::make('s')
->placeholder('s'),
TextInput::make('m')
->placeholder('m'),
TextInput::make('l')
->placeholder('l'),
TextInput::make('xl')
->placeholder('xl'),
TextInput::make('2xl')
->placeholder('2xl'),
TextInput::make('3xl')
->placeholder('3xl'),
TextInput::make('osfa')
->placeholder('osfa'),
])->label('Sizes'),
]),
])->grid(1),
];
}
private static function getProductionDetails(): array
{
return [
Repeater::make('Production Details')
->relationship('productServices')
->schema([
Split::make([
TextInput::make('service_type')
->datalist([
'Embroidery',
'Screen Printing',
'Vinyl',
'Editing',
'Digitizing',
])
->grow(false),
TextInput::make('placement'),
TextInput::make('serviceFile.name')
->label('Logo Name'),
]),
Split::make([
TextInput::make('serviceFile.code'),
TextInput::make('serviceFile.setup_number'),
TextInput::make('serviceFile.width'),
TextInput::make('serviceFile.height'),
TextInput::make('amount')
->label('Quantity'),
TextInput::make('amount_price'),
]),
Textarea::make('notes')
->placeholder('Thread colors...'),
])
->defaultItems(2),
]; ];
} }
} }

@ -4,7 +4,9 @@ namespace App\Filament\Resources\OrderResource\Pages;
use App\Enums\OrderAttributes; use App\Enums\OrderAttributes;
use App\Filament\Resources\OrderResource; use App\Filament\Resources\OrderResource;
use App\Models\Order;
use Filament\Actions; use Filament\Actions;
use Filament\Actions\Action;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
class EditOrder extends EditRecord class EditOrder extends EditRecord
@ -42,7 +44,12 @@ class EditOrder extends EditRecord
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [
Actions\DeleteAction::make(), Action::make('print')
->icon('heroicon-s-printer')
->url(fn (Order $record) => route('orders.pdf', $record))
->openUrlInNewTab(),
Actions\DeleteAction::make()
->icon('heroicon-s-trash'),
]; ];
} }
} }

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\OrderResource\Pages;
use App\Filament\Resources\OrderResource;
use Filament\Resources\Pages\ViewRecord;
class ViewOrder extends ViewRecord
{
protected static string $resource = OrderResource::class;
}

@ -17,6 +17,8 @@ class RushOrdersTable extends BaseWidget
Order::query() Order::query()
->where('status', '!=', OrderStatus::SHIPPED) ->where('status', '!=', OrderStatus::SHIPPED)
->where('status', '!=', OrderStatus::INVOICED) ->where('status', '!=', OrderStatus::INVOICED)
->where('rush', true)
->orderByDesc('due_date')
) )
->columns([ ->columns([
TextColumn::make('customer.company_name'), TextColumn::make('customer.company_name'),

@ -12,6 +12,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Spatie\Browsershot\Browsershot;
use Spatie\LaravelPdf\Facades\Pdf;
class Order extends Model class Order extends Model
{ {
@ -102,6 +104,19 @@ class Order extends Model
return false; return false;
} }
public function generatePdf(): \Illuminate\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
{
Pdf::view('pdf.order', ['order' => $this])
->withBrowsershot(function (Browsershot $browsershot) {
$browsershot->noSandbox();
})
->margins(8, 8, 15, 8)
->footerView('pdf.order-footer', ['order' => $this])
->save('order.pdf');
return redirect('order.pdf');
}
/** /**
* @param Builder<Order> $query * @param Builder<Order> $query
* @return Builder<Order> * @return Builder<Order>

@ -23,6 +23,44 @@ class ProductService extends Model
'notes', 'notes',
]; ];
protected $appends = [
'service_file_name',
'service_file_setup_number',
'service_file_width',
'service_file_height',
'service_file_code',
];
public function getServiceFileNameAttribute(): string
{
return $this->serviceFile->name ?? '';
}
public function getServiceFileSetupNumberAttribute(): string
{
return $this->serviceFile->setup_number ?? '';
}
public function getServiceFileWidthAttribute(): string
{
return $this->serviceFile->width ?? '';
}
public function getServiceFileHeightAttribute(): string
{
return $this->serviceFile->height ?? '';
}
public function getServiceFileCodeAttribute(): string
{
return $this->serviceFile->code ?? '';
}
public function setServiceFileName(string $name): void
{
$this->serviceFile->name = $name;
}
/** /**
* @return BelongsTo<Order, self> * @return BelongsTo<Order, self>
*/ */

@ -11,7 +11,7 @@ return new class extends Migration
Schema::create('product_services', function (Blueprint $table) { Schema::create('product_services', function (Blueprint $table) {
$table->id(); $table->id();
$table->foreignId('order_id'); $table->foreignId('order_id');
$table->foreignId('service_file_id'); $table->foreignId('service_file_id')->nullable();
$table->string('service_type'); $table->string('service_type');
$table->string('placement'); $table->string('placement');
$table->string('amount')->nullable(); $table->string('amount')->nullable();

@ -70,6 +70,8 @@ RUN npx puppeteer browsers install chrome \
libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 \ libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 \
libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils
EXPOSE 80/tcp EXPOSE 80/tcp
ENTRYPOINT ["start-container"] ENTRYPOINT ["start-container"]

96
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "topnotch_website", "name": "html",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"bootstrap-icons": "^1.11.3", "bootstrap-icons": "^1.11.3",
"puppeteer": "^23.4.0" "puppeteer": "^23.6.0"
}, },
"devDependencies": { "devDependencies": {
"@popperjs/core": "^2.11.6", "@popperjs/core": "^2.11.6",
@ -34,12 +34,12 @@
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.24.7", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.9.tgz",
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "integrity": "sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/highlight": "^7.24.7", "@babel/highlight": "^7.25.9",
"picocolors": "^1.0.0" "picocolors": "^1.0.0"
}, },
"engines": { "engines": {
@ -47,21 +47,21 @@
} }
}, },
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.24.7", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/highlight": { "node_modules/@babel/highlight": {
"version": "7.24.7", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz",
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.24.7", "@babel/helper-validator-identifier": "^7.25.9",
"chalk": "^2.4.2", "chalk": "^2.4.2",
"js-tokens": "^4.0.0", "js-tokens": "^4.0.0",
"picocolors": "^1.0.0" "picocolors": "^1.0.0"
@ -1093,9 +1093,9 @@
} }
}, },
"node_modules/b4a": { "node_modules/b4a": {
"version": "1.6.6", "version": "1.6.7",
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
"integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/balanced-match": { "node_modules/balanced-match": {
@ -1106,9 +1106,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/bare-events": { "node_modules/bare-events": {
"version": "2.4.2", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz",
"integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==",
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true "optional": true
}, },
@ -1142,13 +1142,12 @@
} }
}, },
"node_modules/bare-stream": { "node_modules/bare-stream": {
"version": "2.3.0", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.2.tgz",
"integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", "integrity": "sha512-EFZHSIBkDgSHIwj2l2QZfP4U5OcD4xFAOwhSb/vlr9PIqyGJGvB/nfClJbcnh3EY4jtPE4zsb5ztae96bVF79A==",
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"b4a": "^1.6.6",
"streamx": "^2.20.0" "streamx": "^2.20.0"
} }
}, },
@ -1399,9 +1398,9 @@
} }
}, },
"node_modules/chromium-bidi": { "node_modules/chromium-bidi": {
"version": "0.6.5", "version": "0.8.0",
"resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.5.tgz", "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.8.0.tgz",
"integrity": "sha512-RuLrmzYrxSb0s9SgpB+QN5jJucPduZQ/9SIe76MDxYJuecPW5mxMdacJ1f4EtgiV+R0p3sCkznTMvH0MPGFqjA==", "integrity": "sha512-uJydbGdTw0DEUjhoogGveneJVWX/9YuqkWePzMmkBYwtdAqo5d3J/ovNKFr+/2hWXYmYCr6it8mSSTIj6SS6Ug==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"mitt": "3.0.1", "mitt": "3.0.1",
@ -1569,9 +1568,9 @@
} }
}, },
"node_modules/devtools-protocol": { "node_modules/devtools-protocol": {
"version": "0.0.1342118", "version": "0.0.1354347",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1354347.tgz",
"integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", "integrity": "sha512-BlmkSqV0V84E2WnEnoPnwyix57rQxAM5SKJjf4TbYOCGLAWtz8CDH8RIaGOjPgPCXo2Mce3kxSY497OySidY3Q==",
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/didyoumean": { "node_modules/didyoumean": {
@ -2849,17 +2848,17 @@
} }
}, },
"node_modules/puppeteer": { "node_modules/puppeteer": {
"version": "23.4.0", "version": "23.6.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.4.0.tgz", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.6.0.tgz",
"integrity": "sha512-FxgFFJI7NAsX8uebiEDSjS86vufz9TaqERQHShQT0lCbSRI3jUPEcz/0HdwLiYvfYNsc1zGjqY3NsGZya4PvUA==", "integrity": "sha512-l+Fgo8SVFSd51STtq2crz8t1Y3VXowsuR4zfR64qDOn6oggz7YIZauWiNR4IJjczQ6nvFs3S4cgng55/nesxTQ==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@puppeteer/browsers": "2.4.0", "@puppeteer/browsers": "2.4.0",
"chromium-bidi": "0.6.5", "chromium-bidi": "0.8.0",
"cosmiconfig": "^9.0.0", "cosmiconfig": "^9.0.0",
"devtools-protocol": "0.0.1342118", "devtools-protocol": "0.0.1354347",
"puppeteer-core": "23.4.0", "puppeteer-core": "23.6.0",
"typed-query-selector": "^2.12.0" "typed-query-selector": "^2.12.0"
}, },
"bin": { "bin": {
@ -2870,15 +2869,15 @@
} }
}, },
"node_modules/puppeteer-core": { "node_modules/puppeteer-core": {
"version": "23.4.0", "version": "23.6.0",
"resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.4.0.tgz", "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.6.0.tgz",
"integrity": "sha512-fqkIP5FOcb38jfBj/OcBz1wFaI9nk40uQKSORvnXws6wCbep2dg8yxZ3ddJxBIfQsxoiEOvnrykFinUScrB/ew==", "integrity": "sha512-se1bhgUpR9C529SgHGr/eyT92mYyQPAhA2S9pGtGrVG2xob9qE6Pbp7TlqiSPlnnY1lINqhn6/67EwkdzOmKqQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@puppeteer/browsers": "2.4.0", "@puppeteer/browsers": "2.4.0",
"chromium-bidi": "0.6.5", "chromium-bidi": "0.8.0",
"debug": "^4.3.7", "debug": "^4.3.7",
"devtools-protocol": "0.0.1342118", "devtools-protocol": "0.0.1354347",
"typed-query-selector": "^2.12.0", "typed-query-selector": "^2.12.0",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
@ -3368,13 +3367,10 @@
} }
}, },
"node_modules/text-decoder": { "node_modules/text-decoder": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.1.tgz",
"integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==", "integrity": "sha512-x9v3H/lTKIJKQQe7RPQkLfKAnc9lUTkWDypIQgTzPJAq+5/GCDHonmshfvlsNSj58yyshbIJJDLmU15qNERrXQ==",
"license": "Apache-2.0", "license": "Apache-2.0"
"dependencies": {
"b4a": "^1.6.4"
}
}, },
"node_modules/thenify": { "node_modules/thenify": {
"version": "3.3.1", "version": "3.3.1",
@ -3426,9 +3422,9 @@
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.7.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/typed-query-selector": { "node_modules/typed-query-selector": {

@ -18,6 +18,6 @@
}, },
"dependencies": { "dependencies": {
"bootstrap-icons": "^1.11.3", "bootstrap-icons": "^1.11.3",
"puppeteer": "^23.4.0" "puppeteer": "^23.6.0"
} }
} }

Binary file not shown.

@ -0,0 +1,194 @@
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
@php
$containers = $getChildComponentContainers();
$addAction = $getAction($getAddActionName());
$cloneAction = $getAction($getCloneActionName());
$deleteAction = $getAction($getDeleteActionName());
$moveDownAction = $getAction($getMoveDownActionName());
$moveUpAction = $getAction($getMoveUpActionName());
$reorderAction = $getAction($getReorderActionName());
$isAddable = $isAddable();
$isCloneable = $isCloneable();
$isCollapsible = $isCollapsible();
$isDeletable = $isDeletable();
$isReorderable = $isReorderable();
$isReorderableWithButtons = $isReorderableWithButtons();
$isReorderableWithDragAndDrop = $isReorderableWithDragAndDrop();
$statePath = $getStatePath();
$columnLabels = $getColumnLabels();
$colStyles = $getColStyles();
@endphp
<div
{{-- x-data="{ state: $wire.entangle('{{ $getStatePath() }}') }" --}}
x-data="{ isCollapsed: @js($isCollapsed()) }"
x-on:repeater-collapse.window="$event.detail === '{{ $getStatePath() }}' && (isCollapsed = true)"
x-on:repeater-expand.window="$event.detail === '{{ $getStatePath() }}' && (isCollapsed = false)"
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class(['bg-white border border-gray-300 shadow-sm rounded-xl relative dark:bg-gray-900 dark:border-gray-700'])
}}
>
<div @class([
'filament-tables-header',
'flex items-center h-10 overflow-hidden border-b bg-gray-50 rounded-t-xl',
'dark:bg-gray-900 dark:border-gray-700',
])>
<div class="flex-1"></div>
@if ($isCollapsible)
<div>
<button
x-on:click="isCollapsed = !isCollapsed"
type="button"
@class([
'flex items-center justify-center flex-none w-10 h-10 text-gray-400 transition hover:text-gray-300',
'dark:text-gray-400 dark:hover:text-gray-500',
])
>
<x-heroicon-s-minus-small class="w-4 h-4" x-show="! isCollapsed"/>
<span class="sr-only" x-show="! isCollapsed">
{{ __('forms::components.repeater.buttons.collapse_item.label') }}
</span>
<x-heroicon-s-plus-small class="w-4 h-4" x-show="isCollapsed" x-cloak/>
<span class="sr-only" x-show="isCollapsed" x-cloak>
{{ __('forms::components.repeater.buttons.expand_item.label') }}
</span>
</button>
</div>
@endif
</div>
<div class="px-4{{ $isAddable? '' : ' py-2' }}">
<table class="it-table-repeater w-full text-left rtl:text-right table-auto mx-4" x-show="! isCollapsed">
<thead>
<tr>
@foreach($columnLabels as $columnLabel)
@if($columnLabel['display'])
<th class="it-table-repeater-cell-label p-2"
@if($colStyles && isset($colStyles[$columnLabel['component']]))
style="{{ $colStyles[$columnLabel['component']] }}"
@endif
>
<span>
{{ $columnLabel['name'] }}
</span>
</th>
@else
<th style="display: none"></th>
@endif
@endforeach
@if ($isReorderableWithDragAndDrop || $isReorderableWithButtons || $isCloneable || $isDeletable)
<th></th>
@endif
</tr>
</thead>
<tbody
@if($isReorderable)
{{-- :wire:end.stop="'mountFormComponentAction(\'' . $statePath . '\', \'reorder\', { items: $event.target.sortable.toArray() })'" --}}
x-sortable
@endif
>
@foreach ($containers as $uuid => $item)
<tr
class="it-table-repeater-row"
x-on:repeater-collapse.window="$event.detail === '{{ $getStatePath() }}' && (isCollapsed = true)"
x-on:repeater-expand.window="$event.detail === '{{ $getStatePath() }}' && (isCollapsed = false)"
wire:key="{{ $this->getId() }}.{{ $item->getStatePath() }}.{{ $field::class }}.item"
x-sortable-item="{{ $uuid }}"
>
@foreach($item->getComponents() as $component)
<td
class="it-table-repeater-cell px-1 py-2 align-top"
@if($component->isHidden() || ($component instanceof \Filament\Forms\Components\Hidden))style="display:none"@endif
@if($colStyles && isset($colStyles[$component->getName()]))
style="{{ $colStyles[$component->getName()] }}"
@endif
>
{{ $component }}
</td>
@endforeach
@if ($isReorderableWithDragAndDrop || $isReorderableWithButtons || filled($itemLabel) || $isCloneable || $isDeletable || $isCollapsible)
<td class="flex items-center gap-x-3 py-2 max-w-20">
@if ($isReorderableWithDragAndDrop || $isReorderableWithButtons)
@if ($isReorderableWithDragAndDrop)
<div x-sortable-handle>
{{ $reorderAction }}
</div>
@endif
@if ($isReorderableWithButtons)
<div
class="flex items-center justify-center"
>
{{ $moveUpAction(['item' => $uuid])->disabled($loop->first) }}
</div>
<div
class="flex items-center justify-center"
>
{{ $moveDownAction(['item' => $uuid])->disabled($loop->last) }}
</div>
@endif
@endif
@if ($isCloneable || $isDeletable )
@if ($cloneAction->isVisible())
<div>
{{ $cloneAction(['item' => $uuid]) }}
</div>
@endif
@if ($isDeletable)
<div>
{{ $deleteAction(['item' => $uuid]) }}
</div>
@endif
@endif
</td>
@endif
</tr>
@endforeach
</tbody>
</table>
<div class="p-2 text-xs text-center text-gray-400" x-show="isCollapsed" x-cloak>
{{ __('filament-table-repeater::components.table-repeater.collapsed') }}
</div>
</div>
@if($isAddable)
<div class="relative flex justify-center py-2">
{{ $addAction }}
</div>
@endif
</div>
</x-dynamic-component>
Loading…
Cancel
Save