-
composer.json
Open in GitHub{ // "require": { "php": "^7.3|^8.0", // "laravel/framework": "^8.54", "laravel/jetstream": "^2.4" }, // }
-
app/Http/Livewire/AddTransactionButton.php
Open in GitHubuse App\Models\Asset; use App\Models\Account; use App\Transactions\CryptoTransaction; use Livewire\Component; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; class AddTransactionButton extends Component { public Account $account; public bool $newTransactionModalOpen = false; public $state = [ 'asset_id' => null, 'asset_price' => 0, 'amount_in_tokens' => 0, 'amount_in_dollars' => 0 ]; public function render() { return view('livewire.add-transaction-button'); } public function addTransaction() { $data = Validator::make($this->state, [ 'asset_id' => ['required', Rule::exists('assets', 'id')], 'asset_price' => ['required', 'numeric', 'gt:0'], 'amount_in_tokens' => ['required', 'numeric', 'gt:0'], 'amount_in_dollars' => ['required', 'numeric', 'gt:0'] ])->validate(); $this->account->addTransaction( CryptoTransaction::fromCrypto( $data['amount_in_tokens'], $this->getSelectedAssetProperty() ) ); $this->closeNewTransactionModal(); $this->emit('transactionCreated'); } public function closeNewTransactionModal(): void { $this->newTransactionModalOpen = false; } public function getAvailableAssetsProperty() { return Asset::all(); } public function getSelectedAssetProperty(): ?Asset { return Asset::find($this->state['asset_id']); } public function changedAsset() { $this->calculateAssetPrice(); } public function changedCurrentAssetPrice() { $this->state['amount_in_dollars'] = 0; $this->state['amount_in_tokens'] = 0; } public function changedAmountOfTokens() { $this->state['amount_in_dollars'] = $this->getSelectedAssetProperty()->current_price * $this->state['amount_in_tokens']; } public function changedAmountOfDollars() { $this->state['amount_in_tokens'] = $this->state['amount_in_dollars'] / $this->getSelectedAssetProperty()->current_price; } public function calculateAssetPrice() { $this->state['asset_price'] = $this->getSelectedAssetProperty()->current_price; } }
-
resources/views/livewire/add-transaction-button.blade.php
Open in GitHub<div> <x-buttons.branded-button wire:click="$set('newTransactionModalOpen', true)">Add Transaction </x-buttons.branded-button> <x-jet-dialog-modal wire:model="newTransactionModalOpen"> <x-slot name="title"> {{ __('New Transaction') }} </x-slot> <x-slot name="content"> <div class="mt-6 sm:mt-5 space-y-6 sm:space-y-5"> <div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5"> <label for="type" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"> Currency </label> <div class="mt-1 sm:mt-0 sm:col-span-2"> <select id="currency" name="currency" wire:model="state.asset_id" wire:change="changedAsset" class="max-w-lg block focus:ring-indigo-500 focus:border-indigo-500 w-full shadow-sm sm:max-w-xs sm:text-sm border-gray-300 rounded-md"> <option default selected>Select a Crypto</option> @foreach ($this->availableAssets as $asset) <option value="{{ $asset->id }}">{{ $asset->name }}</option> @endforeach </select> </div> </div> @if ($this->selectedAsset) <div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5"> <label for="name" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"> Current Asset Price </label> <div class="mt-1 sm:mt-0 sm:col-span-2"> <div class="max-w-lg flex rounded-md shadow-sm"> <input type="text" name="name" id="name" wire:model="state.asset_price" wire:change="changedCurrentAssetPrice" class="flex-1 block w-full focus:ring-blue-500 focus:border-blue-500 min-w-0 rounded-none rounded-r-md sm:text-sm border-gray-300"> </div> </div> </div> @endif <div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5"> <label for="name" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"> Amount in Tokens </label> <div class="mt-1 sm:mt-0 sm:col-span-2"> <div class="max-w-lg flex rounded-md shadow-sm"> <input type="text" name="name" id="name" wire:model="state.amount_in_tokens" wire:change="changedAmountOfTokens" class="flex-1 block w-full focus:ring-blue-500 focus:border-blue-500 min-w-0 rounded-none rounded-r-md sm:text-sm border-gray-300"> </div> </div> </div> <div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5"> <label for="name" class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"> Amount in Dollars </label> <div class="mt-1 sm:mt-0 sm:col-span-2"> <div class="max-w-lg flex rounded-md shadow-sm"> <input type="text" name="name" id="name" wire:model="state.amount_in_dollars" wire:change="changedAmountOfDollars" class="flex-1 block w-full focus:ring-blue-500 focus:border-blue-500 min-w-0 rounded-none rounded-r-md sm:text-sm border-gray-300"> </div> </div> </div> </div> </x-slot> <x-slot name="footer"> <x-jet-secondary-button wire:click="closeNewTransactionModal" wire:loading.attr="disabled"> {{ __('Cancel') }} </x-jet-secondary-button> <x-buttons.branded-button class="ml-2" wire:click="addTransaction" wire:loading.class="opacity-75" wire:loading.attr="disabled"> {{ __('Save') }} </x-buttons.branded-button> </x-slot> </x-jet-dialog-modal> </div>