mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Merge pull request #17772 from People-Sea/fix/issue/17751
fix: non native reactive `DateTimePicker` infinite update
This commit is contained in:
@@ -8,6 +8,8 @@ use Carbon\Exceptions\InvalidFormatException;
|
||||
use Closure;
|
||||
use DateTime;
|
||||
use Filament\Schemas\Components\Contracts\HasAffixActions;
|
||||
use Filament\Schemas\Components\StateCasts\Contracts\StateCast;
|
||||
use Filament\Schemas\Components\StateCasts\DateTimeStateCast;
|
||||
use Filament\Support\Concerns\HasExtraAlpineAttributes;
|
||||
use Filament\Support\Facades\FilamentTimezone;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
@@ -84,71 +86,44 @@ class DateTimePicker extends Field implements HasAffixActions
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->afterStateHydrated(static function (DateTimePicker $component, $state): void {
|
||||
if (blank($state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $state instanceof CarbonInterface) {
|
||||
try {
|
||||
$state = Carbon::createFromFormat($component->getFormat(), (string) $state, config('app.timezone'));
|
||||
} catch (InvalidFormatException $exception) {
|
||||
try {
|
||||
$state = Carbon::parse($state, config('app.timezone'));
|
||||
} catch (InvalidFormatException $exception) {
|
||||
$component->state(null);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$state = $state->setTimezone($component->getTimezone());
|
||||
|
||||
if (! $component->isNative()) {
|
||||
$component->state((string) $state);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $component->hasTime()) {
|
||||
$component->state($state->toDateString());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$precision = $component->hasSeconds() ? 'second' : 'minute';
|
||||
|
||||
if (! $component->hasDate()) {
|
||||
$component->state($state->toTimeString($precision));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$component->state($state->toDateTimeString($precision));
|
||||
});
|
||||
|
||||
$this->dehydrateStateUsing(static function (DateTimePicker $component, $state) {
|
||||
if (blank($state)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $state instanceof CarbonInterface) {
|
||||
$state = Carbon::parse($state);
|
||||
}
|
||||
|
||||
$state->shiftTimezone($component->getTimezone());
|
||||
$state->setTimezone(config('app.timezone'));
|
||||
|
||||
return $state->format($component->getFormat());
|
||||
});
|
||||
|
||||
$this->rule(
|
||||
'date',
|
||||
static fn (DateTimePicker $component): bool => $component->hasDate(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<StateCast>
|
||||
*/
|
||||
public function getDefaultStateCasts(): array
|
||||
{
|
||||
return [
|
||||
...parent::getDefaultStateCasts(),
|
||||
app(DateTimeStateCast::class, [
|
||||
'format' => $this->getFormat(),
|
||||
'internalFormat' => $this->getInternalFormat(),
|
||||
'timezone' => $this->getTimezone(),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
public function getInternalFormat(): string
|
||||
{
|
||||
if (! $this->isNative()) {
|
||||
return 'Y-m-d H:i:s';
|
||||
}
|
||||
|
||||
if (! $this->hasTime()) {
|
||||
return 'Y-m-d';
|
||||
}
|
||||
|
||||
if (! $this->hasDate()) {
|
||||
return $this->hasSeconds() ? 'H:i:s' : 'H:i';
|
||||
}
|
||||
|
||||
return 'Y-m-d H:i:s';
|
||||
}
|
||||
|
||||
public function displayFormat(string | Closure | null $format): static
|
||||
{
|
||||
$this->displayFormat = $format;
|
||||
|
||||
@@ -1367,21 +1367,6 @@ class Select extends Field implements Contracts\CanDisableOptions, Contracts\Has
|
||||
return (bool) $this->evaluate($this->canOptionLabelsWrap);
|
||||
}
|
||||
|
||||
public function hydrateDefaultState(?array &$hydratedDefaultState): void
|
||||
{
|
||||
parent::hydrateDefaultState($hydratedDefaultState);
|
||||
|
||||
if (is_bool($state = $this->getState())) {
|
||||
$state = $state ? 1 : 0;
|
||||
|
||||
$this->state($state);
|
||||
|
||||
if (is_array($hydratedDefaultState)) {
|
||||
Arr::set($hydratedDefaultState, $this->getStatePath(), $state); /** @phpstan-ignore parameterByRef.type */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getQualifiedRelatedKeyNameForRelationship(Relation $relationship): string
|
||||
{
|
||||
if ($relationship instanceof BelongsToMany) {
|
||||
|
||||
@@ -451,14 +451,14 @@ trait HasState
|
||||
}
|
||||
|
||||
if (! $this->hasDefaultState()) {
|
||||
$this->hasStatePath() && $this->state(null);
|
||||
$this->hasStatePath() && $this->rawState(null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$defaultState = $this->getDefaultState();
|
||||
|
||||
$this->state($defaultState);
|
||||
$this->rawState($defaultState);
|
||||
|
||||
Arr::set($hydratedDefaultState, $statePath, $defaultState); /** @phpstan-ignore parameterByRef.type */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Schemas\Components\StateCasts;
|
||||
|
||||
use Carbon\CarbonInterface;
|
||||
use Carbon\Exceptions\InvalidFormatException;
|
||||
use Filament\Schemas\Components\StateCasts\Contracts\StateCast;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class DateTimeStateCast implements StateCast
|
||||
{
|
||||
public function __construct(
|
||||
protected string $format,
|
||||
protected string $internalFormat,
|
||||
protected string $timezone,
|
||||
) {}
|
||||
|
||||
public function get(mixed $state): ?string
|
||||
{
|
||||
if (blank($state)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $state instanceof CarbonInterface) {
|
||||
$state = Carbon::parse($state);
|
||||
}
|
||||
|
||||
$state->shiftTimezone($this->timezone);
|
||||
$state->setTimezone(config('app.timezone'));
|
||||
|
||||
return $state->format($this->format);
|
||||
}
|
||||
|
||||
public function set(mixed $state): ?string
|
||||
{
|
||||
if (blank($state)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $state instanceof CarbonInterface) {
|
||||
try {
|
||||
$state = Carbon::createFromFormat($this->format, (string) $state, config('app.timezone'));
|
||||
} catch (InvalidFormatException) {
|
||||
try {
|
||||
$state = Carbon::parse($state, config('app.timezone'));
|
||||
} catch (InvalidFormatException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$state = $state->setTimezone($this->timezone);
|
||||
|
||||
return $state->format($this->internalFormat);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user