schema([ Section::make('') ->schema([ Forms\Components\Select::make('plant_id') ->relationship('plant', 'name') ->required() // ->nullable() ->reactive() ->options(function (callable $get) { $userHas = Filament::auth()->user()->plant_id; return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray(); }) ->default(function () { return optional(ProductionLineStop::latest()->first())->plant_id; }) ->disabled(fn (Get $get) => !empty($get('id'))) // ->afterStateUpdated(fn ($set) => $set('block_name', null)) ->afterStateUpdated(function ($state, callable $set, callable $get) { $plantId = $get('plant_id'); $set('block_name', null); if (!$plantId) { $set('plsPlantError', 'Please select a plant first.'); return; } else { $set('plsPlantError', null); } }) ->extraAttributes(fn ($get) => [ 'class' => $get('plsPlantError') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('plsPlantError') ? $get('plsPlantError') : null) ->hintColor('danger'), Forms\Components\Select::make('block_name') ->required() // ->nullable() ->label('Block') ->options(function (callable $get) { if (!$get('plant_id')) { return []; } // return \App\Models\Block::where('plant_id', $get('plant_id')) return Block::where('plant_id', $get('plant_id')) ->pluck('name', 'id') ->toArray(); }) ->reactive() ->default(function () { $latestShiftId = optional(ProductionLineStop::latest()->first())->shift_id; return optional(Shift::where('id', $latestShiftId)->first())->block_id; }) // ->afterStateUpdated(fn ($set) => $set('shift_id', null)) ->afterStateUpdated(function ($state, callable $set, callable $get) { if($get('id')) { $getShift = ProductionLineStop::where('id', $get('id'))->first(); // $getBlock = \App\Models\Shift::where('id', $getShift->shift_id)->first(); $getBlock = Shift::where('id', $getShift->shift_id)->first(); if($getBlock->block_id) { $set('block_name', $getBlock->block_id); $set('plsBlockError', null); } } $blockId = $get('block_name'); $set('shift_id', null); if (!$blockId) { $set('plsBlockError', 'Please select a block first.'); return; } else { $set('plsBlockError', null); } }) ->extraAttributes(fn ($get) => [ 'class' => $get('plsBlockError') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('plsBlockError') ? $get('plsBlockError') : null) ->hintColor('danger'), Forms\Components\Select::make('shift_id') ->relationship('shift', 'name') ->required() // ->nullable() ->options(function (callable $get) { if (!$get('plant_id') || !$get('block_name')) { return []; } return Shift::where('plant_id', $get('plant_id')) ->where('block_id', $get('block_name')) ->pluck('name', 'id') ->toArray(); }) ->reactive() ->default(function () { return optional(ProductionLineStop::latest()->first())->shift_id; }) // ->afterStateUpdated(fn ($set) => $set('line_id', null)) ->afterStateUpdated(function ($state, callable $set, callable $get) { if($get('id')) { $getShift = ProductionLineStop::where('id', $get('id'))->first(); if($getShift->shift_id) { $set('shift_id', $getShift->shift_id); $set('plsShiftError', null); } } $shiftId = $get('shift_id'); $set('line_id', null); if (!$shiftId) { $set('plsShiftError', 'Please select a shift first.'); return; } else { $set('plsShiftError', null); } }) ->extraAttributes(fn ($get) => [ 'class' => $get('plsShiftError') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('plsShiftError') ? $get('plsShiftError') : null) ->hintColor('danger'), Forms\Components\Select::make('line_id') ->relationship('line', 'name') ->required() // ->nullable() ->options(function (callable $get) { if (!$get('plant_id') || !$get('block_name') || !$get('shift_id')) { return []; } // return \App\Models\Line::where('plant_id', $get('plant_id')) return Line::where('plant_id', $get('plant_id')) ->pluck('name', 'id') ->toArray(); }) ->reactive() ->default(function () { return optional(ProductionLineStop::latest()->first())->line_id; }) ->afterStateUpdated(function ($state, callable $set, callable $get) { if($get('id')) { $getShift = ProductionLineStop::where('id', $get('id'))->first(); if($getShift->line_id) { $set('line_id', $getShift->line_id); $set('plsLineError', null); } } $lineId = $get('line_id'); $set('linestop_id', null); $set('lineStop_reason', null); if (!$lineId) { $set('plsLineError', 'Please select a line first.'); return; } else { $set('plsLineError', null); } }) ->extraAttributes(fn ($get) => [ 'class' => $get('plsLineError') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('plsLineError') ? $get('plsLineError') : null) ->hintColor('danger'), // Forms\Components\Select::make('linestop_id') // ->label('Line Stop Code') // ->relationship('linestop', 'code') // ->searchable() // ->required() // ->nullable() // ->reactive(), Forms\Components\Select::make('linestop_id') ->label('Line Stop Code') // ->options(fn (callable $get) => // \App\Models\LineStop::where('id', $get('linestop_id')) // ->pluck('code', 'id') // ) ->placeholder('Scan the valid code') ->autofocus(true) ->options(fn () => LineStop::pluck('code', 'id')) ->required() // ->nullable() // ->reactive() ->optionsLimit(5) ->searchable() ->loadingMessage('Loading line stop codes...') ->live(debounce: 500) // Enable live updates ->afterStateUpdated(function ($state, callable $set, callable $get) { $lineStopId = $get('linestop_id'); // Get entered linestop_id // Ensure `linestop_id` is not cleared if (!$lineStopId) { $set('lineStop_reason', null); return; } // Check if item exists for the selected plant $lineStop = LineStop::where('id', $lineStopId) ->where('id', $lineStopId) ->first(); $set('lineStop_reason', $lineStop?->reason ?? null); }), Forms\Components\TextInput::make('lineStop_reason') ->label('Line Stop Reason') ->required() ->reactive() ->readOnly(true), Forms\Components\DateTimePicker::make('from_datetime') ->label('From DateTime') ->required() ->before('to_datetime') ->reactive() // ->closeOnDateSelection() ->afterStateUpdated(fn ($state, callable $set, callable $get) => self::updateStopDuration($get, $set) ), Forms\Components\DateTimePicker::make('to_datetime') ->label('To DateTime') ->required() ->after('from_datetime') ->reactive() ->afterStateUpdated(fn ($state, callable $set, callable $get) => self::updateStopDuration($get, $set) //self means it calling the function within the class ) ->extraAttributes(fn ($get) => [ 'class' => $get('plsToDateError') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('plsToDateError') ? $get('plsToDateError') : null) ->hintColor('danger'), Forms\Components\TextInput::make('stop_hour') ->required() ->label( 'Stop Hour') // ->dehydrated(false) // Don't send to backend ->readOnly(true) ->numeric(), Forms\Components\TextInput::make('stop_min') ->required() ->label('Stop Minute') // ->dehydrated(false) ->readOnly(true) ->numeric(), Forms\Components\TextInput::make('id') ->hidden() ->readOnly(), Forms\Components\Hidden::make('operator_id') ->default(Filament::auth()->user()->name), ]) ->columns(2), ]); } public static function updateStopDuration(callable $get, callable $set) { $from = $get('from_datetime'); $to = $get('to_datetime'); // Carbon is a PHP date and time library. if ($from && $to) { $fromTime = Carbon::parse($from); //Carbon::parse($from) converts the from datetime string into a Carbon objec $toTime = Carbon::parse($to); if ($fromTime->lt($toTime)) { $diffInMinutes = $fromTime->diffInMinutes($toTime); // $set('stop_hour', floor($diffInMinutes / 60)); // $set('stop_min', $diffInMinutes % 60); if((floor($diffInMinutes / 60) === 0.0) && ($diffInMinutes % 60 === 0)) { $set('stop_hour', null); $set('stop_min', null); $set('plsToDateError', 'Time difference must be atlease a minute.'); } else { $set('stop_hour', floor($diffInMinutes / 60)); $set('stop_min', $diffInMinutes % 60); $set('plsToDateError', null); } } else { $set('stop_hour', null); $set('stop_min', null); $set('plsToDateError', 'To DateTime must be greater.'); } } } public static function table(Table $table): Table { return $table ->query(ProductionLineStop::query()) ->columns([ // Tables\Columns\TextColumn::make('id') // ->label('ID') // ->numeric() // ->sortable(), Tables\Columns\TextColumn::make('No.') ->label('No.') ->getStateUsing(function ($record, $livewire, $column, $rowLoop) { $paginator = $livewire->getTableRecords(); $perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10; $currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1; return ($currentPage - 1) * $perPage + $rowLoop->iteration; }), Tables\Columns\TextColumn::make('linestop.code') ->label('Line Stop Code') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('linestop.reason') ->label('Line Stop Reason') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('from_datetime') ->label('From DateTime') ->dateTime() ->alignCenter(), Tables\Columns\TextColumn::make('to_datetime') ->label('To DateTime') ->dateTime() ->alignCenter(), Tables\Columns\TextColumn::make('stop_hour') ->label('Stop Hour') ->alignCenter() ->numeric(), Tables\Columns\TextColumn::make('stop_min') ->label('Stop Minute') ->alignCenter() ->numeric(), Tables\Columns\TextColumn::make('line.name') ->label('Line') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('shift.block.name') ->label('Block') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('shift.name') ->label('Shift') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('plant.name') ->label('Plant') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('created_at') ->label('Created At') ->dateTime() ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('updated_at') ->label('Updated At') ->dateTime() ->alignCenter() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('deleted_at') ->label('Deleted At') ->dateTime() ->alignCenter() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('operator_id') ->label('Operator ID') ->alignCenter() ->sortable(), ]) ->filters([ Tables\Filters\TrashedFilter::make(), Filter::make('advanced_filters') ->label('Advanced Filters') ->form([ //plant Select::make('Plant') ->label('Select Plant') ->nullable() // ->options(function () { // return Plant::pluck('name', 'id'); // Assuming 'name' is the column you want to display // }) ->options(function (callable $get) { $userHas = Filament::auth()->user()->plant_id; return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray(); }) ->reactive() ->afterStateUpdated(function ($state, callable $set, callable $get) { $set('Line', null); $set('Block', null); $set('Shift', null); $set('line_stop_id', null); }), //line Select::make('Line') ->label('Select line') ->nullable() ->options(function (callable $get) { $plantId = $get('Plant'); if (!$plantId ) { return []; } return Line::where('plant_id', $plantId) ->pluck('name', 'id'); }) ->reactive(), //block Select::make('Block') ->label('Select Block') ->nullable() ->options(function (callable $get) { $plantId = $get('Plant'); if (!$plantId ) { return []; } return Block::where('plant_id', $get('Plant'))->pluck('name', 'id'); }) ->reactive() ->afterStateUpdated(function ($state, callable $set, callable $get) { $set('Shift', null); }), //shift Select::make('Shift') ->label('Select Shift') ->nullable() ->options(function (callable $get) { $plantId = $get('Plant'); $blockId = $get('Block'); if (!$plantId || !$blockId) { return []; // Return empty if plant or block is not selected } return Shift::where('plant_id', $plantId) ->where('block_id', $blockId) ->pluck('name', 'id'); }) ->reactive(), Select::make('line_stop_id') //linestop_id ->label('Search by Line Stop Code') ->nullable() // ->options(fn () => LineStop::orderBy('code')->whereHas('productionLineStops')->pluck('code', 'id')) ->options(function (callable $get) { $pId = $get('Plant'); return LineStop::orderBy('code')->whereHas('productionLineStops', function ($query) use ($pId) { if ($pId) { $query->where('plant_id', $pId); } })->pluck('code', 'id'); }) ->searchable() ->reactive(), DateTimePicker::make(name: 'created_from') ->label('Created From') ->placeholder(placeholder: 'Select From DateTime') ->reactive() ->native(false), DateTimePicker::make('created_to') ->label('Created To') ->placeholder(placeholder: 'Select To DateTime') ->reactive() ->native(false), ]) ->query(function ($query, array $data) { if (empty($data['Plant']) && empty($data['Shift']) && empty($data['Line']) && empty($data['created_from']) && empty($data['created_to']) && empty($data['line_stop_id'])) { return $query->whereRaw('1 = 0'); } if ($plant = $data['Plant'] ?? null) { $query->where('plant_id', $plant); } if ($shift = $data['Shift'] ?? null) { $query->where('shift_id', $shift); } if ($line = $data['Line'] ?? null) { $query->where('line_id', $line); } if ($code = $data['line_stop_id'] ?? null) { // Find the linestop_id by code entered // $lineStop = \App\Models\LineStop::where('code', 'like', "%{$code}%")->first(); // // If we find a matching LineStop, use its id to filter production_line_stops // if ($lineStop) { // $query->where('linestop_id', $lineStop->id); // } else { // // If no match found, you can either handle it as an error or return no results // $query->where('linestop_id', null); // This will return no results if no match // } $query->where('linestop_id', $code); } if ($from = $data['created_from'] ?? null) { $query->where('created_at', '>=', $from); } if ($to = $data['created_to'] ?? null) { $query->where('created_at', '<=', $to); } // return $query; }) ->indicateUsing(function (array $data) { $indicators = []; if (!empty($data['Plant'])) { $indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name'); } if (!empty($data['Shift'])) { $indicators[] = 'Shift: ' . Shift::where('id', $data['Shift'])->value('name'); } if (!empty($data['Line'])) { $indicators[] = 'Line: ' . Line::where('id', $data['Line'])->value('name'); } if (!empty($data['created_from'])) { $indicators[] = 'From: ' . $data['created_from']; } if (!empty($data['created_to'])) { $indicators[] = 'To: ' . $data['created_to']; } if (!empty($data['line_stop_id'])) { $lineStopCod = LineStop::find($data['line_stop_id'])->code ?? 'Unknown'; $indicators[] = 'Line Stop Code: ' . $lineStopCod; } return $indicators; }) ]) ->filtersFormMaxHeight('280px') ->actions([ Tables\Actions\ViewAction::make(), Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), Tables\Actions\ForceDeleteBulkAction::make(), Tables\Actions\RestoreBulkAction::make(), FilamentExportBulkAction::make('export') ]), ]) ->headerActions([ ImportAction::make() ->importer(ProductionLineStopImporter::class) ->visible(function() { return Filament::auth()->user()->can('view import production line stop'); }), ExportAction::make() ->exporter(ProductionLineStopExporter::class) ->visible(function() { return Filament::auth()->user()->can('view export production line stop'); }), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => Pages\ListProductionLineStops::route('/'), 'create' => Pages\CreateProductionLineStop::route('/create'), 'view' => Pages\ViewProductionLineStop::route('/{record}'), 'edit' => Pages\EditProductionLineStop::route('/{record}/edit'), ]; } public static function getEloquentQuery(): Builder { return parent::getEloquentQuery() ->withoutGlobalScopes([ SoftDeletingScope::class, ]); } }