diff --git a/README.md b/README.md index b79ed55..dcaee41 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,16 @@ app/ │ ├── Listeners/ │ ├── Models/ │ └── Providers/ + ├── Finance/ <-- Business Concept: Financial Operations + │ ├── Actions/ + │ ├── Casts/ + │ ├── DTOs/ + │ ├── Enums/ + │ ├── Models/ + │ ├── Policies/ + │ ├── Providers/ + │ ├── Schemas/ + │ └── Support/ └── System/ <-- Business Concept: Cross-cutting Infrastructure ├── Actions/ ├── Casts/ <-- Custom Eloquent casts @@ -487,7 +497,81 @@ All critical database mutations are tracked to maintain a compliant historical l --- -## 16. Dynamic UIs & Livewire Interoperability +## 16. Dynamic UIs & Schema Management + +To ensure consistent and type-safe form generation across the application, we use a schema-based approach. This separates the definition of UI fields from the rendering logic, primarily used for dynamic settings and complex forms. + +### 16.1 Core Schema Components + +The system relies on a combination of interfaces and classes to define UI components: + +* **`BaseSchema` (Interface)**: The contract for any schema-aware class. It requires a `make()` method and serves as the baseline for both individual field schemas and group schemas. +* **`SettingSchema` (Implementation)**: A versatile class used to define individual field attributes, validation rules, type-specific logic, and options (like dropdown values). +* **Domain Schemas (e.g., `InvoiceSchema`)**: Classes that implement `BaseSchema` to group multiple `SettingSchema` instances into a cohesive business unit (like a form). + +### 16.2 Defining a Schema + +Schemas are defined using a fluent API that allows for expressive configuration of UI fields. + +```php +use App\Domains\Finance\Support\Schema\InvoiceSchema; +use App\UI\Support\Schemas\SettingSchema; +use App\UI\Enums\InputType; + +// Define fields within an InvoiceSchema +$schema = InvoiceSchema::make() + ->addSchema( + key: 'invoice_number', + label: 'Invoice Number', + schema: SettingSchema::make(InputType::TEXT) + ->default('INV-' . date('Ymd')) + ->rules(['required', 'string', 'max:20']) + ) + ->addSchema( + key: 'category_id', + label: 'Category', + schema: SettingSchema::make(InputType::SELECT) + ->options(fn($context) => Category::pluck('name', 'id')) + ->live() // Triggers Livewire update on change + ); +``` + +### 16.3 SettingSchema Capabilities + +The `SettingSchema` provides several methods to tune field behavior: + +| Method | Purpose | +| --- | --- | +| `make(InputType $type)` | Static constructor accepting an `InputType` enum. | +| `default(mixed $value)` | Sets the initial/default value for the field. | +| `rules(array $rules)` | Defines Laravel validation rules. | +| `options(array|Closure $options)` | Provides data for select/radio/checkbox fields. Closures receive `$context`. | +| `attributes(array $attr)` | Passes raw HTML attributes to the Blade component. | +| `live()` | Marks the field as "live," useful for dynamic updates in Livewire. | +| `dependsOn(string $key)` | Establishes a dependency on another field for conditional logic. | +| `select2(array $config)` | Helper to quickly configure Select2 JS attributes. | + +### 16.4 Schema Resolution & UI Rendering + +Once a schema is defined, it is resolved into a standardized object structure that Blade components can iterate over. + +```php +// In a Livewire component or Controller +$fields = $schema->withContext(['user_id' => $id])->getSchema(); + +// In Blade +@foreach($fields as $key => $field) + +@endforeach +``` + +--- + +## 17. Dynamic UIs & Livewire Interoperability When building data-driven interfaces (like dynamic settings forms), we utilize the **Renderable Enum** pattern combined with Laravel's native dynamic components. diff --git a/app/Domains/Academic/Queries/Selection/SelectFacultyQuery.php b/app/Domains/Academic/Queries/Selection/SelectFacultyQuery.php index af43e26..74345d3 100644 --- a/app/Domains/Academic/Queries/Selection/SelectFacultyQuery.php +++ b/app/Domains/Academic/Queries/Selection/SelectFacultyQuery.php @@ -9,7 +9,7 @@ class SelectFacultyQuery { public static function fetch(): Collection { - return once(fn() => Faculty::all(['id', 'name']) + return once(fn () => Faculty::all(['id', 'name']) ->pluck('name', 'id')); } } diff --git a/app/Domains/Academic/Queries/Selection/SelectStudyProgramQuery.php b/app/Domains/Academic/Queries/Selection/SelectStudyProgramQuery.php index 7ad8986..6ccea9a 100644 --- a/app/Domains/Academic/Queries/Selection/SelectStudyProgramQuery.php +++ b/app/Domains/Academic/Queries/Selection/SelectStudyProgramQuery.php @@ -9,11 +9,11 @@ class SelectStudyProgramQuery { public static function fetch(array $context = []): Collection { - if(!isset($context['faculty'])) { - return new Collection(); + if (! isset($context['faculty'])) { + return new Collection; } - return once(fn() => StudyProgram::select('id', 'name') + return once(fn () => StudyProgram::select('id', 'name') ->where('faculty_id', $context['faculty']) ->get() ->pluck('name', 'id')); diff --git a/app/Domains/Academic/Queries/Selection/SelectTermQuery.php b/app/Domains/Academic/Queries/Selection/SelectTermQuery.php index 10b3a5a..c596a62 100644 --- a/app/Domains/Academic/Queries/Selection/SelectTermQuery.php +++ b/app/Domains/Academic/Queries/Selection/SelectTermQuery.php @@ -9,7 +9,7 @@ class SelectTermQuery { public static function fetch(): Collection { - return once(fn() => Term::all(['id', 'name']) + return once(fn () => Term::all(['id', 'name']) ->pluck('name', 'id')); } } diff --git a/app/Domains/Admission/Actions/IntakeScheduling/DefineAdmissionSchedule.php b/app/Domains/Admission/Actions/IntakeScheduling/DefineAdmissionSchedule.php index 75c2434..f1a5578 100644 --- a/app/Domains/Admission/Actions/IntakeScheduling/DefineAdmissionSchedule.php +++ b/app/Domains/Admission/Actions/IntakeScheduling/DefineAdmissionSchedule.php @@ -4,7 +4,6 @@ namespace App\Domains\Admission\Actions\IntakeScheduling; use App\Domains\Admission\DTOs\IntakeScheduling\DefineAdmissionScheduleDTO; use App\Domains\Admission\Enums\AdmissionStatus; -use App\Domains\Admission\Events\IntakeScheduling\AdmissionScheduleDefined; use App\Domains\Admission\Models\AdmissionSchedule; class DefineAdmissionSchedule diff --git a/app/Domains/Admission/DTOs/IntakeScheduling/DefineAdmissionScheduleDTO.php b/app/Domains/Admission/DTOs/IntakeScheduling/DefineAdmissionScheduleDTO.php index 04400d4..30d6450 100644 --- a/app/Domains/Admission/DTOs/IntakeScheduling/DefineAdmissionScheduleDTO.php +++ b/app/Domains/Admission/DTOs/IntakeScheduling/DefineAdmissionScheduleDTO.php @@ -3,7 +3,6 @@ namespace App\Domains\Admission\DTOs\IntakeScheduling; use Carbon\CarbonImmutable; -use Illuminate\Contracts\Support\Arrayable; readonly class DefineAdmissionScheduleDTO { diff --git a/app/Domains/Admission/Queries/Selection/SelectFeeTypeQuery.php b/app/Domains/Admission/Queries/Selection/SelectFeeTypeQuery.php index f1a6914..1fd37bc 100644 --- a/app/Domains/Admission/Queries/Selection/SelectFeeTypeQuery.php +++ b/app/Domains/Admission/Queries/Selection/SelectFeeTypeQuery.php @@ -8,6 +8,6 @@ class SelectFeeTypeQuery { public function fetch(): Collection { - return new Collection(); + return new Collection; } -} \ No newline at end of file +} diff --git a/app/Domains/Channel/Actions/Api/AssignEndpointUrl.php b/app/Domains/Channel/Actions/Api/AssignEndpointUrl.php index b278256..9978a98 100644 --- a/app/Domains/Channel/Actions/Api/AssignEndpointUrl.php +++ b/app/Domains/Channel/Actions/Api/AssignEndpointUrl.php @@ -9,20 +9,21 @@ use Exception; class AssignEndpointUrl { /** - * @param EndpointUrlDTO[] $endpointToSave + * @param EndpointUrlDTO[] $endpointToSave + * * @throws Exception */ public function execute(array $endpointToSave): void { - $validateArrayDTO = array_map(fn($endpoint) => $endpoint instanceof EndpointUrlDTO, $endpointToSave); + $validateArrayDTO = array_map(fn ($endpoint) => $endpoint instanceof EndpointUrlDTO, $endpointToSave); if (in_array(false, $validateArrayDTO)) { - throw new \Exception(sprintf('Invalid parameter. to use this action, the $endpointToSave must be an array of %s', EndpointUrlDTO::class)); + throw new Exception(sprintf('Invalid parameter. to use this action, the $endpointToSave must be an array of %s', EndpointUrlDTO::class)); } - $toSave = array_map(fn(EndpointUrlDTO $endpoint) => [ + $toSave = array_map(fn (EndpointUrlDTO $endpoint) => [ 'client_id' => $endpoint->clientId, 'key' => $endpoint->field, - 'value' => $endpoint->endpointUrl + 'value' => $endpoint->endpointUrl, ], $endpointToSave); ApiEndpoint::upsert($toSave, ['client_id', 'key']); } diff --git a/app/Domains/Channel/Actions/Api/SendWebhook.php b/app/Domains/Channel/Actions/Api/SendWebhook.php new file mode 100644 index 0000000..64e94a1 --- /dev/null +++ b/app/Domains/Channel/Actions/Api/SendWebhook.php @@ -0,0 +1,11 @@ +with('client') + ->where('key', $apiType) + ->first(); + + $domain = $endpoint->client->domain; + $url = $endpoint->value; + $credentials = $endpoint->client->credentials; + $authType = $endpoint->client->auth_type; + $url = "https://$domain$url"; + $header = $authType->buildCredentials($credentials); + + $response = Http::withHeaders($header)->get($url); + dd($response); + } +} diff --git a/app/Domains/Channel/Actions/AppProvisioning/ModifyConsumerAppDetail.php b/app/Domains/Channel/Actions/AppProvisioning/ModifyConsumerAppDetail.php index 3d6f506..50c1aa9 100644 --- a/app/Domains/Channel/Actions/AppProvisioning/ModifyConsumerAppDetail.php +++ b/app/Domains/Channel/Actions/AppProvisioning/ModifyConsumerAppDetail.php @@ -12,7 +12,7 @@ class ModifyConsumerAppDetail $client->update([ 'webhook' => $dto->webhook_url, 'auth_type' => $dto->auth_type, - 'credentials' => $dto->credentials, + 'credentials' => $dto->credentials->toArray(), ]); } } diff --git a/app/Domains/Channel/DTOs/Api/SyncDTO.php b/app/Domains/Channel/DTOs/Api/SyncDTO.php index bafcc3c..9267f40 100644 --- a/app/Domains/Channel/DTOs/Api/SyncDTO.php +++ b/app/Domains/Channel/DTOs/Api/SyncDTO.php @@ -7,4 +7,4 @@ readonly class SyncDTO public function __construct( // ) {} -} \ No newline at end of file +} diff --git a/app/Domains/Channel/DTOs/AppProvisioning/ModifyConsumerAppDetailDTO.php b/app/Domains/Channel/DTOs/AppProvisioning/ModifyConsumerAppDetailDTO.php index 9a88939..62a4ef1 100644 --- a/app/Domains/Channel/DTOs/AppProvisioning/ModifyConsumerAppDetailDTO.php +++ b/app/Domains/Channel/DTOs/AppProvisioning/ModifyConsumerAppDetailDTO.php @@ -2,6 +2,7 @@ namespace App\Domains\Channel\DTOs\AppProvisioning; +use App\Domains\Channel\DTOs\AppProvisioning\Type\AuthCredentials; use App\Domains\Channel\Enums\Client\AuthType; readonly class ModifyConsumerAppDetailDTO @@ -9,6 +10,6 @@ readonly class ModifyConsumerAppDetailDTO public function __construct( public string $webhook_url, public AuthType $auth_type, - public array $credentials, + public AuthCredentials $credentials, ) {} } diff --git a/app/Domains/Channel/DTOs/AppProvisioning/ProvisionConsumerAppDTO.php b/app/Domains/Channel/DTOs/AppProvisioning/ProvisionConsumerAppDTO.php index 2f0e382..eb81625 100644 --- a/app/Domains/Channel/DTOs/AppProvisioning/ProvisionConsumerAppDTO.php +++ b/app/Domains/Channel/DTOs/AppProvisioning/ProvisionConsumerAppDTO.php @@ -2,6 +2,7 @@ namespace App\Domains\Channel\DTOs\AppProvisioning; +use App\Domains\Channel\DTOs\AppProvisioning\Type\AuthCredentials; use App\Domains\Channel\Enums\Client\AuthType; readonly class ProvisionConsumerAppDTO @@ -14,6 +15,6 @@ readonly class ProvisionConsumerAppDTO public string $domain, public string $webhook_url, public AuthType $auth_type, - public array $credentials, + public AuthCredentials $credentials, ) {} } diff --git a/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthBasicDTO.php b/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthBasicDTO.php new file mode 100644 index 0000000..adc6f17 --- /dev/null +++ b/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthBasicDTO.php @@ -0,0 +1,27 @@ + $this->username, + 'password' => $this->password, + ]; + } +} diff --git a/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthBearerDTO.php b/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthBearerDTO.php new file mode 100644 index 0000000..1cd1d6c --- /dev/null +++ b/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthBearerDTO.php @@ -0,0 +1,24 @@ + $this->token, + ]; + } +} diff --git a/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthCredentials.php b/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthCredentials.php new file mode 100644 index 0000000..db398d3 --- /dev/null +++ b/app/Domains/Channel/DTOs/AppProvisioning/Type/AuthCredentials.php @@ -0,0 +1,10 @@ +default('-'); - } - - public function default(): mixed - { - return $this->schema()->default; - } - - public function inputAttributes(): array - { - return array_merge($this->schema()->attributes, [ - 'label' => $this->label(), - 'options' => $this->schema()->type->isSelect() ? $this->schema()->options : '', - ]); - } - - public static function section(): array - { - return [ - [ - __('domains/system/pages.api.sections.academic') => [ - self::FACULTY, - self::STUDY_PROGRAM, - self::TERM, - ], - ], - [ - __('domains/system/pages.api.sections.admission') => [ - self::ACADEMIC_PROGRAM, - self::ADMISSION_TRACK, - self::ADMISSION_SCHEDULE, - self::FEE_TYPE, - ], - ], - ]; - } } diff --git a/app/Domains/Channel/Enums/Client/AuthType.php b/app/Domains/Channel/Enums/Client/AuthType.php index ffb28a4..fdf1eae 100644 --- a/app/Domains/Channel/Enums/Client/AuthType.php +++ b/app/Domains/Channel/Enums/Client/AuthType.php @@ -2,6 +2,9 @@ namespace App\Domains\Channel\Enums\Client; +use App\Domains\Channel\DTOs\AppProvisioning\Type\AuthBasicDTO; +use App\Domains\Channel\DTOs\AppProvisioning\Type\AuthBearerDTO; +use App\Domains\Channel\DTOs\AppProvisioning\Type\AuthCredentials; use App\Domains\System\Traits\Enum\HasPredicateMethod; use App\UI\Enums\Concerns\InteractsWithLabels; use App\UI\Enums\Contracts\HasLabel; @@ -13,5 +16,27 @@ enum AuthType: string implements HasLabel case NONE = 'none'; case BASIC = 'basic'; - case TOKEN = 'token'; + case BEARER = 'token'; + + public function buildCredentials(array $credentials): array + { + return match ($this) { + self::NONE => [], + self::BASIC => [ + 'Authorization' => 'Basic ' . base64_encode($credentials['username'] . ':' . $credentials['password']), + ], + self::BEARER => [ + 'Authorization' => 'Bearer ' . $credentials['token'] ?? '', + ] + }; + } + + public function transformCredentials(array $credentials): ?AuthCredentials + { + return match ($this) { + self::NONE => null, + self::BASIC => AuthBasicDTO::fromArray($credentials), + self::BEARER => AuthBearerDTO::fromArray($credentials), + }; + } } diff --git a/app/Domains/Finance/Actions/ProductConfiguration/RegisterProductMapping.php b/app/Domains/Finance/Actions/ProductConfiguration/RegisterProductMapping.php index ad08969..2ea1a2d 100644 --- a/app/Domains/Finance/Actions/ProductConfiguration/RegisterProductMapping.php +++ b/app/Domains/Finance/Actions/ProductConfiguration/RegisterProductMapping.php @@ -12,7 +12,7 @@ class RegisterProductMapping ProductMapping::create([ 'name' => $dto->name, 'code' => $dto->code, - 'chart_of_account_id' => $dto->coaId + 'chart_of_account_id' => $dto->coaId, ]); } } diff --git a/app/Domains/Finance/DTOs/PaymentProcessing/IssueInvoiceDTO.php b/app/Domains/Finance/DTOs/PaymentProcessing/IssueInvoiceDTO.php index d0db157..3d86d9d 100644 --- a/app/Domains/Finance/DTOs/PaymentProcessing/IssueInvoiceDTO.php +++ b/app/Domains/Finance/DTOs/PaymentProcessing/IssueInvoiceDTO.php @@ -9,13 +9,13 @@ use App\Domains\Finance\Enums\InvoiceType; readonly class IssueInvoiceDTO { public function __construct( - public string $name, - public string $clientRefId, + public string $name, + public string $clientRefId, public InvoiceDetailDTO $detail, - public InvoiceType $type, - public InvoiceStatus $status, - public int $amount, - public string $coaId, - public string $clientId + public InvoiceType $type, + public InvoiceStatus $status, + public int $amount, + public string $coaId, + public string $clientId ) {} } diff --git a/app/Domains/Finance/DTOs/ProductConfiguration/ModifyProductMappingDTO.php b/app/Domains/Finance/DTOs/ProductConfiguration/ModifyProductMappingDTO.php index 407c7fe..4639eb4 100644 --- a/app/Domains/Finance/DTOs/ProductConfiguration/ModifyProductMappingDTO.php +++ b/app/Domains/Finance/DTOs/ProductConfiguration/ModifyProductMappingDTO.php @@ -7,4 +7,4 @@ readonly class ModifyProductMappingDTO public function __construct( // ) {} -} \ No newline at end of file +} diff --git a/app/Domains/Finance/Enums/InvoiceType.php b/app/Domains/Finance/Enums/InvoiceType.php index 6ee562c..839b3c5 100644 --- a/app/Domains/Finance/Enums/InvoiceType.php +++ b/app/Domains/Finance/Enums/InvoiceType.php @@ -5,11 +5,12 @@ namespace App\Domains\Finance\Enums; use App\Domains\Finance\DTOs\PaymentProcessing\Detail\InvoiceDetailDTO; use App\Domains\Finance\DTOs\PaymentProcessing\Detail\StudentInvoiceDetailDTO; use App\Domains\Finance\Schemas\Invoice\StudentInvoiceSchema; -use App\Domains\Finance\Support\Schema\InvoiceSchema; +use App\Domains\Finance\Support\Schemas\InvoiceSchema; use App\Domains\System\Traits\Enum\HasPredicateMethod; use App\UI\Enums\Concerns\InteractsWithLabels; use App\UI\Enums\Contracts\HasLabel; use App\UI\Enums\Contracts\HasSchema; +use App\UI\Support\Schemas\InputSchemaField; enum InvoiceType: string implements HasLabel, HasSchema { @@ -24,7 +25,7 @@ enum InvoiceType: string implements HasLabel, HasSchema { return match ($this) { self::STUDENT_INVOICE => StudentInvoiceSchema::make(), - default => InvoiceSchema::make(true), + default => InvoiceSchema::make()->withCoaVisibility(), }; } @@ -32,6 +33,17 @@ enum InvoiceType: string implements HasLabel, HasSchema { return match ($this) { self::STUDENT_INVOICE => StudentInvoiceDetailDTO::fromArray($data), + default => false }; } + + /** + * Resolve all field schemas, keyed by their input keys. + * + * @return array + */ + public function getSchema(): array + { + return $this->schema()->getSchema(); + } } diff --git a/app/Domains/Finance/Schemas/Invoice/StudentInvoiceSchema.php b/app/Domains/Finance/Schemas/Invoice/StudentInvoiceSchema.php index bb7e9e1..8a4a44c 100644 --- a/app/Domains/Finance/Schemas/Invoice/StudentInvoiceSchema.php +++ b/app/Domains/Finance/Schemas/Invoice/StudentInvoiceSchema.php @@ -5,60 +5,73 @@ namespace App\Domains\Finance\Schemas\Invoice; use App\Domains\Academic\Queries\Selection\SelectFacultyQuery; use App\Domains\Academic\Queries\Selection\SelectStudyProgramQuery; use App\Domains\Academic\Queries\Selection\SelectTermQuery; -use App\Domains\Finance\Support\Schema\InvoiceSchema; +use App\Domains\Finance\Support\Schemas\InvoiceSchema; use App\UI\Enums\InputType; -use App\UI\Support\Settings\SettingSchema; +use App\UI\Support\Schemas\InputSchema; class StudentInvoiceSchema { public static function make(): InvoiceSchema { return InvoiceSchema::make() - ->addSchema( - key: 'student_id', - label: __('domains/finance/field.invoice.detail.student_id'), - schema: SettingSchema::make(InputType::TEXTLINE) + ->addInput( + InputSchema::make() + ->key('student_id') + ->label(__('domains/finance/field.invoice.detail.student_id')) + ->type(InputType::TEXTLINE) ->rules(['required']) - )->addSchema( - key: 'student_name', - label: __('domains/finance/field.invoice.detail.student_name'), - schema: SettingSchema::make(InputType::TEXTLINE) + ) + ->addInput( + InputSchema::make() + ->key('student_name') + ->label(__('domains/finance/field.invoice.detail.student_name')) + ->type(InputType::TEXTLINE) ->rules(['required', 'string']) - )->addSchema( - key: 'faculty', - label: __('domains/finance/field.invoice.detail.faculty'), - schema: SettingSchema::make(InputType::SELECT) + ) + ->addInput( + InputSchema::make() + ->key('faculty') + ->label(__('domains/finance/field.invoice.detail.faculty')) + ->type(InputType::SELECT) ->rules(['required', 'string']) ->select2() ->live() - ->options(fn() => SelectFacultyQuery::fetch()) - )->addSchema( - key: 'study_program', - label: __('domains/finance/field.invoice.detail.study_program'), - schema: SettingSchema::make(InputType::SELECT) + ->options(fn () => SelectFacultyQuery::fetch()) + ) + ->addInput( + InputSchema::make() + ->key('study_program') + ->label(__('domains/finance/field.invoice.detail.study_program')) + ->type(InputType::SELECT) ->rules(['required', 'string']) ->select2() ->dependsOn('faculty') - ->setContextKey('faculty') + ->setContextKeys(['faculty']) ->options(fn ($context) => SelectStudyProgramQuery::fetch($context)) - )->addSchema( - key: 'term', - label: __('domains/finance/field.invoice.detail.term'), - schema: SettingSchema::make(InputType::SELECT) + ) + ->addInput( + InputSchema::make() + ->key('term_entry') + ->label(__('domains/finance/field.invoice.detail.term_entry')) + ->type(InputType::SELECT) ->rules(['required']) - ->options(fn() => SelectTermQuery::fetch()) + ->options(fn () => SelectTermQuery::fetch()) ->select2() - )->addSchema( - key: 'semester', - label: __('domains/finance/field.invoice.detail.semester'), - schema: SettingSchema::make(InputType::SELECT) + ) + ->addInput( + InputSchema::make() + ->key('semester') + ->label(__('domains/finance/field.invoice.detail.semester')) + ->type(InputType::SELECT) ->rules(['required']) - ->options(range(1, 13)) + ->options(array_combine(range(1, 13), range(1, 13))) ->select2() - )->addSchema( - key: 'fee_type', - label: __('domains/finance/field.invoice.detail.fee_type'), - schema: SettingSchema::make(InputType::SELECT) + ) + ->addInput( + InputSchema::make() + ->key('fee_type') + ->label(__('domains/finance/field.invoice.detail.fee_type')) + ->type(InputType::SELECT) ->rules(['required']) ->select2() ); diff --git a/app/Domains/Finance/Support/Schema/InvoiceSchema.php b/app/Domains/Finance/Support/Schema/InvoiceSchema.php deleted file mode 100644 index c12328c..0000000 --- a/app/Domains/Finance/Support/Schema/InvoiceSchema.php +++ /dev/null @@ -1,67 +0,0 @@ -attributes(['label' => $label]); - $uiSchema = array_merge($this->uiSchema, [[ - 'key' => $key, - 'schema' => $schema - ]]); - return new self($uiSchema, $this->coaVisibility); - } - - public function withContext(array $context): static - { - $this->context = $context; - return $this; - } - - public function withFormString(string $form): static - { - $this->form = $form; - return $this; - } - - public function getSchema(): array - { - $fields = []; - foreach($this->uiSchema as $field) { - /** @var SettingSchema $schema */ - $schema = $field['schema']; - $attributes['options'] =$schema->type->isSelect() ? $schema->resolveOptions($this->context) : ''; - - $fields[$field['key']] = (object) [ - 'attributes' => array_merge($schema->attributes, $attributes), - 'schema' => $schema, - ]; - } - - return $fields; - } - - public function isCoaVisible(): bool - { - return $this->coaVisibility; - } -} diff --git a/app/Domains/Finance/Support/Schemas/InvoiceSchema.php b/app/Domains/Finance/Support/Schemas/InvoiceSchema.php new file mode 100644 index 0000000..71a70d2 --- /dev/null +++ b/app/Domains/Finance/Support/Schemas/InvoiceSchema.php @@ -0,0 +1,25 @@ +coaVisibility = $visible; + + return $this; + } + + public function isCoaVisible(): bool + { + return $this->coaVisibility; + } +} diff --git a/app/Domains/Identity/Enums/UserSettingKey.php b/app/Domains/Identity/Enums/UserSettingKey.php index e8a7778..824be89 100644 --- a/app/Domains/Identity/Enums/UserSettingKey.php +++ b/app/Domains/Identity/Enums/UserSettingKey.php @@ -6,7 +6,8 @@ use App\UI\Enums\Concerns\InteractsWithLabels; use App\UI\Enums\Contracts\HasLabel; use App\UI\Enums\Contracts\HasSchema; use App\UI\Enums\InputType; -use App\UI\Support\Settings\SettingSchema; +use App\UI\Support\Schemas\InputSchema; +use App\UI\Support\Schemas\InputSchemaField; use Illuminate\Validation\Rule; enum UserSettingKey: string implements HasLabel, HasSchema @@ -17,7 +18,7 @@ enum UserSettingKey: string implements HasLabel, HasSchema case LANGUAGE = 'language'; case TIMEZONE = 'timezone'; - public function schema(): SettingSchema + public function schema(): InputSchema { $options = match ($this) { self::LANGUAGE => [ @@ -42,8 +43,22 @@ enum UserSettingKey: string implements HasLabel, HasSchema self::TIMEZONE => 'UTC', }; - return SettingSchema::make(InputType::SELECT, ['required', Rule::in(array_keys($options))]) + return InputSchema::make() + ->key($this->value) + ->label($this->label()) + ->type(InputType::SELECT) + ->rules(['required', Rule::in(array_keys($options))]) ->default($default) ->options($options); } + + public function getSchema(): InputSchemaField + { + return $this->schema()->getSchema(); + } + + public function default(): mixed + { + return $this->getSchema()->default; + } } diff --git a/app/Domains/System/Actions/Settings/UpdateSettings.php b/app/Domains/System/Actions/Settings/UpdateSettings.php index 4266340..46fc579 100644 --- a/app/Domains/System/Actions/Settings/UpdateSettings.php +++ b/app/Domains/System/Actions/Settings/UpdateSettings.php @@ -11,8 +11,9 @@ class UpdateSettings public function execute(SystemSetingDTO $dto): void { $value = $dto->value; + $schema = $dto->key->getSchema(); - if ($dto->key->schema()->type->isFile()) { + if ($schema->type->isFile()) { $currentSettings = SystemSettings::where('key', $dto->key->value)->value('value'); if ($currentSettings) { diff --git a/app/Domains/System/Enums/SystemSettingKey.php b/app/Domains/System/Enums/SystemSettingKey.php index 960c62c..bc1606e 100644 --- a/app/Domains/System/Enums/SystemSettingKey.php +++ b/app/Domains/System/Enums/SystemSettingKey.php @@ -8,7 +8,8 @@ use App\UI\Enums\Contracts\HasLabel; use App\UI\Enums\Contracts\HasSchema; use App\UI\Enums\FileType; use App\UI\Enums\InputType; -use App\UI\Support\Settings\SettingSchema; +use App\UI\Support\Schemas\InputSchema; +use App\UI\Support\Schemas\InputSchemaField; enum SystemSettingKey: string implements HasLabel, HasSchema { @@ -30,7 +31,7 @@ enum SystemSettingKey: string implements HasLabel, HasSchema /** * Centralized Schema Definitions */ - public function schema(): SettingSchema + public function schema(): InputSchema { $imageRules = ['required', 'file', 'mimetypes:'.implode(',', FileType::IMAGE->mimeType()), 'max:1024']; $imageAttrs = [ @@ -43,24 +44,50 @@ enum SystemSettingKey: string implements HasLabel, HasSchema ]; return match ($this) { - self::WEB_NAME => SettingSchema::make(InputType::TEXTLINE)->default('Acme Inc'), - self::WEB_DESCRIPTION => SettingSchema::make(InputType::TEXTAREA), - self::WEB_ADDRESS => SettingSchema::make(InputType::TEXTLINE)->default('123 Main St, Anytown, USA'), - self::WEB_PHONE => SettingSchema::make(InputType::TEXTLINE)->default('+1234567890'), - self::WEB_EMAIL => SettingSchema::make(InputType::TEXTLINE)->default('acme@web.io'), + self::WEB_NAME => InputSchema::make() + ->type(InputType::TEXTLINE) + ->label($this->label()) + ->default('Acme Inc'), + + self::WEB_DESCRIPTION => InputSchema::make() + ->label($this->label()) + ->type(InputType::TEXTAREA), + + self::WEB_ADDRESS => InputSchema::make() + ->type(InputType::TEXTLINE) + ->label($this->label()) + ->default('123 Main St, Anytown, USA'), + + self::WEB_PHONE => InputSchema::make() + ->type(InputType::TEXTLINE) + ->label($this->label()) + ->default('+1234567890'), + + self::WEB_EMAIL => InputSchema::make() + ->type(InputType::TEXTLINE) + ->label($this->label()) + ->default('acme@web.io'), self::WEB_LOGO, - self::WEB_FAVICON => SettingSchema::make(InputType::FILE, $imageRules)->attributes($imageAttrs), + self::WEB_FAVICON => InputSchema::make() + ->type(InputType::FILE) + ->label($this->label()) + ->rules($imageRules) + ->attributes($imageAttrs), - self::DEFAULT_LANGUAGE => SettingSchema::make(InputType::SELECT) + self::DEFAULT_LANGUAGE => InputSchema::make() + ->type(InputType::SELECT) ->default('en') + ->label($this->label()) ->options([ 'en' => __('domains/system/enum.system_setting_key_options.default_language.en'), 'id' => __('domains/system/enum.system_setting_key_options.default_language.id'), ]), - self::TIMEZONE => SettingSchema::make(InputType::SELECT) + self::TIMEZONE => InputSchema::make() + ->type(InputType::SELECT) ->default('UTC') + ->label($this->label()) ->options([ 'UTC' => __('domains/system/enum.system_setting_key_options.timezone.UTC'), 'Asia/Jakarta' => __('domains/system/enum.system_setting_key_options.timezone.Asia/Jakarta'), @@ -68,23 +95,13 @@ enum SystemSettingKey: string implements HasLabel, HasSchema 'Asia/Jayapura' => __('domains/system/enum.system_setting_key_options.timezone.Asia/Jayapura'), ]), - default => SettingSchema::make(InputType::TEXTLINE)->rules(['nullable', 'string']), + default => InputSchema::make() + ->label($this->label()) + ->type(InputType::TEXTLINE) + ->rules(['nullable', 'string']), }; } - public function default(): mixed - { - return $this->schema()->default; - } - - public function inputAttributes(): array - { - return array_merge($this->schema()->attributes, [ - 'label' => $this->label(), - 'options' => $this->schema()->type->isSelect() ? $this->schema()->options : '', - ]); - } - public static function section(): array { return [ @@ -100,4 +117,14 @@ enum SystemSettingKey: string implements HasLabel, HasSchema ], ]; } + + public function getSchema(): InputSchemaField + { + return $this->schema()->getSchema(); + } + + public function getValidation(): array + { + return $this->schema()->getSchema()->rules; + } } diff --git a/app/Domains/System/Models/SystemSettings.php b/app/Domains/System/Models/SystemSettings.php index be9f5c3..5e8ce64 100644 --- a/app/Domains/System/Models/SystemSettings.php +++ b/app/Domains/System/Models/SystemSettings.php @@ -2,6 +2,7 @@ namespace App\Domains\System\Models; +use App\Domains\System\Enums\SystemSettingKey; use Exception; use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Attributes\WithoutTimestamps; @@ -18,13 +19,13 @@ class SystemSettings extends Model */ public function getTranslatedValueAttribute(): ?string { - $key = $this->attributes['type']::tryFrom($this->attributes['key']); + $key = SystemSettingKey::tryFrom($this->attributes['key']); - $schema = $key->schema(); + $schema = $key->getSchema(); if ($schema->type->isFile() && isset($this->attributes['value'])) { return asset_static($this->attributes['value']); } elseif ($schema->type->isSelect()) { - return $schema->options[$this->attributes['value']]; + return $schema->attributes['options'][$this->attributes['value']]; } return $this->attributes['value']; diff --git a/app/Domains/System/Queries/GetSystemSettings.php b/app/Domains/System/Queries/GetSystemSettings.php index a26216e..bff72a3 100644 --- a/app/Domains/System/Queries/GetSystemSettings.php +++ b/app/Domains/System/Queries/GetSystemSettings.php @@ -12,7 +12,7 @@ class GetSystemSettings public function get(SystemSettingKey $setting): ?string { - return $this->fetch()[$setting->value] ?? $setting->default(); + return $this->fetch()[$setting->value] ?? $setting->getSchema()->default; } public function fetch(): array @@ -22,10 +22,10 @@ class GetSystemSettings } $this->settings = Cache::rememberForever(SystemSettings::$cacheName, function () { - $settings = SystemSettings::where('type', SystemSettingKey::class)->pluck('value', 'key')->toArray(); + $settings = SystemSettings::pluck('value', 'key')->toArray(); $finalSettings = []; foreach (SystemSettingKey::cases() as $key) { - $finalSettings[$key->value] = $settings[$key->value] ?? $key->default(); + $finalSettings[$key->value] = $settings[$key->value] ?? $key->getSchema()->default; } return $finalSettings; diff --git a/app/Http/DataTables/Academic/FacultyDataTable.php b/app/Http/DataTables/Academic/FacultyDataTable.php index e352f0c..3167598 100644 --- a/app/Http/DataTables/Academic/FacultyDataTable.php +++ b/app/Http/DataTables/Academic/FacultyDataTable.php @@ -91,7 +91,8 @@ class FacultyDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#faculty-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#faculty-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Academic/StudyProgramDataTable.php b/app/Http/DataTables/Academic/StudyProgramDataTable.php index 9e0fc86..c30b0dd 100644 --- a/app/Http/DataTables/Academic/StudyProgramDataTable.php +++ b/app/Http/DataTables/Academic/StudyProgramDataTable.php @@ -97,7 +97,8 @@ class StudyProgramDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#studyprogram-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#studyprogram-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Academic/TermDataTable.php b/app/Http/DataTables/Academic/TermDataTable.php index e44c02d..48bf008 100644 --- a/app/Http/DataTables/Academic/TermDataTable.php +++ b/app/Http/DataTables/Academic/TermDataTable.php @@ -91,7 +91,8 @@ class TermDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#term-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#term-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Admission/AcademicProgramDataTable.php b/app/Http/DataTables/Admission/AcademicProgramDataTable.php index 9d74296..ed15ccf 100644 --- a/app/Http/DataTables/Admission/AcademicProgramDataTable.php +++ b/app/Http/DataTables/Admission/AcademicProgramDataTable.php @@ -95,7 +95,8 @@ class AcademicProgramDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#academicprogram-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#academicprogram-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php b/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php index c7cd4d7..cf1003e 100644 --- a/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php +++ b/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php @@ -98,7 +98,8 @@ class AdmissionScheduleDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#admissionschedule-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#admissionschedule-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Admission/AdmissionTrackDataTable.php b/app/Http/DataTables/Admission/AdmissionTrackDataTable.php index 083e62e..cc73b96 100644 --- a/app/Http/DataTables/Admission/AdmissionTrackDataTable.php +++ b/app/Http/DataTables/Admission/AdmissionTrackDataTable.php @@ -95,7 +95,8 @@ class AdmissionTrackDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#admissiontrack-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#admissiontrack-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Admission/FeeTypeDataTable.php b/app/Http/DataTables/Admission/FeeTypeDataTable.php index 708e4b7..0a1df5c 100644 --- a/app/Http/DataTables/Admission/FeeTypeDataTable.php +++ b/app/Http/DataTables/Admission/FeeTypeDataTable.php @@ -88,7 +88,8 @@ class FeeTypeDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#feetype-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#feetype-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Channel/ClientDataTable.php b/app/Http/DataTables/Channel/ClientDataTable.php index 2feb591..cff95a6 100644 --- a/app/Http/DataTables/Channel/ClientDataTable.php +++ b/app/Http/DataTables/Channel/ClientDataTable.php @@ -92,12 +92,14 @@ class ClientDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#client-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#client-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make() ->text(svg('tabler-api', ['width' => 16, 'height' => 16])->toHtml()) - ->action('$("#api-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#api-form-modal']) ->addClass('btn-sm btn-info'), Button::make('reload') ->text(svg('tabler-reload', ['width' => 16, 'height' => 16])->toHtml()) diff --git a/app/Http/DataTables/Finance/ChartOfAccountDataTable.php b/app/Http/DataTables/Finance/ChartOfAccountDataTable.php index 9898a24..a457234 100644 --- a/app/Http/DataTables/Finance/ChartOfAccountDataTable.php +++ b/app/Http/DataTables/Finance/ChartOfAccountDataTable.php @@ -96,7 +96,8 @@ class ChartOfAccountDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#chartofaccount-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#chartofaccount-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Finance/InvoiceDataTable.php b/app/Http/DataTables/Finance/InvoiceDataTable.php index a4fa821..177a0f2 100644 --- a/app/Http/DataTables/Finance/InvoiceDataTable.php +++ b/app/Http/DataTables/Finance/InvoiceDataTable.php @@ -72,7 +72,8 @@ class InvoiceDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#invoice-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#invoice-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Finance/ProductMappingDataTable.php b/app/Http/DataTables/Finance/ProductMappingDataTable.php index 035d0d0..7ce0928 100644 --- a/app/Http/DataTables/Finance/ProductMappingDataTable.php +++ b/app/Http/DataTables/Finance/ProductMappingDataTable.php @@ -91,7 +91,8 @@ class ProductMappingDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#product-mapping-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#product-mapping-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Identity/RoleDataTable.php b/app/Http/DataTables/Identity/RoleDataTable.php index e9c4d97..2847a40 100644 --- a/app/Http/DataTables/Identity/RoleDataTable.php +++ b/app/Http/DataTables/Identity/RoleDataTable.php @@ -92,7 +92,8 @@ class RoleDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#role-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#role-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('reload') diff --git a/app/Http/DataTables/Identity/UserDataTable.php b/app/Http/DataTables/Identity/UserDataTable.php index 0991fde..2d5b80b 100644 --- a/app/Http/DataTables/Identity/UserDataTable.php +++ b/app/Http/DataTables/Identity/UserDataTable.php @@ -146,7 +146,8 @@ class UserDataTable extends DataTable ]) ->buttons([ Button::make('add') - ->action('$("#user-form-modal").modal("show");') + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#user-form-modal']) ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), Button::make('excel') @@ -157,7 +158,8 @@ class UserDataTable extends DataTable ->text(svg('tabler-table-import', ['width' => 16, 'height' => 16])->toHtml()) ->titleAttr(__('ui/title.import', ['resource' => 'Excel'])) ->addClass('btn-sm') - ->action("$('#excel-import-modal').modal('show')"), + ->action('javascript:void(0)') + ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#excel-import-modal']), Button::make('reload') ->text(svg('tabler-reload', ['width' => 16, 'height' => 16])->toHtml()) ->addClass('btn-sm'), diff --git a/app/Livewire/Forms/Channel/ClientForm.php b/app/Livewire/Forms/Channel/ClientForm.php index e8adde5..a1cc7f0 100644 --- a/app/Livewire/Forms/Channel/ClientForm.php +++ b/app/Livewire/Forms/Channel/ClientForm.php @@ -15,7 +15,7 @@ class ClientForm extends Form public string $domain = ''; #[Validate('required', as: 'domains/channel/field.client.auth_type')] - public AuthType $auth_type = AuthType::NONE; + public ?AuthType $auth_type = null; #[Validate(as: [ 'credentials' => 'domains/channel/field.client.credentials', @@ -28,14 +28,14 @@ class ClientForm extends Form #[Validate('required|max:255', as: 'domains/channel/field.client.webhook')] public string $webhook = ''; - public function updatingAuthType(): void + public function updatedAuthType(): void { $this->reset('credentials'); } public function rules(): array { - if ($this->auth_type === AuthType::TOKEN) { + if ($this->auth_type === AuthType::BEARER) { return [ 'credentials.token' => 'required', ]; diff --git a/app/Livewire/Forms/Finance/InvoiceForm.php b/app/Livewire/Forms/Finance/InvoiceForm.php index b939547..532689d 100644 --- a/app/Livewire/Forms/Finance/InvoiceForm.php +++ b/app/Livewire/Forms/Finance/InvoiceForm.php @@ -5,7 +5,7 @@ namespace App\Livewire\Forms\Finance; use App\Domains\Finance\DTOs\PaymentProcessing\IssueInvoiceDTO; use App\Domains\Finance\Enums\InvoiceStatus; use App\Domains\Finance\Enums\InvoiceType; -use App\UI\Support\Settings\SettingSchema; +use App\UI\Support\Schemas\InputSchemaField; use Livewire\Attributes\Validate; use Livewire\Form; @@ -35,9 +35,9 @@ class InvoiceForm extends Form $this->resetValidation(); foreach ($formSchema as $key => $schema) { - /** @var SettingSchema $schema */ - $schema = $schema->schema; - if ($schema->depends == $prop) { + /** @var InputSchemaField $schema */ + $schema = $schema->schema->getSchema(); + if ($schema->dependsOn == $prop) { $this->detail[$key] = ''; } } @@ -48,9 +48,9 @@ class InvoiceForm extends Form { $this->reset('detail'); - $schema = $this->type?->schema()?->getSchema() ?? []; - foreach ($schema as $key => $value) { - $this->detail[$key] = ''; + $schema = $this->type?->getSchema() ?? []; + foreach ($schema as $value) { + $this->detail[$value->key] = ''; } $this->resetValidation(); @@ -58,44 +58,25 @@ class InvoiceForm extends Form public function rules(): array { - $rules = []; - $detailSchema = $this->type - ?->schema() - ->getSchema() ?? []; - foreach ($detailSchema as $key => $schema) { - $rules = array_merge($rules, [ - 'detail.'.$key => $schema->schema->rules, - ]); - } - - return $rules; + return $this->type?->schema()?->getValidationRules('detail'); } public function validationAttributes(): array { - $attributes = []; - $detailSchema = $this->type - ?->schema() - ->getSchema() ?? []; - foreach ($detailSchema as $key => $schema) { - $attributes = array_merge($attributes, [ - 'detail.'.$key => $schema->schema->attributes['label'], - ]); - } - - return $attributes; + return $this->type?->schema()?->getValidationAttributes('detail'); } public function toDto(): IssueInvoiceDTO { - return new IssueInvoiceDTO( name: $this->name, clientRefId: $this->client_id, detail: $this->type->dtoTransform($this->detail), type: $this->type, status: InvoiceStatus::PENDING, - clientId: $this->client_id + amount: $this->amount, + coaId: $this->coa_id, + clientId: $this->client_id, ); } } diff --git a/app/Livewire/Forms/Finance/PaymentForm.php b/app/Livewire/Forms/Finance/PaymentForm.php index 2d0461f..b8e4fec 100644 --- a/app/Livewire/Forms/Finance/PaymentForm.php +++ b/app/Livewire/Forms/Finance/PaymentForm.php @@ -2,7 +2,6 @@ namespace App\Livewire\Forms\Finance; -use Livewire\Attributes\Validate; use Livewire\Form; class PaymentForm extends Form diff --git a/app/Livewire/Forms/Finance/ProductMappingForm.php b/app/Livewire/Forms/Finance/ProductMappingForm.php index 7d165b4..d083b06 100644 --- a/app/Livewire/Forms/Finance/ProductMappingForm.php +++ b/app/Livewire/Forms/Finance/ProductMappingForm.php @@ -16,6 +16,6 @@ class ProductMappingForm extends Form #[Validate('required|string', as: 'domains/finance/field.product-mapping.chart_of_account')] public string $coa_id = ''; -// #[Validate('required|string', as: 'domains/finance/field.product-mapping.client')] -// public string $client = ''; + // #[Validate('required|string', as: 'domains/finance/field.product-mapping.client')] + // public string $client = ''; } diff --git a/app/UI/Enums/Contracts/HasSchema.php b/app/UI/Enums/Contracts/HasSchema.php index fd22d37..6ecdfb0 100644 --- a/app/UI/Enums/Contracts/HasSchema.php +++ b/app/UI/Enums/Contracts/HasSchema.php @@ -2,9 +2,12 @@ namespace App\UI\Enums\Contracts; -use App\UI\Support\Settings\BaseSchema; +use App\UI\Support\Schemas\BaseSchema; +use App\UI\Support\Schemas\InputSchemaField; interface HasSchema { public function schema(): BaseSchema; + + public function getSchema(): array|InputSchemaField; } diff --git a/app/UI/Support/Schemas/AbstractGroupSchema.php b/app/UI/Support/Schemas/AbstractGroupSchema.php new file mode 100644 index 0000000..5eb7eb4 --- /dev/null +++ b/app/UI/Support/Schemas/AbstractGroupSchema.php @@ -0,0 +1,82 @@ + + */ + protected array $fields = []; + + /** + * Add one or multiple fields to the container. + */ + public function addInput(InputSchema $input): static + { + $inputSchema = $input->getSchema(); + $this->fields[$inputSchema->key] = $input; + + return $this; + } + + /** + * Pass dynamic context down to all child fields. + */ + public function withContext(array $context): static + { + parent::withContext($context); + + foreach ($this->fields as $field) { + $field->withContext($this->context); + } + + return $this; + } + + /** + * Resolve all field schemas, keyed by their input keys. + * + * @return array + */ + public function getSchema(): array + { + return array_map(function ($schema) { + return $schema->getSchema(); + }, $this->fields); + } + + /** + * Extract validation rules for FormRequest or Livewire. + * + * @return array + */ + public function getValidationRules(string $prefix = ''): array + { + $rules = []; + + foreach ($this->getSchema() as $key => $schema) { + $fieldKey = $prefix ? "{$prefix}.{$key}" : $key; + $rules[$fieldKey] = $schema->rules; + } + + return $rules; + } + + /** + * Extract validation rules for FormRequest or Livewire. + * + * @return array + */ + public function getValidationAttributes(string $prefix = ''): array + { + $rules = []; + + foreach ($this->getSchema() as $key => $schema) { + $fieldKey = $prefix ? "{$prefix}.{$key}" : $key; + $rules[$fieldKey] = $schema->label; + } + + return $rules; + } +} diff --git a/app/UI/Support/Schemas/AbstractSchema.php b/app/UI/Support/Schemas/AbstractSchema.php new file mode 100644 index 0000000..1d0ee8d --- /dev/null +++ b/app/UI/Support/Schemas/AbstractSchema.php @@ -0,0 +1,25 @@ +context = array_merge($this->context, $context); + + return $this; + } + + abstract public function getSchema(): array|InputSchemaField; +} diff --git a/app/UI/Support/Schemas/BaseSchema.php b/app/UI/Support/Schemas/BaseSchema.php new file mode 100644 index 0000000..9c058e8 --- /dev/null +++ b/app/UI/Support/Schemas/BaseSchema.php @@ -0,0 +1,22 @@ + for group containers. + */ + public function getSchema(): array|InputSchemaField; +} diff --git a/app/UI/Support/Schemas/InputSchema.php b/app/UI/Support/Schemas/InputSchema.php new file mode 100644 index 0000000..24a1be1 --- /dev/null +++ b/app/UI/Support/Schemas/InputSchema.php @@ -0,0 +1,160 @@ +key = $key; + + return $this; + } + + /** + * Set the display label. + */ + public function label(string $label): static + { + $this->label = $label; + + return $this; + } + + public function type(InputType $type): static + { + $this->type = $type; + + return $this; + } + + public function default(mixed $default): static + { + $this->default = $default; + + return $this; + } + + public function rules(array|string $rules): static + { + $this->rules = is_array($rules) ? $rules : explode('|', $rules); + + return $this; + } + + public function options(array|Closure $options): static + { + $this->options = $options; + + return $this; + } + + public function attributes(array $attributes): static + { + $this->attributes = array_merge($this->attributes, $attributes); + + return $this; + } + + public function setContextKeys(array|string $keys): static + { + $this->contextKeys = (array) $keys; + + return $this; + } + + public function select2(array $config = []): static + { + return $this->attributes(['x-select2' => json_encode($config)]); + } + + public function live(): static + { + $this->live = true; + + return $this; + } + + public function dependsOn(string $depends): static + { + $this->depends = $depends; + + return $this; + } + + public function isLive(): bool + { + return $this->live; + } + + public function resolveOptions(array $extraContext = []): array|Collection + { + if (! $this->options instanceof Closure) { + return $this->options; + } + + $mergedContext = array_merge($this->context, $extraContext); + + if (! empty($this->contextKeys)) { + $mergedContext = array_intersect_key( + $mergedContext, + array_flip($this->contextKeys) + ); + } + + return ($this->options)($mergedContext); + } + + private function getAttributes(): array + { + $attributes = array_merge(['label' => $this->label], $this->attributes); + + if ($this->type->isSelect()) { + $attributes['options'] = $this->resolveOptions(); + } + + return $attributes; + } + + public function getSchema(): InputSchemaField + { + return new InputSchemaField( + key: $this->key, + label: $this->label, + type: $this->type, + attributes: $this->getAttributes(), + rules: $this->rules, + default: $this->default, + isLive: $this->isLive(), + dependsOn: $this->depends, + schema: $this, + ); + } +} diff --git a/app/UI/Support/Schemas/InputSchemaField.php b/app/UI/Support/Schemas/InputSchemaField.php new file mode 100644 index 0000000..b903a8a --- /dev/null +++ b/app/UI/Support/Schemas/InputSchemaField.php @@ -0,0 +1,20 @@ +default = $default; - - return $this; - } - - public function rules(array $rules): static - { - $this->rules = $rules; - - return $this; - } - - public function options(array|Closure $options): static - { - $this->options = $options; - - return $this; - } - - public function attributes(array $attributes): static - { - $this->attributes = array_merge($this->attributes, $attributes); - - return $this; - } - - public function setContextKey(array|string $contextKey): static - { - $this->contextKey = array_merge($this->contextKey, (array) $contextKey); - return $this; - } - - public function withContext(array $context): static - { - $this->context = array_merge($this->context, $context); - - return $this; - } - - public function select2(array $config = []): static - { - $this->attributes(['x-select2' => json_encode($config)]); - return $this; - } - - public function live(): static - { - $this->live = true; - return $this; - } - - public function dependsOn(string $depends): static - { - $this->depends = $depends; - return $this; - } - - public function isLive(): bool - { - return $this->live; - } - - public function resolveOptions(array $extraContext = []): array|Collection - { - if ($this->options instanceof Closure) { - $mergedContext = array_merge($this->context, $extraContext); - - if(!empty($this->contextKey)) { - $temporaryContext = []; - foreach($this->contextKey as $key) { - $temporaryContext[$key] = !empty($mergedContext[$key]) ? $mergedContext[$key] : null; - } - $mergedContext = $temporaryContext; - } - - return ($this->options)($mergedContext); - } - - return $this->options; - } - - public function getAttributes(array $extraContext = []): array - { - $attributes = $this->attributes; - - if ($this->type->isSelect()) { - $attributes['options'] = $this->resolveOptions($extraContext); - } - - return $attributes; - } -} diff --git a/database/migrations/2026_05_01_172941_create_system_settings_table.php b/database/migrations/2026_05_01_172941_create_system_settings_table.php index dec9650..872d870 100644 --- a/database/migrations/2026_05_01_172941_create_system_settings_table.php +++ b/database/migrations/2026_05_01_172941_create_system_settings_table.php @@ -15,7 +15,6 @@ return new class extends Migration $table->id(); $table->string('key')->unique(); $table->text('value')->nullable(); - $table->text('type'); }); } diff --git a/database/seeders/SystemSettingSeeder.php b/database/seeders/SystemSettingSeeder.php index cab1793..f50e4e7 100644 --- a/database/seeders/SystemSettingSeeder.php +++ b/database/seeders/SystemSettingSeeder.php @@ -2,7 +2,6 @@ namespace Database\Seeders; -use App\Domains\Channel\Enums\Api\ApiType; use App\Domains\System\Enums\SystemSettingKey; use App\Domains\System\Models\SystemSettings; use Illuminate\Database\Seeder; @@ -18,16 +17,7 @@ class SystemSettingSeeder extends Seeder foreach ($settings as $setting) { SystemSettings::create([ 'key' => $setting->value, - 'value' => $setting->default(), - 'type' => SystemSettingKey::class, - ]); - } - - foreach (ApiType::cases() as $sync) { - SystemSettings::create([ - 'key' => $sync->value, - 'value' => '-', - 'type' => ApiType::class, + 'value' => $setting->schema()->getSchema()->default, ]); } } diff --git a/lang/en/domains/channel/enum.php b/lang/en/domains/channel/enum.php index e629305..df697bf 100644 --- a/lang/en/domains/channel/enum.php +++ b/lang/en/domains/channel/enum.php @@ -16,6 +16,6 @@ return [ 'auth_type' => [ AuthType::NONE->value => 'None', AuthType::BASIC->value => 'Basic', - AuthType::TOKEN->value => 'Token', + AuthType::BEARER->value => 'Bearer', ], ]; diff --git a/lang/en/domains/finance/field.php b/lang/en/domains/finance/field.php index d4e8160..7302b3a 100644 --- a/lang/en/domains/finance/field.php +++ b/lang/en/domains/finance/field.php @@ -6,7 +6,7 @@ return [ 'name' => 'Account Name', 'classification' => 'Classification', 'status' => 'Status', - 'parent' => 'Derived From' + 'parent' => 'Derived From', ], 'invoice' => [ 'name' => 'Invoice Name', @@ -22,14 +22,14 @@ return [ 'student_id' => 'Student ID', 'faculty' => 'Faculty', 'study_program' => 'Study Program', - 'term' => 'Study Term', + 'term_entry' => 'Term Entry', 'fee_type' => 'Fee Type', 'semester' => 'Semester', // Vendor Bill 'vendor_name' => 'Vendor Name', 'vendor_id' => 'Vendor ID', - ] + ], ], 'payment' => [ 'virtual_account' => 'Virtual Account', diff --git a/lang/en/ui/button.php b/lang/en/ui/button.php index f2d3ff7..dac07b1 100644 --- a/lang/en/ui/button.php +++ b/lang/en/ui/button.php @@ -7,6 +7,7 @@ return [ 'close' => 'Close', 'create' => 'Create', 'update' => 'Update', + 'update-mode' => 'Enter Update Mode', 'upload' => 'Upload', 'edit' => 'Edit', 'delete' => 'Delete', diff --git a/lang/id/domains/channel/enum.php b/lang/id/domains/channel/enum.php index b30b022..e36da81 100644 --- a/lang/id/domains/channel/enum.php +++ b/lang/id/domains/channel/enum.php @@ -16,6 +16,6 @@ return [ 'auth_type' => [ AuthType::NONE->value => 'Tidak Ada', AuthType::BASIC->value => 'Dasar', - AuthType::TOKEN->value => 'Token', + AuthType::BEARER->value => 'Bearer', ], ]; diff --git a/lang/id/domains/finance/field.php b/lang/id/domains/finance/field.php index b6e6e88..5e6a98d 100644 --- a/lang/id/domains/finance/field.php +++ b/lang/id/domains/finance/field.php @@ -6,7 +6,7 @@ return [ 'name' => 'Nama Akun', 'classification' => 'Klasifikasi', 'status' => 'Status', - 'parent' => 'Turunan Dari' + 'parent' => 'Turunan Dari', ], 'invoice' => [ 'name' => 'Nama Pembayar', @@ -14,6 +14,21 @@ return [ 'amount' => 'Jumlah Tagihan', 'client_name' => 'Nama Klien', 'status' => 'Status', + 'coa_name' => 'Nama Akun (COA)', + 'detail' => [ + // Detail for Student + 'student_name' => 'Nama Mahasiswa', + 'student_id' => 'Nomor Induk Mahasiswa', + 'faculty' => 'Fakultas', + 'study_program' => 'Program Studi', + 'term_entry' => 'Periode Masuk', + 'fee_type' => 'Jenis Biaya', + 'semester' => 'Semester', + + // Vendor Bill + 'vendor_name' => 'Nama Vendor', + 'vendor_id' => 'Nomor Pengenal Vendor', + ], ], 'product_mapping' => [ 'code' => 'Kode Produk', diff --git a/resources/js/alpine/bs.js b/resources/js/alpine/bs.js index 83eaa91..cf9287a 100644 --- a/resources/js/alpine/bs.js +++ b/resources/js/alpine/bs.js @@ -8,7 +8,7 @@ export default function bs(Alpine) { } let wrapHandler = (callback, wrapper) => (e) => wrapper(callback, e) - const eventName = `${modifiers}.bs.${value}` + const eventName = `${modifiers}.coreui.${value}` handler = wrapHandler(handler, (next, e) => { next(e); @@ -25,13 +25,13 @@ export default function bs(Alpine) { get(target, type) { return { on(event, callback) { - el.addEventListener(`${event}.bs.${type}`, (e) => { + el.addEventListener(`${event}.coreui.${type}`, (e) => { callback(e); }); }, instance(element = undefined) { const className = type.charAt(0).toUpperCase() + type.slice(1); - return bootstrap[className].getInstance(element ?? el); + return coreui[className].getInstance(element ?? el); }, updateHTML(attr, html) { el.querySelector(attr).innerHTML = html @@ -40,4 +40,4 @@ export default function bs(Alpine) { } }); }); -} \ No newline at end of file +} diff --git a/resources/views/components/datatables/action-button.blade.php b/resources/views/components/datatables/action-button.blade.php index 4366628..b4c3152 100644 --- a/resources/views/components/datatables/action-button.blade.php +++ b/resources/views/components/datatables/action-button.blade.php @@ -12,9 +12,9 @@ diff --git a/resources/views/pages/account/profile/⚡user-settings/user-settings.php b/resources/views/pages/account/profile/⚡user-settings/user-settings.php index 1051f82..ea7cb33 100644 --- a/resources/views/pages/account/profile/⚡user-settings/user-settings.php +++ b/resources/views/pages/account/profile/⚡user-settings/user-settings.php @@ -17,17 +17,20 @@ new class extends Component { $userSettings = auth('web')->user()->settings ?? collect(); - $this->settings = collect(UserSettingKey::cases())->map(function ($key) { + $this->settings = collect(UserSettingKey::cases())->map(function (UserSettingKey $key) { + $field = $key->getSchema(); // Returns InputSchemaField + return [ - 'key' => $key->value, - 'label' => $key->label(), - 'type' => $key->schema()->type, - 'options' => $key->schema()->options, + 'key' => $field->key, + 'label' => $field->label, + 'type' => $field->type, + 'options' => $field->attributes['options'] ?? [], ]; })->toArray(); foreach (UserSettingKey::cases() as $key) { - $this->form[$key->value] = $userSettings->get($key->value, $key->schema()->default); + $field = $key->getSchema(); + $this->form[$field->key] = $userSettings->get($field->key, $field->default); } } @@ -35,8 +38,9 @@ new class extends Component { $rules = []; foreach (UserSettingKey::cases() as $key) { - if ($key->validation()) { - $rules["form.{$key->value}"] = $key->validation(); + $field = $key->getSchema(); + if (! empty($field->rules)) { + $rules["form.{$field->key}"] = $field->rules; } } diff --git a/resources/views/pages/channel/client/⚡api-form-modal/api-form-modal.blade.php b/resources/views/pages/channel/client/⚡api-form-modal/api-form-modal.blade.php index c8540bc..9ffe79b 100644 --- a/resources/views/pages/channel/client/⚡api-form-modal/api-form-modal.blade.php +++ b/resources/views/pages/channel/client/⚡api-form-modal/api-form-modal.blade.php @@ -3,6 +3,9 @@
@foreach($this->endpoints as $key => $endpoint) + + +
value])) { + if (isset($apiEndpoints[$item->value])) { $client_id = $apiEndpoints[$item->value]->client_id; $client_id = $clients[$client_id]; $value = $apiEndpoints[$item->value]->value; @@ -68,12 +69,12 @@ new class extends Component $endpoints[$item->value] = [ 'label' => $item->label(), - 'value' => $value + 'value' => $value, ]; $this->field[$item->value] = [ 'type' => $item->value, 'value' => $value, - 'client_id' => $client_id + 'client_id' => $client_id, ]; } @@ -101,6 +102,13 @@ new class extends Component $assign->execute($endpointToSave); + $this->mode = 'view'; + $this->success($this->message()); } + + public function runSynchronization(ApiType $type, SynchronizeWithApi $api): void + { + $api->execute($type); + } }; diff --git a/resources/views/pages/channel/client/⚡form-modal/form-modal.php b/resources/views/pages/channel/client/⚡form-modal/form-modal.php index 466e117..744ec49 100644 --- a/resources/views/pages/channel/client/⚡form-modal/form-modal.php +++ b/resources/views/pages/channel/client/⚡form-modal/form-modal.php @@ -37,13 +37,13 @@ new class extends Component domain: $this->form->domain, webhook_url: $this->form->webhook, auth_type: $this->form->auth_type, - credentials: $this->form->credentials, + credentials: $this->form->auth_type->transformCredentials($this->form->credentials), )); } else { $modify->execute($this->client, new ModifyConsumerAppDetailDTO( webhook_url: $this->form->webhook, auth_type: $this->form->auth_type, - credentials: $this->form->credentials, + credentials: $this->form->auth_type->transformCredentials($this->form->credentials), )); } @@ -65,7 +65,7 @@ new class extends Component { $this->id = $id; $this->mode = 'update'; - $this->form->fill($this->client->only(['name', 'webhook', 'domain', 'auth_type'])); + $this->form->fill($this->client->only(['name', 'webhook', 'domain', 'auth_type', 'credentials'])); } public function hide(): void diff --git a/resources/views/pages/finance/chart-of-account/⚡form-modal/form-modal.php b/resources/views/pages/finance/chart-of-account/⚡form-modal/form-modal.php index 6d0bc15..9723d01 100644 --- a/resources/views/pages/finance/chart-of-account/⚡form-modal/form-modal.php +++ b/resources/views/pages/finance/chart-of-account/⚡form-modal/form-modal.php @@ -30,13 +30,13 @@ new class extends Component public function updating($property, $value): void { - if($property === 'form.parent_id') { + if ($property === 'form.parent_id') { $props = explode('.', $property); $props = implode('->', $props); $this->{$props} = $value; $coa = $this->chartOfAccounts->where('ulid', $value)->first(); - if($coa) { + if ($coa) { $this->form->code = $coa->code + 1; $this->form->classification = $coa->classification; } diff --git a/resources/views/pages/finance/invoice/⚡form-modal/form-modal.blade.php b/resources/views/pages/finance/invoice/⚡form-modal/form-modal.blade.php index 37ee373..d444eaa 100644 --- a/resources/views/pages/finance/invoice/⚡form-modal/form-modal.blade.php +++ b/resources/views/pages/finance/invoice/⚡form-modal/form-modal.blade.php @@ -9,10 +9,10 @@ /> @forelse ($this->invoiceSchema as $key => $value) @php($model = $value->schema?->isLive() ? 'wire:model.live' : 'wire:model') - @empty diff --git a/resources/views/pages/finance/invoice/⚡form-modal/form-modal.php b/resources/views/pages/finance/invoice/⚡form-modal/form-modal.php index eb2634c..b3111d8 100644 --- a/resources/views/pages/finance/invoice/⚡form-modal/form-modal.php +++ b/resources/views/pages/finance/invoice/⚡form-modal/form-modal.php @@ -6,7 +6,6 @@ use App\Livewire\Concerns\WithToast; use App\Livewire\Forms\Finance\InvoiceForm; use Livewire\Attributes\Computed; use Livewire\Attributes\Locked; -use Livewire\Attributes\Validate; use Livewire\Component; new class extends Component @@ -34,14 +33,12 @@ new class extends Component #[Computed] public function invoiceSchema(): array { - return $this->form ->type ?->schema() ->withContext([ 'faculty' => $this->form->detail['faculty'] ?? null, ]) - ->withFormString('form.detail.') ->getSchema() ?? []; } @@ -58,6 +55,6 @@ new class extends Component { $this->form->reset(); $this->reset('id', 'mode'); - $this->resetErrorBag(); + $this->resetValidation(); } }; diff --git a/resources/views/pages/finance/product-mapping/⚡form-modal/form-modal.php b/resources/views/pages/finance/product-mapping/⚡form-modal/form-modal.php index 11a153e..a4c3f71 100644 --- a/resources/views/pages/finance/product-mapping/⚡form-modal/form-modal.php +++ b/resources/views/pages/finance/product-mapping/⚡form-modal/form-modal.php @@ -47,13 +47,13 @@ new class extends Component public function save(RegisterProductMapping $register, ModifyProductMapping $modify): void { $this->form->validate(); - if($this->mode == 'create') { + if ($this->mode == 'create') { $register->execute(new RegisterProductMappingDTO( name: $this->form->name, code: $this->form->code, coaId: $this->form->coa_id, )); - } elseif($this->mode == 'update') { + } elseif ($this->mode == 'update') { $modify->execute($this->id, $this->form->coa_id); } } diff --git a/resources/views/pages/system/settings/⚡setting-list/setting-list.blade.php b/resources/views/pages/system/settings/⚡setting-list/setting-list.blade.php index daeef53..d4d9923 100644 --- a/resources/views/pages/system/settings/⚡setting-list/setting-list.blade.php +++ b/resources/views/pages/system/settings/⚡setting-list/setting-list.blade.php @@ -12,17 +12,17 @@ - @if ($field->schema()->type->isFile()) + @if ($field->schema()->getSchema()->type->isFile()) @else diff --git a/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.blade.php b/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.blade.php index db92c45..4fb9d6f 100644 --- a/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.blade.php +++ b/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.blade.php @@ -2,10 +2,10 @@
- @if ($this->settingEnum) + @if ($this->inputField) @endif diff --git a/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.php b/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.php index 070940b..b9fc3b2 100644 --- a/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.php +++ b/resources/views/pages/system/settings/⚡update-setting-modal/update-setting-modal.php @@ -6,6 +6,7 @@ use App\Domains\System\Enums\SystemSettingKey; use App\Domains\System\Models\SystemSettings; use App\Livewire\Concerns\WithModal; use App\Livewire\Concerns\WithToast; +use App\UI\Support\Schemas\InputSchemaField; use Livewire\Attributes\Computed; use Livewire\Attributes\Locked; use Livewire\Attributes\Validate; @@ -19,7 +20,7 @@ new class extends Component use WithToast; #[Locked] - public string $settingKey = ''; + public ?SystemSettingKey $settingKey = null; #[Validate] public mixed $settingValue = null; @@ -32,16 +33,16 @@ new class extends Component public function rules(): array { return [ - 'settingValue' => $this->settingEnum->schema()->rules, + 'settingValue' => $this->inputField->rules, ]; } public function show(int|string $id): void { - $this->settingKey = $id; + $this->settingKey = SystemSettingKey::tryFrom($id); $setting = SystemSettings::where('key', $id) ->first(); - if ($this->settingEnum->schema()->type->isFile()) { + if ($this->inputField->type->isFile()) { $this->settingValue = $setting->value; } else { $this->settingValue = $setting?->translated_value ?? '-'; @@ -49,9 +50,9 @@ new class extends Component } #[Computed] - public function settingEnum(): ?SystemSettingKey + public function inputField(): ?InputSchemaField { - return SystemSettingKey::tryFrom($this->settingKey); + return $this->settingKey?->getSchema(); } public function save(UpdateSettings $action): void @@ -59,11 +60,11 @@ new class extends Component $this->validate(); $action->execute(new SystemSetingDTO( - key: $this->settingEnum, + key: $this->settingKey, value: $this->settingValue, )); - $this->success(__('ui/crud.success.updated', ['resource' => $this->settingEnum->label()])); + $this->success(__('ui/crud.success.updated', ['resource' => $this->settingKey->label()])); $this->dispatch('hide-update-setting-modal'); $this->dispatch('setting-updated'); }