Selaa lähdekoodia

update: ConnectedAccounts page

3.x
wallo 1 vuosi sitten
vanhempi
commit
7cc0f85d32
32 muutettua tiedostoa jossa 407 lisäystä ja 221 poistoa
  1. 3
    1
      app/Events/PlaidSuccess.php
  2. 11
    11
      app/Events/StartTransactionImport.php
  3. 8
    8
      app/Filament/Company/Pages/Accounting/AccountChart.php
  4. 2
    2
      app/Filament/Company/Pages/Service/ConnectedAccount.php
  5. 0
    3
      app/Filament/Company/Resources/Accounting/TransactionResource.php
  6. 0
    1
      app/Filament/Company/Resources/Accounting/TransactionResource/Pages/CreateTransaction.php
  7. 3
    5
      app/Filament/Company/Resources/Banking/AccountResource.php
  8. 0
    5
      app/Filament/Company/Resources/Banking/AccountResource/Pages/CreateAccount.php
  9. 0
    3
      app/Filament/Company/Resources/Banking/AccountResource/Pages/EditAccount.php
  10. 0
    2
      app/Listeners/CreateConnectedAccount.php
  11. 1
    9
      app/Listeners/HandleTransactionImport.php
  12. 63
    45
      app/Livewire/Company/Service/ConnectedAccount/ListInstitutions.php
  13. 2
    2
      app/Livewire/UpdatePassword.php
  14. 2
    2
      app/Livewire/UpdateProfileInformation.php
  15. 1
    2
      app/Models/Accounting/AccountSubtype.php
  16. 1
    2
      app/Models/Banking/BankAccount.php
  17. 1
    1
      app/Models/Banking/ConnectedBankAccount.php
  18. 34
    34
      app/Observers/AccountObserver.php
  19. 1
    3
      app/Observers/BankAccountObserver.php
  20. 0
    1
      app/Providers/EventServiceProvider.php
  21. 9
    9
      app/Providers/MacroServiceProvider.php
  22. 1
    1
      app/Services/PlaidService.php
  23. 4
    2
      app/Utilities/Plaid/AccountTypeMapper.php
  24. 22
    22
      composer.lock
  25. 2
    2
      config/chart-of-accounts.php
  26. 159
    0
      config/livewire.php
  27. 1
    1
      config/services.php
  28. 0
    1
      database/factories/Accounting/AccountFactory.php
  29. 17
    14
      package-lock.json
  30. 6
    0
      resources/views/components/actions/delete-bank-connection-modal.blade.php
  31. 18
    0
      resources/views/components/actions/transaction-import-modal.blade.php
  32. 35
    27
      resources/views/livewire/company/service/connected-account/list-institutions.blade.php

+ 3
- 1
app/Events/PlaidSuccess.php Näytä tiedosto

8
 
8
 
9
 class PlaidSuccess
9
 class PlaidSuccess
10
 {
10
 {
11
-    use Dispatchable, SerializesModels;
11
+    use Dispatchable;
12
+    use SerializesModels;
12
 
13
 
13
     public string $publicToken;
14
     public string $publicToken;
15
+
14
     public string $accessToken;
16
     public string $accessToken;
15
 
17
 
16
     public Company $company;
18
     public Company $company;

+ 11
- 11
app/Events/StartTransactionImport.php Näytä tiedosto

2
 
2
 
3
 namespace App\Events;
3
 namespace App\Events;
4
 
4
 
5
+use App\Models\Banking\ConnectedBankAccount;
5
 use App\Models\Company;
6
 use App\Models\Company;
6
-use Illuminate\Broadcasting\Channel;
7
-use Illuminate\Broadcasting\InteractsWithSockets;
8
-use Illuminate\Broadcasting\PresenceChannel;
9
-use Illuminate\Broadcasting\PrivateChannel;
10
-use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
11
 use Illuminate\Foundation\Events\Dispatchable;
7
 use Illuminate\Foundation\Events\Dispatchable;
12
 use Illuminate\Queue\SerializesModels;
8
 use Illuminate\Queue\SerializesModels;
13
 
9
 
14
 class StartTransactionImport
10
 class StartTransactionImport
15
 {
11
 {
16
-    use Dispatchable, SerializesModels;
12
+    use Dispatchable;
13
+    use SerializesModels;
17
 
14
 
18
     public Company $company;
15
     public Company $company;
19
-    public $connectedBankAccountId;
20
-    public $selectedBankAccountId;
21
-    public $startDate;
16
+
17
+    public ConnectedBankAccount $connectedBankAccount;
18
+
19
+    public mixed $selectedBankAccountId;
20
+
21
+    public mixed $startDate;
22
 
22
 
23
     /**
23
     /**
24
      * Create a new event instance.
24
      * Create a new event instance.
25
      */
25
      */
26
-    public function __construct($company, $connectedBankAccountId, $selectedBankAccountId, $startDate)
26
+    public function __construct($company, $connectedBankAccount, $selectedBankAccountId, $startDate)
27
     {
27
     {
28
         $this->company = $company;
28
         $this->company = $company;
29
-        $this->connectedBankAccountId = $connectedBankAccountId;
29
+        $this->connectedBankAccount = $connectedBankAccount;
30
         $this->selectedBankAccountId = $selectedBankAccountId;
30
         $this->selectedBankAccountId = $selectedBankAccountId;
31
         $this->startDate = $startDate;
31
         $this->startDate = $startDate;
32
     }
32
     }

+ 8
- 8
app/Filament/Company/Pages/Accounting/AccountChart.php Näytä tiedosto

2
 
2
 
3
 namespace App\Filament\Company\Pages\Accounting;
3
 namespace App\Filament\Company\Pages\Accounting;
4
 
4
 
5
-use App\Models\Accounting\Account as ChartModel;
6
 use App\Enums\Accounting\AccountCategory;
5
 use App\Enums\Accounting\AccountCategory;
6
+use App\Models\Accounting\Account as ChartModel;
7
 use App\Models\Accounting\AccountSubtype;
7
 use App\Models\Accounting\AccountSubtype;
8
 use App\Utilities\Accounting\AccountCode;
8
 use App\Utilities\Accounting\AccountCode;
9
 use App\Utilities\Currency\CurrencyAccessor;
9
 use App\Utilities\Currency\CurrencyAccessor;
117
                 ->disabled(static fn (string $operation, ?ChartModel $record) => $operation === 'edit' && $record?->default === true)
117
                 ->disabled(static fn (string $operation, ?ChartModel $record) => $operation === 'edit' && $record?->default === true)
118
                 ->options($this->getChartSubtypeOptions($useActiveTab))
118
                 ->options($this->getChartSubtypeOptions($useActiveTab))
119
                 ->afterStateUpdated(static function (?string $state, Set $set): void {
119
                 ->afterStateUpdated(static function (?string $state, Set $set): void {
120
-                   if ($state) {
121
-                       $companyId = auth()->user()->currentCompany->id;
122
-                       $generatedCode = AccountCode::generate($companyId, $state);
123
-                       $set('code', $generatedCode);
124
-                   }
120
+                    if ($state) {
121
+                        $companyId = auth()->user()->currentCompany->id;
122
+                        $generatedCode = AccountCode::generate($companyId, $state);
123
+                        $set('code', $generatedCode);
124
+                    }
125
                 }),
125
                 }),
126
             TextInput::make('code')
126
             TextInput::make('code')
127
                 ->label('Code')
127
                 ->label('Code')
154
             AccountSubtype::where('category', $this->activeTab)->get() :
154
             AccountSubtype::where('category', $this->activeTab)->get() :
155
             AccountSubtype::all();
155
             AccountSubtype::all();
156
 
156
 
157
-        return $subtypes->groupBy(fn(AccountSubtype $subtype) => $subtype->type->getLabel())
158
-            ->map(fn(Collection $subtypes, string $type) => $subtypes->mapWithKeys(static fn (AccountSubtype $subtype) => [$subtype->id => $subtype->name]))
157
+        return $subtypes->groupBy(fn (AccountSubtype $subtype) => $subtype->type->getLabel())
158
+            ->map(fn (Collection $subtypes, string $type) => $subtypes->mapWithKeys(static fn (AccountSubtype $subtype) => [$subtype->id => $subtype->name]))
159
             ->toArray();
159
             ->toArray();
160
     }
160
     }
161
 
161
 

+ 2
- 2
app/Filament/Company/Pages/Service/ConnectedAccount.php Näytä tiedosto

20
 
20
 
21
     protected static string $view = 'filament.company.pages.service.connected-account';
21
     protected static string $view = 'filament.company.pages.service.connected-account';
22
 
22
 
23
-    public function getTitle(): string|Htmlable
23
+    public function getTitle(): string | Htmlable
24
     {
24
     {
25
         return translate(static::$title);
25
         return translate(static::$title);
26
     }
26
     }
48
         ];
48
         ];
49
     }
49
     }
50
 
50
 
51
-    public function getMaxContentWidth(): MaxWidth|string|null
51
+    public function getMaxContentWidth(): MaxWidth | string | null
52
     {
52
     {
53
         return MaxWidth::ScreenLarge;
53
         return MaxWidth::ScreenLarge;
54
     }
54
     }

+ 0
- 3
app/Filament/Company/Resources/Accounting/TransactionResource.php Näytä tiedosto

4
 
4
 
5
 use App\Enums\DateFormat;
5
 use App\Enums\DateFormat;
6
 use App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
6
 use App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
7
-use App\Filament\Company\Resources\Accounting\TransactionResource\RelationManagers;
8
 use App\Models\Accounting\Transaction;
7
 use App\Models\Accounting\Transaction;
9
 use App\Models\Banking\Account;
8
 use App\Models\Banking\Account;
10
 use App\Models\Setting\Localization;
9
 use App\Models\Setting\Localization;
14
 use Filament\Support\Enums\FontWeight;
13
 use Filament\Support\Enums\FontWeight;
15
 use Filament\Tables;
14
 use Filament\Tables;
16
 use Filament\Tables\Table;
15
 use Filament\Tables\Table;
17
-use Illuminate\Database\Eloquent\Builder;
18
-use Illuminate\Database\Eloquent\SoftDeletingScope;
19
 use Illuminate\Support\Carbon;
16
 use Illuminate\Support\Carbon;
20
 
17
 
21
 class TransactionResource extends Resource
18
 class TransactionResource extends Resource

+ 0
- 1
app/Filament/Company/Resources/Accounting/TransactionResource/Pages/CreateTransaction.php Näytä tiedosto

3
 namespace App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
3
 namespace App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
4
 
4
 
5
 use App\Filament\Company\Resources\Accounting\TransactionResource;
5
 use App\Filament\Company\Resources\Accounting\TransactionResource;
6
-use Filament\Actions;
7
 use Filament\Resources\Pages\CreateRecord;
6
 use Filament\Resources\Pages\CreateRecord;
8
 
7
 
9
 class CreateTransaction extends CreateRecord
8
 class CreateTransaction extends CreateRecord

+ 3
- 5
app/Filament/Company/Resources/Banking/AccountResource.php Näytä tiedosto

4
 
4
 
5
 use App\Actions\OptionAction\CreateCurrency;
5
 use App\Actions\OptionAction\CreateCurrency;
6
 use App\Enums\Accounting\AccountCategory;
6
 use App\Enums\Accounting\AccountCategory;
7
-use App\Enums\Accounting\AccountType;
8
 use App\Enums\BankAccountType;
7
 use App\Enums\BankAccountType;
9
 use App\Facades\Forex;
8
 use App\Facades\Forex;
10
 use App\Filament\Company\Resources\Banking\AccountResource\Pages;
9
 use App\Filament\Company\Resources\Banking\AccountResource\Pages;
25
 use Illuminate\Support\Facades\Auth;
24
 use Illuminate\Support\Facades\Auth;
26
 use Illuminate\Support\Facades\DB;
25
 use Illuminate\Support\Facades\DB;
27
 use Illuminate\Validation\Rules\Unique;
26
 use Illuminate\Validation\Rules\Unique;
28
-use Livewire\Component as Livewire;
29
 use Wallo\FilamentSelectify\Components\ToggleButton;
27
 use Wallo\FilamentSelectify\Components\ToggleButton;
30
 
28
 
31
 class AccountResource extends Resource
29
 class AccountResource extends Resource
198
                     ->icon(static fn (BankAccount $record) => $record->isEnabled() ? 'heroicon-o-lock-closed' : null)
196
                     ->icon(static fn (BankAccount $record) => $record->isEnabled() ? 'heroicon-o-lock-closed' : null)
199
                     ->tooltip(static fn (BankAccount $record) => $record->isEnabled() ? 'Default Account' : null)
197
                     ->tooltip(static fn (BankAccount $record) => $record->isEnabled() ? 'Default Account' : null)
200
                     ->iconPosition('after')
198
                     ->iconPosition('after')
201
-                    ->description(static fn (BankAccount $record) => $record->number ?: 'N/A')
199
+                    ->description(static fn (BankAccount $record) => $record->mask ?: 'N/A')
202
                     ->sortable(),
200
                     ->sortable(),
203
                 Tables\Columns\TextColumn::make('account.starting_balance')
201
                 Tables\Columns\TextColumn::make('account.starting_balance')
204
                     ->localizeLabel('Current Balance')
202
                     ->localizeLabel('Current Balance')
300
 
298
 
301
         $subtypes = AccountSubtype::where('category', $category)->get();
299
         $subtypes = AccountSubtype::where('category', $category)->get();
302
 
300
 
303
-        return $subtypes->groupBy(fn(AccountSubtype $subtype) => $subtype->type->getLabel())
304
-            ->map(fn(Collection $subtypes, string $type) => $subtypes->mapWithKeys(static fn (AccountSubtype $subtype) => [$subtype->id => $subtype->name]))
301
+        return $subtypes->groupBy(fn (AccountSubtype $subtype) => $subtype->type->getLabel())
302
+            ->map(fn (Collection $subtypes, string $type) => $subtypes->mapWithKeys(static fn (AccountSubtype $subtype) => [$subtype->id => $subtype->name]))
305
             ->toArray();
303
             ->toArray();
306
     }
304
     }
307
 }
305
 }

+ 0
- 5
app/Filament/Company/Resources/Banking/AccountResource/Pages/CreateAccount.php Näytä tiedosto

3
 namespace App\Filament\Company\Resources\Banking\AccountResource\Pages;
3
 namespace App\Filament\Company\Resources\Banking\AccountResource\Pages;
4
 
4
 
5
 use App\Filament\Company\Resources\Banking\AccountResource;
5
 use App\Filament\Company\Resources\Banking\AccountResource;
6
-use App\Models\Banking\BankAccount;
7
-use App\Traits\HandlesResourceRecordCreation;
8
 use Filament\Resources\Pages\CreateRecord;
6
 use Filament\Resources\Pages\CreateRecord;
9
-use Filament\Support\Exceptions\Halt;
10
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
11
-use Illuminate\Support\Facades\Auth;
12
 use Illuminate\Support\Facades\Log;
8
 use Illuminate\Support\Facades\Log;
13
 
9
 
14
 class CreateAccount extends CreateRecord
10
 class CreateAccount extends CreateRecord
15
 {
11
 {
16
-
17
     protected static string $resource = AccountResource::class;
12
     protected static string $resource = AccountResource::class;
18
 
13
 
19
     protected function getRedirectUrl(): string
14
     protected function getRedirectUrl(): string

+ 0
- 3
app/Filament/Company/Resources/Banking/AccountResource/Pages/EditAccount.php Näytä tiedosto

6
 use App\Traits\HandlesResourceRecordUpdate;
6
 use App\Traits\HandlesResourceRecordUpdate;
7
 use Filament\Actions;
7
 use Filament\Actions;
8
 use Filament\Resources\Pages\EditRecord;
8
 use Filament\Resources\Pages\EditRecord;
9
-use Filament\Support\Exceptions\Halt;
10
-use Illuminate\Database\Eloquent\Model;
11
-use Illuminate\Support\Facades\Auth;
12
 
9
 
13
 class EditAccount extends EditRecord
10
 class EditAccount extends EditRecord
14
 {
11
 {

+ 0
- 2
app/Listeners/CreateConnectedAccount.php Näytä tiedosto

6
 use App\Models\Banking\Institution;
6
 use App\Models\Banking\Institution;
7
 use App\Models\Company;
7
 use App\Models\Company;
8
 use App\Services\PlaidService;
8
 use App\Services\PlaidService;
9
-use Illuminate\Contracts\Queue\ShouldQueue;
10
-use Illuminate\Queue\InteractsWithQueue;
11
 use Illuminate\Support\Facades\DB;
9
 use Illuminate\Support\Facades\DB;
12
 
10
 
13
 class CreateConnectedAccount
11
 class CreateConnectedAccount

+ 1
- 9
app/Listeners/HandleTransactionImport.php Näytä tiedosto

10
 use App\Models\Setting\Currency;
10
 use App\Models\Setting\Currency;
11
 use App\Services\PlaidService;
11
 use App\Services\PlaidService;
12
 use App\Utilities\Currency\CurrencyAccessor;
12
 use App\Utilities\Currency\CurrencyAccessor;
13
-use Illuminate\Contracts\Queue\ShouldQueue;
14
-use Illuminate\Queue\InteractsWithQueue;
15
 use Illuminate\Support\Facades\DB;
13
 use Illuminate\Support\Facades\DB;
16
 
14
 
17
 class HandleTransactionImport
15
 class HandleTransactionImport
39
     public function processTransactionImport(StartTransactionImport $event): void
37
     public function processTransactionImport(StartTransactionImport $event): void
40
     {
38
     {
41
         $company = $event->company;
39
         $company = $event->company;
42
-        $connectedBankAccountId = $event->connectedBankAccountId;
40
+        $connectedBankAccount = $event->connectedBankAccount;
43
         $selectedBankAccountId = $event->selectedBankAccountId;
41
         $selectedBankAccountId = $event->selectedBankAccountId;
44
         $startDate = $event->startDate;
42
         $startDate = $event->startDate;
45
 
43
 
46
-        $connectedBankAccount = ConnectedBankAccount::find($connectedBankAccountId);
47
-
48
-        if ($connectedBankAccount === null) {
49
-            return;
50
-        }
51
-
52
         $accessToken = $connectedBankAccount->access_token;
44
         $accessToken = $connectedBankAccount->access_token;
53
 
45
 
54
         if ($selectedBankAccountId === 'new') {
46
         if ($selectedBankAccountId === 'new') {

+ 63
- 45
app/Livewire/Company/Service/ConnectedAccount/ListInstitutions.php Näytä tiedosto

12
 use Filament\Actions\Action;
12
 use Filament\Actions\Action;
13
 use Filament\Actions\Concerns\InteractsWithActions;
13
 use Filament\Actions\Concerns\InteractsWithActions;
14
 use Filament\Actions\Contracts\HasActions;
14
 use Filament\Actions\Contracts\HasActions;
15
+use Filament\Forms\Components\Checkbox;
15
 use Filament\Forms\Components\DatePicker;
16
 use Filament\Forms\Components\DatePicker;
17
+use Filament\Forms\Components\Placeholder;
16
 use Filament\Forms\Components\Select;
18
 use Filament\Forms\Components\Select;
17
 use Filament\Forms\Concerns\InteractsWithForms;
19
 use Filament\Forms\Concerns\InteractsWithForms;
18
 use Filament\Forms\Contracts\HasForms;
20
 use Filament\Forms\Contracts\HasForms;
19
-use Filament\Forms\Form;
20
-use Filament\Forms\Get;
21
 use Filament\Notifications\Notification;
21
 use Filament\Notifications\Notification;
22
-use Filament\Support\Enums\MaxWidth;
22
+use Filament\Support\Enums\Alignment;
23
 use Illuminate\Contracts\View\View;
23
 use Illuminate\Contracts\View\View;
24
-use Illuminate\Database\Eloquent\Builder;
25
 use Illuminate\Database\Eloquent\Collection;
24
 use Illuminate\Database\Eloquent\Collection;
26
-use Illuminate\Database\Eloquent\Relations\HasMany;
27
 use Illuminate\Support\Facades\Auth;
25
 use Illuminate\Support\Facades\Auth;
28
 use Illuminate\Support\Facades\Log;
26
 use Illuminate\Support\Facades\Log;
29
-use JsonException;
30
 use Livewire\Attributes\Computed;
27
 use Livewire\Attributes\Computed;
31
 use Livewire\Attributes\On;
28
 use Livewire\Attributes\On;
32
 use Livewire\Component;
29
 use Livewire\Component;
33
 use RuntimeException;
30
 use RuntimeException;
34
 
31
 
35
-class ListInstitutions extends Component implements HasForms, HasActions
32
+class ListInstitutions extends Component implements HasActions, HasForms
36
 {
33
 {
37
-    use InteractsWithForms;
38
     use InteractsWithActions;
34
     use InteractsWithActions;
35
+    use InteractsWithForms;
39
 
36
 
40
     protected PlaidService $plaidService;
37
     protected PlaidService $plaidService;
41
 
38
 
42
     public User $user;
39
     public User $user;
43
 
40
 
44
-    public ?ConnectedBankAccount $connectedBankAccount = null;
41
+    public string $modalWidth;
45
 
42
 
46
     public function boot(PlaidService $plaidService): void
43
     public function boot(PlaidService $plaidService): void
47
     {
44
     {
54
     }
51
     }
55
 
52
 
56
     #[Computed]
53
     #[Computed]
57
-    public function connectedInstitutions(): Collection|array
54
+    public function connectedInstitutions(): Collection | array
58
     {
55
     {
59
         return Institution::withWhereHas('connectedBankAccounts')
56
         return Institution::withWhereHas('connectedBankAccounts')
60
             ->get();
57
             ->get();
66
             ->link()
63
             ->link()
67
             ->icon('heroicon-o-cloud-arrow-down')
64
             ->icon('heroicon-o-cloud-arrow-down')
68
             ->label('Start Importing Transactions')
65
             ->label('Start Importing Transactions')
69
-            ->modalWidth(MaxWidth::TwoExtraLarge)
66
+            ->modalWidth(fn () => $this->modalWidth)
67
+            ->modalFooterActionsAlignment(fn () => $this->modalWidth === 'screen' ? Alignment::Center : Alignment::Start)
70
             ->stickyModalHeader()
68
             ->stickyModalHeader()
71
             ->stickyModalFooter()
69
             ->stickyModalFooter()
72
-            ->record($this->connectedBankAccount)
73
-            ->mountUsing(function (array $arguments, Form $form) {
74
-                $connectedAccountId = $arguments['connectedBankAccount'];
75
-
76
-                $this->connectedBankAccount = ConnectedBankAccount::find($connectedAccountId);
77
-
78
-                $form
79
-                    ->fill($this->connectedBankAccount->toArray())
80
-                    ->operation('edit')
81
-                    ->model($this->connectedBankAccount);
82
-            })
70
+            ->record(fn (array $arguments) => ConnectedBankAccount::find($arguments['connectedBankAccount']))
83
             ->form([
71
             ->form([
72
+                Placeholder::make('import_from')
73
+                    ->label('Import Transactions From')
74
+                    ->content(static fn (ConnectedBankAccount $connectedBankAccount): View => view(
75
+                        'components.actions.transaction-import-modal',
76
+                        compact('connectedBankAccount')
77
+                    )),
78
+                Placeholder::make('info')
79
+                    ->hiddenLabel()
80
+                    ->visible(static fn (ConnectedBankAccount $connectedBankAccount) => $connectedBankAccount->bank_account_id === null)
81
+                    ->content(static fn (ConnectedBankAccount $connectedBankAccount) => 'If ' . $connectedBankAccount->name . ' already has transactions for an existing account, select the account to import transactions into.'),
84
                 Select::make('bank_account_id')
82
                 Select::make('bank_account_id')
85
                     ->label('Select Account')
83
                     ->label('Select Account')
86
-                    ->visible(static fn (?ConnectedBankAccount $connectedBankAccount) => $connectedBankAccount?->bank_account_id === null)
87
-                    ->options(fn () => $this->getBankAccountOptions())
88
-                    ->required()
89
-                    ->placeholder('Select an account to start importing transactions for.'),
84
+                    ->visible(static fn (ConnectedBankAccount $connectedBankAccount) => $connectedBankAccount->bank_account_id === null)
85
+                    ->options(fn (ConnectedBankAccount $connectedBankAccount) => $this->getBankAccountOptions($connectedBankAccount))
86
+                    ->required(),
90
                 DatePicker::make('start_date')
87
                 DatePicker::make('start_date')
91
                     ->label('Start Date')
88
                     ->label('Start Date')
92
                     ->required()
89
                     ->required()
93
                     ->placeholder('Select a start date for importing transactions.'),
90
                     ->placeholder('Select a start date for importing transactions.'),
94
             ])
91
             ])
95
             ->action(function (array $arguments, array $data, ConnectedBankAccount $connectedBankAccount) {
92
             ->action(function (array $arguments, array $data, ConnectedBankAccount $connectedBankAccount) {
96
-                $connectedBankAccountId = $arguments['connectedBankAccount'];
97
                 $selectedBankAccountId = $data['bank_account_id'] ?? $connectedBankAccount->bank_account_id;
93
                 $selectedBankAccountId = $data['bank_account_id'] ?? $connectedBankAccount->bank_account_id;
98
                 $startDate = $data['start_date'];
94
                 $startDate = $data['start_date'];
99
                 $company = $this->user->currentCompany;
95
                 $company = $this->user->currentCompany;
100
 
96
 
101
-                StartTransactionImport::dispatch($company, $connectedBankAccountId, $selectedBankAccountId, $startDate);
97
+                StartTransactionImport::dispatch($company, $connectedBankAccount, $selectedBankAccountId, $startDate);
102
 
98
 
103
                 unset($this->connectedInstitutions);
99
                 unset($this->connectedInstitutions);
104
             });
100
             });
105
     }
101
     }
106
 
102
 
107
-    public function getBankAccountOptions(): array
103
+    public function getBankAccountOptions(ConnectedBankAccount $connectedBankAccount): array
108
     {
104
     {
109
-        $institutionId = $this->connectedBankAccount->institution_id ?? null;
110
-
111
-        $options = BankAccount::query()
112
-            ->where('company_id', $this->user->currentCompany->id)
113
-            ->when($institutionId, static fn($query) => $query->where('institution_id', $institutionId))
114
-            ->whereDoesntHave('connectedBankAccount')
115
-            ->with('account')
116
-            ->get()
117
-            ->pluck('account.name', 'id')
118
-            ->toArray();
119
-
120
-        return ['new' => 'New Account'] + $options;
105
+        $institutionId = $connectedBankAccount->institution_id ?? null;
106
+        $options = ['new' => 'New Account'];
107
+
108
+        if ($institutionId) {
109
+            $options += BankAccount::query()
110
+                ->where('company_id', $this->user->currentCompany->id)
111
+                ->where('institution_id', $institutionId)
112
+                ->whereDoesntHave('connectedBankAccount')
113
+                ->with('account')
114
+                ->get()
115
+                ->pluck('account.name', 'id')
116
+                ->toArray();
117
+        }
118
+
119
+        return $options;
121
     }
120
     }
122
 
121
 
123
     public function stopImportingTransactions(): Action
122
     public function stopImportingTransactions(): Action
137
 
136
 
138
                 if ($connectedBankAccount) {
137
                 if ($connectedBankAccount) {
139
                     $connectedBankAccount->update([
138
                     $connectedBankAccount->update([
140
-                        'import_transactions' => !$connectedBankAccount->import_transactions,
139
+                        'import_transactions' => ! $connectedBankAccount->import_transactions,
141
                     ]);
140
                     ]);
142
                 }
141
                 }
143
 
142
 
150
         return Action::make('deleteBankConnection')
149
         return Action::make('deleteBankConnection')
151
             ->iconButton()
150
             ->iconButton()
152
             ->icon('heroicon-o-trash')
151
             ->icon('heroicon-o-trash')
153
-            ->requiresConfirmation()
152
+            ->color('danger')
154
             ->modalHeading('Delete Bank Connection')
153
             ->modalHeading('Delete Bank Connection')
155
-            ->modalDescription('Deleting this bank connection will stop the import of transactions for all accounts associated with this bank. Existing transactions will remain unchanged.')
154
+            ->modalWidth(fn () => $this->modalWidth)
155
+            ->modalFooterActionsAlignment(fn () => $this->modalWidth === 'screen' ? Alignment::Center : Alignment::Start)
156
+            ->stickyModalHeader()
157
+            ->stickyModalFooter()
158
+            ->record(fn (array $arguments) => Institution::find($arguments['institution']))
159
+            ->form([
160
+                Placeholder::make('accounts')
161
+                    ->hiddenLabel()
162
+                    ->content(static fn (Institution $institution): View => view(
163
+                        'components.actions.delete-bank-connection-modal',
164
+                        compact('institution')
165
+                    )),
166
+                Placeholder::make('info')
167
+                    ->hiddenLabel()
168
+                    ->content('Deleting this bank connection will stop the import of transactions for all accounts associated with this bank. Existing transactions will remain unchanged.'),
169
+                Checkbox::make('confirm')
170
+                    ->label('Yes, I want to delete this bank connection.')
171
+                    ->markAsRequired(false)
172
+                    ->required(),
173
+            ])
156
             ->action(function (array $arguments) {
174
             ->action(function (array $arguments) {
157
                 $institutionId = $arguments['institution'];
175
                 $institutionId = $arguments['institution'];
158
 
176
 
183
 
201
 
184
             $this->dispatch('initializeLink', $plaidLinkToken)->self();
202
             $this->dispatch('initializeLink', $plaidLinkToken)->self();
185
         } catch (RuntimeException) {
203
         } catch (RuntimeException) {
186
-            Log::error("Error creating Plaid token.");
204
+            Log::error('Error creating Plaid token.');
187
 
205
 
188
             $this->sendErrorNotification("We're currently experiencing issues connecting your account. Please try again in a few moments.");
206
             $this->sendErrorNotification("We're currently experiencing issues connecting your account. Please try again in a few moments.");
189
         }
207
         }

+ 2
- 2
app/Livewire/UpdatePassword.php Näytä tiedosto

10
 use Filament\Notifications\Notification;
10
 use Filament\Notifications\Notification;
11
 use Filament\Support\Exceptions\Halt;
11
 use Filament\Support\Exceptions\Halt;
12
 use Illuminate\Contracts\Auth\Authenticatable;
12
 use Illuminate\Contracts\Auth\Authenticatable;
13
+use Illuminate\Contracts\View\View;
13
 use Illuminate\Database\Eloquent\Model;
14
 use Illuminate\Database\Eloquent\Model;
14
 use Illuminate\Support\Facades\Hash;
15
 use Illuminate\Support\Facades\Hash;
15
 use Illuminate\Validation\Rules\Password;
16
 use Illuminate\Validation\Rules\Password;
16
 use Livewire\Component;
17
 use Livewire\Component;
17
-use Illuminate\Contracts\View\View;
18
 use RuntimeException;
18
 use RuntimeException;
19
 
19
 
20
 /**
20
 /**
34
         $this->fillForm();
34
         $this->fillForm();
35
     }
35
     }
36
 
36
 
37
-    public function getUser(): Authenticatable|Model
37
+    public function getUser(): Authenticatable | Model
38
     {
38
     {
39
         $user = Filament::auth()->user();
39
         $user = Filament::auth()->user();
40
 
40
 

+ 2
- 2
app/Livewire/UpdateProfileInformation.php Näytä tiedosto

11
 use Filament\Notifications\Notification;
11
 use Filament\Notifications\Notification;
12
 use Filament\Support\Exceptions\Halt;
12
 use Filament\Support\Exceptions\Halt;
13
 use Illuminate\Contracts\Auth\Authenticatable;
13
 use Illuminate\Contracts\Auth\Authenticatable;
14
+use Illuminate\Contracts\View\View;
14
 use Illuminate\Database\Eloquent\Model;
15
 use Illuminate\Database\Eloquent\Model;
15
 use Illuminate\Http\UploadedFile;
16
 use Illuminate\Http\UploadedFile;
16
 use Illuminate\Support\Facades\Blade;
17
 use Illuminate\Support\Facades\Blade;
17
 use Illuminate\Support\HtmlString;
18
 use Illuminate\Support\HtmlString;
18
 use Livewire\Component;
19
 use Livewire\Component;
19
-use Illuminate\Contracts\View\View;
20
 use RuntimeException;
20
 use RuntimeException;
21
 use Wallo\FilamentCompanies\Features;
21
 use Wallo\FilamentCompanies\Features;
22
 
22
 
37
         $this->fillForm();
37
         $this->fillForm();
38
     }
38
     }
39
 
39
 
40
-    public function getUser(): Authenticatable|Model
40
+    public function getUser(): Authenticatable | Model
41
     {
41
     {
42
         $user = Filament::auth()->user();
42
         $user = Filament::auth()->user();
43
 
43
 

+ 1
- 2
app/Models/Accounting/AccountSubtype.php Näytä tiedosto

15
 
15
 
16
 class AccountSubtype extends Model
16
 class AccountSubtype extends Model
17
 {
17
 {
18
-    use HasFactory;
19
     use CompanyOwned;
18
     use CompanyOwned;
19
+    use HasFactory;
20
 
20
 
21
     protected $table = 'account_subtypes';
21
     protected $table = 'account_subtypes';
22
 
22
 
35
         'type' => AccountType::class,
35
         'type' => AccountType::class,
36
     ];
36
     ];
37
 
37
 
38
-
39
     public function company(): BelongsTo
38
     public function company(): BelongsTo
40
     {
39
     {
41
         return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
40
         return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');

+ 1
- 2
app/Models/Banking/BankAccount.php Näytä tiedosto

2
 
2
 
3
 namespace App\Models\Banking;
3
 namespace App\Models\Banking;
4
 
4
 
5
-use App\Enums\BankAccountSubtype;
6
 use App\Enums\BankAccountType;
5
 use App\Enums\BankAccountType;
7
 use App\Models\Accounting\Account;
6
 use App\Models\Accounting\Account;
8
 use App\Traits\Blamable;
7
 use App\Traits\Blamable;
81
     protected function mask(): Attribute
80
     protected function mask(): Attribute
82
     {
81
     {
83
         return Attribute::get(static function (mixed $value, array $attributes): ?string {
82
         return Attribute::get(static function (mixed $value, array $attributes): ?string {
84
-            return $attributes['number'] ? '****' . substr($attributes['number'], -4) : null;
83
+            return $attributes['number'] ? '•••• ' . substr($attributes['number'], -4) : null;
85
         });
84
         });
86
     }
85
     }
87
 
86
 

+ 1
- 1
app/Models/Banking/ConnectedBankAccount.php Näytä tiedosto

62
     protected function maskedNumber(): Attribute
62
     protected function maskedNumber(): Attribute
63
     {
63
     {
64
         return Attribute::get(static function (mixed $value, array $attributes): ?string {
64
         return Attribute::get(static function (mixed $value, array $attributes): ?string {
65
-            return $attributes['mask'] ? '****' . $attributes['mask'] : null;
65
+            return $attributes['mask'] ? '•••• ' . substr($attributes['mask'], -4) : null;
66
         });
66
         });
67
     }
67
     }
68
 
68
 

+ 34
- 34
app/Observers/AccountObserver.php Näytä tiedosto

55
     public function created(Account $account): void
55
     public function created(Account $account): void
56
     {
56
     {
57
         //$account->histories()->create([
57
         //$account->histories()->create([
58
-           // 'company_id' => $account->company_id,
59
-          //  'account_id' => $account->id,
60
-           // 'type' => $account->type,
61
-          //  'name' => $account->name,
62
-          //  'number' => $account->number,
63
-           // 'currency_code' => $account->currency_code,
64
-         //   'opening_balance' => $account->opening_balance,
65
-         //   'balance' => $account->balance,
66
-         //   'exchange_rate' => $account->currency->rate,
67
-          //  'status' => AccountStatus::Open,
68
-          //  'actions' => ['account_created'],
69
-         //   'enabled' => $account->enabled,
70
-          //  'changed_by' => $account->created_by,
58
+        // 'company_id' => $account->company_id,
59
+        //  'account_id' => $account->id,
60
+        // 'type' => $account->type,
61
+        //  'name' => $account->name,
62
+        //  'number' => $account->number,
63
+        // 'currency_code' => $account->currency_code,
64
+        //   'opening_balance' => $account->opening_balance,
65
+        //   'balance' => $account->balance,
66
+        //   'exchange_rate' => $account->currency->rate,
67
+        //  'status' => AccountStatus::Open,
68
+        //  'actions' => ['account_created'],
69
+        //   'enabled' => $account->enabled,
70
+        //  'changed_by' => $account->created_by,
71
         //]);
71
         //]);
72
     }
72
     }
73
 
73
 
79
         //$actionsTaken = [];
79
         //$actionsTaken = [];
80
 
80
 
81
         //foreach ($this->actions as $action => $attribute) {
81
         //foreach ($this->actions as $action => $attribute) {
82
-            //if ($account->isDirty($attribute)) {
83
-                //$actionsTaken[] = $action;
84
-           // }
82
+        //if ($account->isDirty($attribute)) {
83
+        //$actionsTaken[] = $action;
84
+        // }
85
         //}
85
         //}
86
 
86
 
87
         //if (count($actionsTaken) > 0) {
87
         //if (count($actionsTaken) > 0) {
88
-            //$account->histories()->create([
89
-                //'company_id' => $account->company_id,
90
-               // 'account_id' => $account->id,
91
-               // 'type' => $account->getOriginal('type'),
92
-               // 'name' => $account->getOriginal('name'),
93
-               // 'number' => $account->getOriginal('number'),
94
-               // 'currency_code' => $account->getOriginal('currency_code'),
95
-               // 'opening_balance' => $account->getRawOriginal('opening_balance'),
96
-               // 'balance' => $account->getRawOriginal('balance'),
97
-               // 'exchange_rate' => $account->currency->getRawOriginal('rate'),
98
-               // 'status' => $account->getOriginal('status'),
99
-               // 'actions' => $actionsTaken,
100
-               // 'enabled' => $account->getOriginal('enabled'),
101
-               // 'changed_by' => $account->updated_by,
102
-            //]);
88
+        //$account->histories()->create([
89
+        //'company_id' => $account->company_id,
90
+        // 'account_id' => $account->id,
91
+        // 'type' => $account->getOriginal('type'),
92
+        // 'name' => $account->getOriginal('name'),
93
+        // 'number' => $account->getOriginal('number'),
94
+        // 'currency_code' => $account->getOriginal('currency_code'),
95
+        // 'opening_balance' => $account->getRawOriginal('opening_balance'),
96
+        // 'balance' => $account->getRawOriginal('balance'),
97
+        // 'exchange_rate' => $account->currency->getRawOriginal('rate'),
98
+        // 'status' => $account->getOriginal('status'),
99
+        // 'actions' => $actionsTaken,
100
+        // 'enabled' => $account->getOriginal('enabled'),
101
+        // 'changed_by' => $account->updated_by,
102
+        //]);
103
         //}
103
         //}
104
     }
104
     }
105
 
105
 
133
         $defaultChartType = AccountType::CurrentAsset;
133
         $defaultChartType = AccountType::CurrentAsset;
134
 
134
 
135
         //if ($account->type->isCreditCard()) {
135
         //if ($account->type->isCreditCard()) {
136
-            //$defaultChartCategory = ChartCategory::Liability;
137
-            //$defaultChartType = ChartType::CurrentLiability;
136
+        //$defaultChartCategory = ChartCategory::Liability;
137
+        //$defaultChartType = ChartType::CurrentLiability;
138
         //}
138
         //}
139
 
139
 
140
         $subTypeId = $this->getSubTypeId($account->company_id, $defaultChartType);
140
         $subTypeId = $this->getSubTypeId($account->company_id, $defaultChartType);
170
             ->where('type', $type)
170
             ->where('type', $type)
171
             ->first();
171
             ->first();
172
 
172
 
173
-        if (!$subType) {
173
+        if (! $subType) {
174
             $subType = AccountSubtype::where('company_id', $companyId)
174
             $subType = AccountSubtype::where('company_id', $companyId)
175
                 ->where('type', $type)
175
                 ->where('type', $type)
176
                 ->first();
176
                 ->first();

+ 1
- 3
app/Observers/BankAccountObserver.php Näytä tiedosto

2
 
2
 
3
 namespace App\Observers;
3
 namespace App\Observers;
4
 
4
 
5
-use App\Enums\Accounting\AccountCategory;
6
 use App\Enums\Accounting\AccountType;
5
 use App\Enums\Accounting\AccountType;
7
 use App\Models\Accounting\Account;
6
 use App\Models\Accounting\Account;
8
 use App\Models\Accounting\AccountSubtype;
7
 use App\Models\Accounting\AccountSubtype;
9
 use App\Models\Banking\BankAccount;
8
 use App\Models\Banking\BankAccount;
10
-use Illuminate\Support\Facades\Log;
11
 
9
 
12
 class BankAccountObserver
10
 class BankAccountObserver
13
 {
11
 {
37
             ->where('type', $type)
35
             ->where('type', $type)
38
             ->first();
36
             ->first();
39
 
37
 
40
-        if (!$subType) {
38
+        if (! $subType) {
41
             $subType = AccountSubtype::where('company_id', $companyId)
39
             $subType = AccountSubtype::where('company_id', $companyId)
42
                 ->where('type', $type)
40
                 ->where('type', $type)
43
                 ->first();
41
                 ->first();

+ 0
- 1
app/Providers/EventServiceProvider.php Näytä tiedosto

31
 use Illuminate\Auth\Events\Registered;
31
 use Illuminate\Auth\Events\Registered;
32
 use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
32
 use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
33
 use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
33
 use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
34
-use Wallo\FilamentCompanies\Events\CompanyCreated;
35
 
34
 
36
 class EventServiceProvider extends ServiceProvider
35
 class EventServiceProvider extends ServiceProvider
37
 {
36
 {

+ 9
- 9
app/Providers/MacroServiceProvider.php Näytä tiedosto

108
             $this
108
             $this
109
                 ->rules([
109
                 ->rules([
110
                     fn (Field $component): Closure => static function (string $attribute, $value, Closure $fail) use ($subtype, $component) {
110
                     fn (Field $component): Closure => static function (string $attribute, $value, Closure $fail) use ($subtype, $component) {
111
-                    $subtype = $component->evaluate($subtype);
112
-                    $chartSubtype = AccountSubtype::find($subtype);
113
-                    $type = $chartSubtype->type;
111
+                        $subtype = $component->evaluate($subtype);
112
+                        $chartSubtype = AccountSubtype::find($subtype);
113
+                        $type = $chartSubtype->type;
114
 
114
 
115
-                    if (!AccountCode::isValidCode($value, $type)) {
116
-                        $message = AccountCode::getMessage($type);
115
+                        if (! AccountCode::isValidCode($value, $type)) {
116
+                            $message = AccountCode::getMessage($type);
117
 
117
 
118
-                        $fail($message);
119
-                    }
120
-                },
121
-            ]);
118
+                            $fail($message);
119
+                        }
120
+                    },
121
+                ]);
122
 
122
 
123
             return $this;
123
             return $this;
124
         });
124
         });

+ 1
- 1
app/Services/PlaidService.php Näytä tiedosto

276
         return $this->sendRequest('institutions/get_by_id', $data);
276
         return $this->sendRequest('institutions/get_by_id', $data);
277
     }
277
     }
278
 
278
 
279
-    public function syncTransactions(string $access_token, string|null $cursor = null, int $count = 100, array $options = []): object
279
+    public function syncTransactions(string $access_token, ?string $cursor = null, int $count = 100, array $options = []): object
280
     {
280
     {
281
         $data = [
281
         $data = [
282
             'access_token' => $access_token,
282
             'access_token' => $access_token,

+ 4
- 2
app/Utilities/Plaid/AccountTypeMapper.php Näytä tiedosto

7
 
7
 
8
 class AccountTypeMapper
8
 class AccountTypeMapper
9
 {
9
 {
10
-    public static function mapToEnums(string $plaidType, string $plaidSubtype): array {
10
+    public static function mapToEnums(string $plaidType, string $plaidSubtype): array
11
+    {
11
         $mappedType = self::mapType($plaidType);
12
         $mappedType = self::mapType($plaidType);
12
         $mappedSubtype = self::mapSubtype($plaidType, $plaidSubtype);
13
         $mappedSubtype = self::mapSubtype($plaidType, $plaidSubtype);
13
 
14
 
17
         ];
18
         ];
18
     }
19
     }
19
 
20
 
20
-    private static function mapType(string $plaidType): BankAccountType {
21
+    private static function mapType(string $plaidType): BankAccountType
22
+    {
21
         return match ($plaidType) {
23
         return match ($plaidType) {
22
             'depository' => BankAccountType::Depository,
24
             'depository' => BankAccountType::Depository,
23
             'credit' => BankAccountType::Credit,
25
             'credit' => BankAccountType::Credit,

+ 22
- 22
composer.lock Näytä tiedosto

413
         },
413
         },
414
         {
414
         {
415
             "name": "aws/aws-sdk-php",
415
             "name": "aws/aws-sdk-php",
416
-            "version": "3.298.9",
416
+            "version": "3.299.1",
417
             "source": {
417
             "source": {
418
                 "type": "git",
418
                 "type": "git",
419
                 "url": "https://github.com/aws/aws-sdk-php.git",
419
                 "url": "https://github.com/aws/aws-sdk-php.git",
420
-                "reference": "db225c3a1c5dabfbb5071349cfb7e4c396c3d9ec"
420
+                "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457"
421
             },
421
             },
422
             "dist": {
422
             "dist": {
423
                 "type": "zip",
423
                 "type": "zip",
424
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/db225c3a1c5dabfbb5071349cfb7e4c396c3d9ec",
425
-                "reference": "db225c3a1c5dabfbb5071349cfb7e4c396c3d9ec",
424
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a0f87b8e8bfb9afd0ffd702fcda556b465eee457",
425
+                "reference": "a0f87b8e8bfb9afd0ffd702fcda556b465eee457",
426
                 "shasum": ""
426
                 "shasum": ""
427
             },
427
             },
428
             "require": {
428
             "require": {
502
             "support": {
502
             "support": {
503
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
503
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
504
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
504
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
505
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.298.9"
505
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.299.1"
506
             },
506
             },
507
-            "time": "2024-02-13T19:08:16+00:00"
507
+            "time": "2024-02-16T19:08:34+00:00"
508
         },
508
         },
509
         {
509
         {
510
             "name": "aws/aws-sdk-php-laravel",
510
             "name": "aws/aws-sdk-php-laravel",
1210
         },
1210
         },
1211
         {
1211
         {
1212
             "name": "doctrine/dbal",
1212
             "name": "doctrine/dbal",
1213
-            "version": "3.8.1",
1213
+            "version": "3.8.2",
1214
             "source": {
1214
             "source": {
1215
                 "type": "git",
1215
                 "type": "git",
1216
                 "url": "https://github.com/doctrine/dbal.git",
1216
                 "url": "https://github.com/doctrine/dbal.git",
1217
-                "reference": "c9ea252cdce4da324ede3d6c5913dd89f769afd2"
1217
+                "reference": "a19a1d05ca211f41089dffcc387733a6875196cb"
1218
             },
1218
             },
1219
             "dist": {
1219
             "dist": {
1220
                 "type": "zip",
1220
                 "type": "zip",
1221
-                "url": "https://api.github.com/repos/doctrine/dbal/zipball/c9ea252cdce4da324ede3d6c5913dd89f769afd2",
1222
-                "reference": "c9ea252cdce4da324ede3d6c5913dd89f769afd2",
1221
+                "url": "https://api.github.com/repos/doctrine/dbal/zipball/a19a1d05ca211f41089dffcc387733a6875196cb",
1222
+                "reference": "a19a1d05ca211f41089dffcc387733a6875196cb",
1223
                 "shasum": ""
1223
                 "shasum": ""
1224
             },
1224
             },
1225
             "require": {
1225
             "require": {
1303
             ],
1303
             ],
1304
             "support": {
1304
             "support": {
1305
                 "issues": "https://github.com/doctrine/dbal/issues",
1305
                 "issues": "https://github.com/doctrine/dbal/issues",
1306
-                "source": "https://github.com/doctrine/dbal/tree/3.8.1"
1306
+                "source": "https://github.com/doctrine/dbal/tree/3.8.2"
1307
             },
1307
             },
1308
             "funding": [
1308
             "funding": [
1309
                 {
1309
                 {
1319
                     "type": "tidelift"
1319
                     "type": "tidelift"
1320
                 }
1320
                 }
1321
             ],
1321
             ],
1322
-            "time": "2024-02-03T17:33:49+00:00"
1322
+            "time": "2024-02-12T18:36:36+00:00"
1323
         },
1323
         },
1324
         {
1324
         {
1325
             "name": "doctrine/deprecations",
1325
             "name": "doctrine/deprecations",
3220
         },
3220
         },
3221
         {
3221
         {
3222
             "name": "laravel/socialite",
3222
             "name": "laravel/socialite",
3223
-            "version": "v5.12.0",
3223
+            "version": "v5.12.1",
3224
             "source": {
3224
             "source": {
3225
                 "type": "git",
3225
                 "type": "git",
3226
                 "url": "https://github.com/laravel/socialite.git",
3226
                 "url": "https://github.com/laravel/socialite.git",
3227
-                "reference": "ffeeb2cdf723b4c88b25479968e2d3a61a83dbe5"
3227
+                "reference": "7dae1b072573809f32ab6dcf4aebb57c8b3e8acf"
3228
             },
3228
             },
3229
             "dist": {
3229
             "dist": {
3230
                 "type": "zip",
3230
                 "type": "zip",
3231
-                "url": "https://api.github.com/repos/laravel/socialite/zipball/ffeeb2cdf723b4c88b25479968e2d3a61a83dbe5",
3232
-                "reference": "ffeeb2cdf723b4c88b25479968e2d3a61a83dbe5",
3231
+                "url": "https://api.github.com/repos/laravel/socialite/zipball/7dae1b072573809f32ab6dcf4aebb57c8b3e8acf",
3232
+                "reference": "7dae1b072573809f32ab6dcf4aebb57c8b3e8acf",
3233
                 "shasum": ""
3233
                 "shasum": ""
3234
             },
3234
             },
3235
             "require": {
3235
             "require": {
3286
                 "issues": "https://github.com/laravel/socialite/issues",
3286
                 "issues": "https://github.com/laravel/socialite/issues",
3287
                 "source": "https://github.com/laravel/socialite"
3287
                 "source": "https://github.com/laravel/socialite"
3288
             },
3288
             },
3289
-            "time": "2024-02-11T18:29:55+00:00"
3289
+            "time": "2024-02-16T08:58:20+00:00"
3290
         },
3290
         },
3291
         {
3291
         {
3292
             "name": "laravel/tinker",
3292
             "name": "laravel/tinker",
4231
         },
4231
         },
4232
         {
4232
         {
4233
             "name": "matomo/device-detector",
4233
             "name": "matomo/device-detector",
4234
-            "version": "6.2.1",
4234
+            "version": "6.3.0",
4235
             "source": {
4235
             "source": {
4236
                 "type": "git",
4236
                 "type": "git",
4237
                 "url": "https://github.com/matomo-org/device-detector.git",
4237
                 "url": "https://github.com/matomo-org/device-detector.git",
4238
-                "reference": "19138b0c4b9ddf4ffd8e423d6af3764b7317cb0b"
4238
+                "reference": "35efad75b31f2596701834d19f097497909572a4"
4239
             },
4239
             },
4240
             "dist": {
4240
             "dist": {
4241
                 "type": "zip",
4241
                 "type": "zip",
4242
-                "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/19138b0c4b9ddf4ffd8e423d6af3764b7317cb0b",
4243
-                "reference": "19138b0c4b9ddf4ffd8e423d6af3764b7317cb0b",
4242
+                "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/35efad75b31f2596701834d19f097497909572a4",
4243
+                "reference": "35efad75b31f2596701834d19f097497909572a4",
4244
                 "shasum": ""
4244
                 "shasum": ""
4245
             },
4245
             },
4246
             "require": {
4246
             "require": {
4296
                 "source": "https://github.com/matomo-org/matomo",
4296
                 "source": "https://github.com/matomo-org/matomo",
4297
                 "wiki": "https://dev.matomo.org/"
4297
                 "wiki": "https://dev.matomo.org/"
4298
             },
4298
             },
4299
-            "time": "2024-01-05T09:03:21+00:00"
4299
+            "time": "2024-02-16T16:26:57+00:00"
4300
         },
4300
         },
4301
         {
4301
         {
4302
             "name": "monolog/monolog",
4302
             "name": "monolog/monolog",

+ 2
- 2
config/chart-of-accounts.php Näytä tiedosto

382
             ],
382
             ],
383
         ],
383
         ],
384
         'contra_expense' => [
384
         'contra_expense' => [
385
-             'Contra Expenses' => [
385
+            'Contra Expenses' => [
386
                 'description' => 'Expenses that are deducted from gross expenses to arrive at net expenses. This includes purchase discounts, returns, and allowances.',
386
                 'description' => 'Expenses that are deducted from gross expenses to arrive at net expenses. This includes purchase discounts, returns, and allowances.',
387
                 'multi_currency' => false,
387
                 'multi_currency' => false,
388
                 'base_code' => '5900',
388
                 'base_code' => '5900',
394
                         'description' => 'The amount of money deducted from purchases due to discounts offered by suppliers for early payment or other reasons.',
394
                         'description' => 'The amount of money deducted from purchases due to discounts offered by suppliers for early payment or other reasons.',
395
                     ],
395
                     ],
396
                 ],
396
                 ],
397
-             ],
397
+            ],
398
         ],
398
         ],
399
         'uncategorized_expense' => [
399
         'uncategorized_expense' => [
400
             'Uncategorized Expense' => [
400
             'Uncategorized Expense' => [

+ 159
- 0
config/livewire.php Näytä tiedosto

1
+<?php
2
+
3
+return [
4
+
5
+    /*
6
+    |---------------------------------------------------------------------------
7
+    | Class Namespace
8
+    |---------------------------------------------------------------------------
9
+    |
10
+    | This value sets the root class namespace for Livewire component classes in
11
+    | your application. This value will change where component auto-discovery
12
+    | finds components. It's also referenced by the file creation commands.
13
+    |
14
+    */
15
+
16
+    'class_namespace' => 'App\\Livewire',
17
+
18
+    /*
19
+    |---------------------------------------------------------------------------
20
+    | View Path
21
+    |---------------------------------------------------------------------------
22
+    |
23
+    | This value is used to specify where Livewire component Blade templates are
24
+    | stored when running file creation commands like `artisan make:livewire`.
25
+    | It is also used if you choose to omit a component's render() method.
26
+    |
27
+    */
28
+
29
+    'view_path' => resource_path('views/livewire'),
30
+
31
+    /*
32
+    |---------------------------------------------------------------------------
33
+    | Layout
34
+    |---------------------------------------------------------------------------
35
+    | The view that will be used as the layout when rendering a single component
36
+    | as an entire page via `Route::get('/post/create', CreatePost::class);`.
37
+    | In this case, the view returned by CreatePost will render into $slot.
38
+    |
39
+    */
40
+
41
+    'layout' => 'components.layouts.app',
42
+
43
+    /*
44
+    |---------------------------------------------------------------------------
45
+    | Lazy Loading Placeholder
46
+    |---------------------------------------------------------------------------
47
+    | Livewire allows you to lazy load components that would otherwise slow down
48
+    | the initial page load. Every component can have a custom placeholder or
49
+    | you can define the default placeholder view for all components below.
50
+    |
51
+    */
52
+
53
+    'lazy_placeholder' => null,
54
+
55
+    /*
56
+    |---------------------------------------------------------------------------
57
+    | Temporary File Uploads
58
+    |---------------------------------------------------------------------------
59
+    |
60
+    | Livewire handles file uploads by storing uploads in a temporary directory
61
+    | before the file is stored permanently. All file uploads are directed to
62
+    | a global endpoint for temporary storage. You may configure this below:
63
+    |
64
+    */
65
+
66
+    'temporary_file_upload' => [
67
+        'disk' => null,        // Example: 'local', 's3'              | Default: 'default'
68
+        'rules' => null,       // Example: ['file', 'mimes:png,jpg']  | Default: ['required', 'file', 'max:12288'] (12MB)
69
+        'directory' => null,   // Example: 'tmp'                      | Default: 'livewire-tmp'
70
+        'middleware' => null,  // Example: 'throttle:5,1'             | Default: 'throttle:60,1'
71
+        'preview_mimes' => [   // Supported file types for temporary pre-signed file URLs...
72
+            'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
73
+            'mov', 'avi', 'wmv', 'mp3', 'm4a',
74
+            'jpg', 'jpeg', 'mpga', 'webp', 'wma',
75
+        ],
76
+        'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
77
+    ],
78
+
79
+    /*
80
+    |---------------------------------------------------------------------------
81
+    | Render On Redirect
82
+    |---------------------------------------------------------------------------
83
+    |
84
+    | This value determines if Livewire will run a component's `render()` method
85
+    | after a redirect has been triggered using something like `redirect(...)`
86
+    | Setting this to true will render the view once more before redirecting
87
+    |
88
+    */
89
+
90
+    'render_on_redirect' => false,
91
+
92
+    /*
93
+    |---------------------------------------------------------------------------
94
+    | Eloquent Model Binding
95
+    |---------------------------------------------------------------------------
96
+    |
97
+    | Previous versions of Livewire supported binding directly to eloquent model
98
+    | properties using wire:model by default. However, this behavior has been
99
+    | deemed too "magical" and has therefore been put under a feature flag.
100
+    |
101
+    */
102
+
103
+    'legacy_model_binding' => false,
104
+
105
+    /*
106
+    |---------------------------------------------------------------------------
107
+    | Auto-inject Frontend Assets
108
+    |---------------------------------------------------------------------------
109
+    |
110
+    | By default, Livewire automatically injects its JavaScript and CSS into the
111
+    | <head> and <body> of pages containing Livewire components. By disabling
112
+    | this behavior, you need to use @livewireStyles and @livewireScripts.
113
+    |
114
+    */
115
+
116
+    'inject_assets' => true,
117
+
118
+    /*
119
+    |---------------------------------------------------------------------------
120
+    | Navigate (SPA mode)
121
+    |---------------------------------------------------------------------------
122
+    |
123
+    | By adding `wire:navigate` to links in your Livewire application, Livewire
124
+    | will prevent the default link handling and instead request those pages
125
+    | via AJAX, creating an SPA-like effect. Configure this behavior here.
126
+    |
127
+    */
128
+
129
+    'navigate' => [
130
+        'show_progress_bar' => true,
131
+        'progress_bar_color' => '#2299dd',
132
+    ],
133
+
134
+    /*
135
+    |---------------------------------------------------------------------------
136
+    | HTML Morph Markers
137
+    |---------------------------------------------------------------------------
138
+    |
139
+    | Livewire intelligently "morphs" existing HTML into the newly rendered HTML
140
+    | after each update. To make this process more reliable, Livewire injects
141
+    | "markers" into the rendered Blade surrounding @if, @class & @foreach.
142
+    |
143
+    */
144
+
145
+    'inject_morph_markers' => true,
146
+
147
+    /*
148
+    |---------------------------------------------------------------------------
149
+    | Pagination Theme
150
+    |---------------------------------------------------------------------------
151
+    |
152
+    | When enabling Livewire's pagination feature by using the `WithPagination`
153
+    | trait, Livewire will use Tailwind templates to render pagination views
154
+    | on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
155
+    |
156
+    */
157
+
158
+    'pagination_theme' => 'tailwind',
159
+];

+ 1
- 1
config/services.php Näytä tiedosto

46
         'client_id' => env('PLAID_CLIENT_ID'),
46
         'client_id' => env('PLAID_CLIENT_ID'),
47
         'client_secret' => env('PLAID_CLIENT_SECRET'),
47
         'client_secret' => env('PLAID_CLIENT_SECRET'),
48
         'environment' => env('PLAID_ENVIRONMENT', 'sandbox'),
48
         'environment' => env('PLAID_ENVIRONMENT', 'sandbox'),
49
-    ]
49
+    ],
50
 ];
50
 ];

+ 0
- 1
database/factories/Accounting/AccountFactory.php Näytä tiedosto

10
  */
10
  */
11
 class AccountFactory extends Factory
11
 class AccountFactory extends Factory
12
 {
12
 {
13
-
14
     /**
13
     /**
15
      * The name of the factory's corresponding model.
14
      * The name of the factory's corresponding model.
16
      */
15
      */

+ 17
- 14
package-lock.json Näytä tiedosto

411
             }
411
             }
412
         },
412
         },
413
         "node_modules/@jridgewell/resolve-uri": {
413
         "node_modules/@jridgewell/resolve-uri": {
414
-            "version": "3.1.1",
415
-            "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
416
-            "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
414
+            "version": "3.1.2",
415
+            "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
416
+            "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
417
             "dev": true,
417
             "dev": true,
418
             "engines": {
418
             "engines": {
419
                 "node": ">=6.0.0"
419
                 "node": ">=6.0.0"
656
             }
656
             }
657
         },
657
         },
658
         "node_modules/browserslist": {
658
         "node_modules/browserslist": {
659
-            "version": "4.22.3",
660
-            "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz",
661
-            "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==",
659
+            "version": "4.23.0",
660
+            "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
661
+            "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
662
             "dev": true,
662
             "dev": true,
663
             "funding": [
663
             "funding": [
664
                 {
664
                 {
675
                 }
675
                 }
676
             ],
676
             ],
677
             "dependencies": {
677
             "dependencies": {
678
-                "caniuse-lite": "^1.0.30001580",
679
-                "electron-to-chromium": "^1.4.648",
678
+                "caniuse-lite": "^1.0.30001587",
679
+                "electron-to-chromium": "^1.4.668",
680
                 "node-releases": "^2.0.14",
680
                 "node-releases": "^2.0.14",
681
                 "update-browserslist-db": "^1.0.13"
681
                 "update-browserslist-db": "^1.0.13"
682
             },
682
             },
845
             "dev": true
845
             "dev": true
846
         },
846
         },
847
         "node_modules/electron-to-chromium": {
847
         "node_modules/electron-to-chromium": {
848
-            "version": "1.4.668",
849
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.668.tgz",
850
-            "integrity": "sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ==",
848
+            "version": "1.4.673",
849
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.673.tgz",
850
+            "integrity": "sha512-zjqzx4N7xGdl5468G+vcgzDhaHkaYgVcf9MqgexcTqsl2UHSCmOj/Bi3HAprg4BZCpC7HyD8a6nZl6QAZf72gw==",
851
             "dev": true
851
             "dev": true
852
         },
852
         },
853
         "node_modules/emoji-regex": {
853
         "node_modules/emoji-regex": {
1551
             }
1551
             }
1552
         },
1552
         },
1553
         "node_modules/postcss-load-config/node_modules/lilconfig": {
1553
         "node_modules/postcss-load-config/node_modules/lilconfig": {
1554
-            "version": "3.0.0",
1555
-            "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz",
1556
-            "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==",
1554
+            "version": "3.1.0",
1555
+            "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.0.tgz",
1556
+            "integrity": "sha512-p3cz0JV5vw/XeouBU3Ldnp+ZkBjE+n8ydJ4mcwBrOiXXPqNlrzGBqWs9X4MWF7f+iKUBu794Y8Hh8yawiJbCjw==",
1557
             "dev": true,
1557
             "dev": true,
1558
             "engines": {
1558
             "engines": {
1559
                 "node": ">=14"
1559
                 "node": ">=14"
1560
+            },
1561
+            "funding": {
1562
+                "url": "https://github.com/sponsors/antonk52"
1560
             }
1563
             }
1561
         },
1564
         },
1562
         "node_modules/postcss-nested": {
1565
         "node_modules/postcss-nested": {

+ 6
- 0
resources/views/components/actions/delete-bank-connection-modal.blade.php Näytä tiedosto

1
+<span>Are you sure you want to delete your {{ $institution->name }} connection? Deleting this bank connection will remove the following connected accounts:</span>
2
+<ul class="list-disc list-inside p-2">
3
+    @foreach($institution->connectedBankAccounts as $connectedBankAccount)
4
+        <li>{{ $connectedBankAccount->name }}</li>
5
+    @endforeach
6
+</ul>

+ 18
- 0
resources/views/components/actions/transaction-import-modal.blade.php Näytä tiedosto

1
+<div class="rounded-lg bg-primary-300/10 shadow-sm ring-1 ring-gray-950/10 dark:ring-white/20 overflow-hidden">
2
+    <div class="flex items-center p-4 gap-x-2">
3
+        @if($connectedBankAccount->institution->logo_url)
4
+            <img src="{{ $connectedBankAccount->institution->logo_url }}" alt="{{ $connectedBankAccount->institution->name }}" class="h-10">
5
+        @else
6
+            <div class="flex-shrink-0 bg-platinum p-2 rounded-full dark:bg-gray-500/20">
7
+                <x-filament::icon
8
+                    icon="heroicon-o-building-library"
9
+                    class="h-6 w-6 text-gray-500 dark:text-gray-400"
10
+                />
11
+            </div>
12
+        @endif
13
+        <div>
14
+            <p class="text-sm font-medium leading-6 text-gray-900 dark:text-white">{{ $connectedBankAccount->institution->name }}</p>
15
+            <p class="text-sm leading-6 text-gray-600 dark:text-gray-200">{{ ucwords($connectedBankAccount->subtype) }} {{ $connectedBankAccount->masked_number }}</p>
16
+        </div>
17
+    </div>
18
+</div>

+ 35
- 27
resources/views/livewire/company/service/connected-account/list-institutions.blade.php Näytä tiedosto

2
     <div class="grid grid-cols-1 gap-4">
2
     <div class="grid grid-cols-1 gap-4">
3
         @forelse($this->connectedInstitutions as $institution) {{-- Group connected accounts by institution --}}
3
         @forelse($this->connectedInstitutions as $institution) {{-- Group connected accounts by institution --}}
4
             <section class="connected-account-section overflow-hidden rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
4
             <section class="connected-account-section overflow-hidden rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
5
-                <header class="connected-account-header bg-primary-300/10 flex flex-col gap-3 overflow-hidden sm:flex-row sm:items-center px-6 py-4">
5
+                <header class="connected-account-header bg-primary-300/10 px-6 py-4 flex flex-col sm:flex-row sm:items-center gap-3">
6
                     @if($institution->logo_url === null)
6
                     @if($institution->logo_url === null)
7
                         <div class="flex-shrink-0 bg-platinum p-2 rounded-full dark:bg-gray-500/20">
7
                         <div class="flex-shrink-0 bg-platinum p-2 rounded-full dark:bg-gray-500/20">
8
                             <x-filament::icon
8
                             <x-filament::icon
11
                             />
11
                             />
12
                         </div>
12
                         </div>
13
                     @else
13
                     @else
14
-                        <img src="{{ $institution->logo_url }}" alt="{{ $institution->name }}" class="h-10">
14
+                        <img src="{{ $institution->logo_url }}" alt="{{ $institution->name }}" class="h-10 object-contain object-left">
15
                     @endif
15
                     @endif
16
 
16
 
17
-                    <div class="grid flex-1 gap-y-1">
18
-                        <h3 class="connected-account-section-header-heading text-lg font-semibold leading-[1.4] text-gray-950 dark:text-white">
17
+                    <div class="flex-auto">
18
+                        <h3 class="connected-account-section-header-heading text-lg font-semibold leading-6 text-gray-950 dark:text-white">
19
                             {{ $institution->name }}
19
                             {{ $institution->name }}
20
                         </h3>
20
                         </h3>
21
 
21
 
22
                         {{-- Eventually we will need to assert last updated time based on when the last time one of the accounts for the institution last has transactions imported --}}
22
                         {{-- Eventually we will need to assert last updated time based on when the last time one of the accounts for the institution last has transactions imported --}}
23
-                        <p class="connected-account-section-header-description text-sm text-gray-500 dark:text-gray-400">
23
+                        <p class="connected-account-section-header-description text-sm leading-6 text-gray-500 dark:text-gray-400">
24
                             {{ __('Last Updated') }} {{ $institution->updated_at->diffForHumans() }}
24
                             {{ __('Last Updated') }} {{ $institution->updated_at->diffForHumans() }}
25
                         </p>
25
                         </p>
26
                     </div>
26
                     </div>
29
                 </header>
29
                 </header>
30
 
30
 
31
                 @foreach($institution->connectedBankAccounts as $connectedBankAccount)
31
                 @foreach($institution->connectedBankAccounts as $connectedBankAccount)
32
-                    <div class="border-t-2 border-gray-200 dark:border-white/10">
33
-                        <div class="p-6">
34
-                            <div class="flex justify-between items-start">
35
-                                <div class="flex flex-col space-y-2">
36
-                                    <span class="account-name text-base font-medium text-gray-900 dark:text-white">{{ $connectedBankAccount->name }}</span>
37
-                                    <span class="account-type text-sm text-gray-600 dark:text-gray-200">{{  ucwords($connectedBankAccount->subtype) }} {{ $connectedBankAccount->masked_number }}</span>
38
-                                </div>
39
-
40
-                                @if($connectedBankAccount->bankAccount?->account)
41
-                                    <div class="account-balance flex justify-between text-base text-gray-700 dark:text-gray-200 space-x-1">
42
-                                        <strong>@money($connectedBankAccount->bankAccount->account->ending_balance, $connectedBankAccount->bankAccount->account->currency_code, true)</strong>
43
-                                        <p>{{ $connectedBankAccount->bankAccount->account->currency_code }}</p>
44
-                                    </div>
45
-                                @endif
32
+                    <div class="border-t-2 border-gray-200 dark:border-white/10 px-6 py-4">
33
+                        <div class="flex flex-col sm:flex-row items-start gap-y-2">
34
+                            <div class="grid flex-auto gap-y-2">
35
+                                <span class="account-name text-base font-medium leading-6 text-gray-900 dark:text-white">{{ $connectedBankAccount->name }}</span>
36
+                                <span class="account-type text-sm leading-6 text-gray-600 dark:text-gray-200">{{  ucwords($connectedBankAccount->subtype) }} {{ $connectedBankAccount->masked_number }}</span>
46
                             </div>
37
                             </div>
47
 
38
 
48
-                            {{-- Add the toggle button to import transactions or not --}}
49
-                            <div class="mt-4 flex items-center space-x-2">
50
-                                @if($connectedBankAccount->import_transactions)
51
-                                    {{ ($this->stopImportingTransactions)(['connectedBankAccount' => $connectedBankAccount->id]) }}
52
-                                @else
53
-                                    {{ ($this->startImportingTransactions)(['connectedBankAccount' => $connectedBankAccount->id]) }}
54
-                                @endif
55
-                            </div>
39
+                            @if($connectedBankAccount->bankAccount?->account)
40
+                                <div class="account-balance flex text-base leading-6 text-gray-700 dark:text-gray-200 space-x-1">
41
+                                    <strong>@money($connectedBankAccount->bankAccount->account->ending_balance, $connectedBankAccount->bankAccount->account->currency_code, true)</strong>
42
+                                    <p>{{ $connectedBankAccount->bankAccount->account->currency_code }}</p>
43
+                                </div>
44
+                            @endif
45
+                        </div>
46
+
47
+                        {{-- Add the toggle button to import transactions or not --}}
48
+                        <div class="mt-4">
49
+                            @if($connectedBankAccount->import_transactions)
50
+                                {{ ($this->stopImportingTransactions)(['connectedBankAccount' => $connectedBankAccount->id]) }}
51
+                            @else
52
+                                {{ ($this->startImportingTransactions)(['connectedBankAccount' => $connectedBankAccount->id]) }}
53
+                            @endif
56
                         </div>
54
                         </div>
57
                     </div>
55
                     </div>
58
                 @endforeach
56
                 @endforeach
96
     {{-- Initialize Plaid Link --}}
94
     {{-- Initialize Plaid Link --}}
97
     @script
95
     @script
98
     <script>
96
     <script>
97
+        let data = Alpine.reactive({ windowWidth: 'max-w-2xl' });
98
+
99
+        Alpine.effect(() => {
100
+            $wire.$set('modalWidth', data.windowWidth);
101
+        });
102
+
103
+        window.addEventListener('resize', () => {
104
+            data.windowWidth = window.innerWidth <= 480 ? 'screen' : 'max-w-2xl';
105
+        });
106
+
99
         $wire.on('initializeLink', token => {
107
         $wire.on('initializeLink', token => {
100
             const handler = Plaid.create({
108
             const handler = Plaid.create({
101
                 token: token,
109
                 token: token,

Loading…
Peruuta
Tallenna