$this->getTabsContentComponent()->container($this->makeSchema())->toHtml(), scopes: static::class, ); } public function content(Schema $schema): Schema { return $schema ->components([ RenderHook::make(PanelsRenderHook::RESOURCE_RELATION_MANAGER_BEFORE), EmbeddedTable::make(), RenderHook::make(PanelsRenderHook::RESOURCE_RELATION_MANAGER_AFTER), ]); } public function getTabs(): array { $ownerRecord = $this->getOwnerRecord(); $counts = $ownerRecord->lines() ->selectRaw('status, count(*) as count') ->groupBy('status') ->pluck('count', 'status'); return [ 'all' => Tab::make('Mind') ->badge($counts->sum()), 'hibas' => Tab::make('Hibás') ->icon(PricelistFileLineStatusEnum::error->icon()) ->badgeColor(PricelistFileLineStatusEnum::error->color()) ->badge($counts->get(PricelistFileLineStatusEnum::error->value, 0)) ->modifyQueryUsing(fn (Builder $query) => $query->where('status', PricelistFileLineStatusEnum::error)), 'warning' => Tab::make('Figyelmeztetések') ->icon(PricelistFileLineStatusEnum::warning->icon()) ->badgeColor(PricelistFileLineStatusEnum::warning->color()) ->badge($counts->get(PricelistFileLineStatusEnum::warning->value, 0)) ->modifyQueryUsing(fn (Builder $query) => $query->where('status', PricelistFileLineStatusEnum::warning)), 'uj' => Tab::make('Új') ->icon(PricelistFileLineStatusEnum::new_product->icon()) ->badgeColor(PricelistFileLineStatusEnum::new_product->color()) ->badge($counts->get(PricelistFileLineStatusEnum::new_product->value, 0)) ->modifyQueryUsing(fn (Builder $query) => $query->where('status', PricelistFileLineStatusEnum::new_product)), 'modosult' => Tab::make('Módosult') ->icon(PricelistFileLineStatusEnum::updated->icon()) ->badgeColor(PricelistFileLineStatusEnum::updated->color()) ->badge($counts->get(PricelistFileLineStatusEnum::updated->value, 0)) ->modifyQueryUsing(fn (Builder $query) => $query->where('status', PricelistFileLineStatusEnum::updated)), ]; } public function form(Schema $schema): Schema { return $schema ->components([ Grid::make(1) ->schema([ Section::make('Módosulások') ->schema([ Text::make(fn ($record) => new HtmlString( '
' . collect($record->diff ?? [])->map(function ($d, $field) { $old = $d['old_label'] ?? $d['old'] ?? 'N/A'; $new = $d['new_label'] ?? $d['new'] ?? 'N/A'; $label = $d['label'] ?? $field; if ($old === '' || $old === null) $old = '(üres)'; if ($new === '' || $new === null) $new = '(üres)'; // Ár formázása ha árról van szó if ($field === 'price') { $old = number_format((float)($d['old'] ?? 0), 2, ',', ' ') . ' Ft'; $new = number_format((float)($d['new'] ?? 0), 2, ',', ' ') . ' Ft'; } return "
$label
$old $new
"; })->join('') . '
' )), ]) ->visible(fn ($record) => !empty($record->diff)), Section::make('Validációs üzenetek') ->schema([ Text::make(fn ($record) => new HtmlString( '' )), ]) ->visible(fn ($record) => !empty($record->validation_messages)), ]) ->columnSpan(1) ->visible(fn ($record) => !empty($record->diff) || !empty($record->validation_messages)), Section::make('Adatok') ->schema([ Text::make(fn ($record) => new HtmlString( ' ' . collect($record->payload ?? [])->map(function ($value, $key) { $valStr = is_array($value) ? json_encode($value) : (string)$value; return ''; })->join('') . '
Oszlop Érték
' . e($key) . ' ' . e($valStr) . '
' )), ]) ->columnSpan(fn ($record) => (empty($record->diff) && empty($record->validation_messages)) ? 2 : 1), ]); } public function table(Table $table): Table { return $table ->recordTitleAttribute('id') ->columns([ TextColumn::make('row_number') ->label('#') ->sortable() ->width('50px'), TextColumn::make('status') ->label('Státusz') ->badge() ->color(fn (PricelistFileLineStatusEnum $state) => $state->color()) ->formatStateUsing(fn (PricelistFileLineStatusEnum $state) => $state->label()) ->icon(fn (PricelistFileLineStatusEnum $state) => $state->icon()) ->sortable(), TextColumn::make('product_info') ->label('Termék') ->description(fn ($record) => $record->payload[PriceListService::EXPECTED_HEADERS[4]] ?? '') ->getStateUsing(fn ($record) => $record->payload[PriceListService::EXPECTED_HEADERS[0]] ?? 'N/A') ->color(fn ($record) => !empty($record->diff) ? 'info' : null) ->wrap() ->searchable(query: function ($query, string $search) { $sku = PriceListService::EXPECTED_HEADERS[0]; $name = PriceListService::EXPECTED_HEADERS[4]; $query->where("payload->$sku", 'like', "%{$search}%") ->orWhere("payload->$name", 'like', "%{$search}%"); }), TextColumn::make('price_diff') ->label('Árváltozás') ->html() ->getStateUsing(function ($record) { // Biztonságos elérés data_get-tel, mert a diff lehet null $oldPrice = data_get($record->diff, 'price.old'); // Az új árat a diff-ből vesszük (már float), vagy a payload-ból (string lehet) $newPriceRaw = data_get($record->diff, 'price.new') ?? data_get($record->payload, PriceListService::EXPECTED_HEADERS[14]); // Normalizálás: szóközök eltávolítása és tizedesvessző cseréje $newPrice = is_string($newPriceRaw) ? (float) str_replace([' ', ','], ['', '.'], $newPriceRaw) : (float) $newPriceRaw; // Ha nincs régi ár, vagy az nulla, akkor nincs százalékos számítás if (empty($oldPrice) || (float)$oldPrice === 0.0) { return number_format($newPrice, 2, ',', ' ') . ' Ft'; } $oldPrice = (float) $oldPrice; $diffPercent = (($newPrice / $oldPrice) - 1) * 100; $colorClass = $diffPercent > 0 ? 'text-danger-600' : ($diffPercent < 0 ? 'text-success-600' : 'text-gray-600'); $icon = $diffPercent > 0 ? '↑' : ($diffPercent < 0 ? '↓' : ''); return sprintf( '
%s Ft %s Ft %s %s%%
', number_format($oldPrice, 2, ',', ' '), number_format($newPrice, 2, ',', ' '), $colorClass, $icon, number_format(abs($diffPercent), 1, ',', ' ') ); }) ->visible(fn ($livewire) => $livewire->getOwnerRecord()->status !== PricelistFileStatusEnum::todo), TextColumn::make('validation_messages') ->label('Megjegyzés') ->listWithLineBreaks() ->bulleted() ->wrap() ->color(fn ($state) => collect($state)->contains(fn ($msg) => str_contains($msg, 'Hiányzó') || str_contains($msg, 'Ismeretlen') || str_contains($msg, 'Érvénytelen')) ? 'danger' : 'info') ->getStateUsing(function ($record) { $messages = collect($record->validation_messages ?? [])->values(); $diffMessages = collect($record->diff ?? [])->map(function ($d, $field) { $label = $d['label'] ?? $field; $old = $d['old_label'] ?? $d['old'] ?? 'N/A'; $new = $d['new_label'] ?? $d['new'] ?? 'N/A'; if ($field === 'price') { $old = number_format((float)($d['old'] ?? 0), 0, ',', ' ') . ' Ft'; $new = number_format((float)($d['new'] ?? 0), 0, ',', ' ') . ' Ft'; } return "Módosult $label: $old -> $new"; })->values(); return $messages->merge($diffMessages)->toArray(); }), ]) ->filters([ // ]) ->headerActions([ // ]) ->actions([ ViewAction::make() ->slideOver() ->modalWidth(Width::FourExtraLarge) ->iconButton() ->modalHeading(fn ($record) => "Sor száma: #{$record->row_number}") ->modalDescription(fn ($record) => "Státusz: " . $record->status->label()), ]) ->bulkActions([ // ]) ->defaultSort('row_number', 'asc') ->striped() ->poll('5s'); } }