Last active
October 25, 2024 11:44
-
-
Save devhammed/17f28a651fd791b70f7311a00bea2661 to your computer and use it in GitHub Desktop.
Filament Money Input Component (this assumes that you are using the MoneyCast from https://github.com/akaunting/laravel-money package for the field in your model, this package is depended on by default in FilamentPHP so this should work out of the box))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Frontend\Forms\Components; | |
use Closure; | |
use Akaunting\Money\Money; | |
use Filament\Support\RawJs; | |
use Akaunting\Money\Currency; | |
use Filament\Forms\Components\TextInput; | |
class MoneyInput extends TextInput | |
{ | |
protected bool|Closure|null $masking = null; | |
protected bool|Closure|null $allowNegative = null; | |
protected string|Currency|Closure|null $currency = null; | |
protected function setUp(): void | |
{ | |
parent::setUp(); | |
$this | |
->inputMode('decimal') | |
->extraInputAttributes(['class' => '!text-xl']) | |
->prefix(fn(MoneyInput $component) => $component->getCurrency()->getPrefix(), isInline: true) | |
->suffix(fn(MoneyInput $component) => $component->getCurrency()->getSuffix(), isInline: true) | |
->stripCharacters(fn(MoneyInput $component) => $component->getCurrency()->getDecimalMark()) | |
->formatStateUsing(fn(MoneyInput $component, ?array $state): ?float => $state['value'] ?? null) | |
->dehydrateStateUsing(fn(MoneyInput $component, ?string $state): Money => money( | |
amount: floatval(str_replace($component->getCurrency()->getThousandsSeparator(), '', $state ?? '0')), | |
currency: $component->getCurrency()->getCurrency(), | |
convert: true, | |
)) | |
->extraAttributes(['class' => h('[&_.fi-input-wrp-label]:text-3xl [&_.fi-input-wrp-label]:text-primary-700 [&_.fi-input-wrp-label]:select-none dark:[&_.fi-input-wrp-label]:text-primary')]) | |
->rule(fn(MoneyInput $component) => function (string $attribute, ?string $value, Closure $fail) use ( | |
$component | |
) { | |
if ( ! $component->getAllowNegative() && floatval($value) < 0) { | |
$fail(t('Field must be a positive number.')); | |
} | |
}); | |
} | |
public function currency(string|Currency|Closure|null $currency = null): static | |
{ | |
$this->currency = $currency; | |
return $this; | |
} | |
public function masking(bool|Closure $masking = true): static | |
{ | |
$this->masking = $masking; | |
return $this; | |
} | |
public function allowNegative(bool|Closure $allowNegative = true): static | |
{ | |
$this->allowNegative = $allowNegative; | |
return $this; | |
} | |
public function getCurrency(): Currency | |
{ | |
$currency = $this->evaluate($this->currency); | |
if ($currency instanceof Currency) { | |
return $currency; | |
} | |
return currency($currency); | |
} | |
public function getMasking(): bool | |
{ | |
return $this->evaluate($this->masking ?? true); | |
} | |
public function getAllowNegative(): bool | |
{ | |
return $this->evaluate($this->allowNegative ?? false); | |
} | |
public function getMask(): string|RawJs|null | |
{ | |
if ( ! $this->getMasking()) { | |
return null; | |
} | |
return RawJs::make(sprintf( | |
"\$money(\$input, '%s', '%s', %d);", | |
$this->getCurrency()->getDecimalMark(), | |
$this->getCurrency()->getThousandsSeparator(), | |
$this->getCurrency()->getPrecision(), | |
)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment