diff --git a/app/Http/Controllers/PortfolioController.php b/app/Http/Controllers/PortfolioController.php index 3564f4e..62ce2c4 100644 --- a/app/Http/Controllers/PortfolioController.php +++ b/app/Http/Controllers/PortfolioController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers; use App\Models\Holding; use App\Models\Portfolio; -use App\Models\DailyChange; +use Illuminate\Http\Request; class PortfolioController extends Controller { @@ -20,8 +20,12 @@ class PortfolioController extends Controller /** * Display the specified resource. */ - public function show(Portfolio $portfolio) + public function show(Request $request, Portfolio $portfolio) { + if ($request->user()->cannot('readOnly', $portfolio)) { + abort(403); + } + $portfolio->load(['transactions', 'holdings']); // get portfolio metrics diff --git a/app/Models/Portfolio.php b/app/Models/Portfolio.php index 1a931e3..89f2273 100644 --- a/app/Models/Portfolio.php +++ b/app/Models/Portfolio.php @@ -69,6 +69,17 @@ class Portfolio extends Model }); } + public function scopeFullAccess() + { + return $this->whereHas('users', function ($query) { + $query->where('user_id', auth()->user()->id) + ->where(function ($query) { + $query->where('full_access', true) + ->orWhere('owner', true); + }); + }); + } + public function scopeWithoutWishlists() { return $this->where(['wishlist' => false]); diff --git a/lang/en.json b/lang/en.json index 0a746ad..287c401 100644 --- a/lang/en.json +++ b/lang/en.json @@ -125,7 +125,7 @@ "Dividends": "Dividends", "Holding Options": "Holding Options", "Holding options saved": "Holding options saved", - "Reinvest dividends": "Reinvest dividends", + "Reinvest Dividends": "Reinvest Dividends", "Automatically generate buy transactions for any dividends earned": "Automatically generate buy transactions for any dividends earned", "Split": "Split", "Splits": "Splits", @@ -348,9 +348,11 @@ "Updated user's access permission to portfolio": "Updated user's access permission to portfolio", "Removed user's access to portfolio": "Removed user's access to portfolio", "Shared portfolio with user": "Shared portfolio with user", - "Share Portfolio": "Share portfolio", + "Share Portfolio": "Share Portfolio", "Type an email address to share portfolio": "Type an email address to share portfolio", "Grant full access": "Grant full access", "Allow this user to manage portfolio details and create or update transactions": "Allow this user to manage portfolio details and create or update transactions", - "Share": "Share" + "Share": "Share", + "Remove Access": "Remove Access", + "By removing this person's access, they will no longer be able to view this portfolio. They will lose access immediately.": "By removing this person's access, they will no longer be able to view this portfolio. They will lose access immediately." } \ No newline at end of file diff --git a/lang/es.json b/lang/es.json index 01d2cf0..1696bc7 100644 --- a/lang/es.json +++ b/lang/es.json @@ -125,7 +125,7 @@ "Dividends": "Dividendos", "Holding Options": "Opciones de Participaciones", "Holding options saved": "Opciones de participaciones guardadas", - "Reinvest dividends": "Reinvertir dividendos", + "Reinvest Dividends": "Reinvertir Dividendos", "Automatically generate buy transactions for any dividends earned": "Genere automáticamente transacciones de compra para cualquier dividendo obtenido", "Split": "Division", "Splits": "Divisiones", @@ -352,5 +352,7 @@ "Type an email address to share portfolio": "Escribe una dirección de correo electrónico para compartir portafolio", "Grant full access": "Otorgar acceso completo", "Allow this user to manage portfolio details and create or update transactions": "Permitir a este usuario administrar detalles de portafolio y crear o actualizar transacciones", - "Share": "Compartir" + "Share": "Compartir", + "Remove Access": "Eliminar acceso", + "By removing this person's access, they will no longer be able to view this portfolio. They will lose access immediately.": "Al eliminar el acceso de esta persona, ya no podrá ver este portafolio. Perderán el acceso inmediatamente." } \ No newline at end of file diff --git a/resources/views/components/confirmation-modal.blade.php b/resources/views/components/confirmation-modal.blade.php index e466d2e..1f599da 100644 --- a/resources/views/components/confirmation-modal.blade.php +++ b/resources/views/components/confirmation-modal.blade.php @@ -1,7 +1,7 @@ @props(['id' => null, 'maxWidth' => null]) - -
+ +
@@ -21,9 +21,7 @@
-
+
{{ $footer }}
- - - + diff --git a/resources/views/components/dialog-modal.blade.php b/resources/views/components/dialog-modal.blade.php index d082615..d901537 100644 --- a/resources/views/components/dialog-modal.blade.php +++ b/resources/views/components/dialog-modal.blade.php @@ -1,7 +1,7 @@ @props(['id' => null, 'maxWidth' => null]) - -
+ +
{{ $title }}
@@ -11,7 +11,7 @@
-
+
{{ $footer }}
- + diff --git a/resources/views/components/ib-modal.blade.php b/resources/views/components/ib-alpine-modal.blade.php similarity index 89% rename from resources/views/components/ib-modal.blade.php rename to resources/views/components/ib-alpine-modal.blade.php index 1981eb5..ea9e929 100644 --- a/resources/views/components/ib-modal.blade.php +++ b/resources/views/components/ib-alpine-modal.blade.php @@ -3,10 +3,11 @@ 'showClose' => true, 'closeOnEscape' => true, 'title' => null, - 'subtitle' => null + 'subtitle' => null, + 'persistent' => false ]) -
-
\ No newline at end of file + \ No newline at end of file diff --git a/resources/views/components/ib-drawer.blade.php b/resources/views/components/ib-drawer.blade.php index 4b58853..45b3399 100644 --- a/resources/views/components/ib-drawer.blade.php +++ b/resources/views/components/ib-drawer.blade.php @@ -22,9 +22,8 @@
- merge(['class' => 'min-h-screen w-5/6 xl:w-3/5 rounded-none px-8 transition']) }} + merge(['class' => 'min-h-screen w-full md:w-3/4 xl:w-3/5 rounded-none px-8 transition']) }} > @if($title) diff --git a/resources/views/components/ib-livewire-modal.blade.php b/resources/views/components/ib-livewire-modal.blade.php new file mode 100644 index 0000000..496ed14 --- /dev/null +++ b/resources/views/components/ib-livewire-modal.blade.php @@ -0,0 +1,46 @@ +@props([ + 'showClose' => true, + 'closeOnEscape' => true, + 'title' => null, + 'subtitle' => null, + 'persistent' => false +]) + +except('wire:model')->class(["modal"]) }} + x-data="{open: @entangle($attributes->wire('model')).live }" + :class="{'modal-open !animate-none': open}" + :open="open" + @if($closeOnEscape) + @keydown.escape.window = "$wire.{{ $attributes->wire('model')->value() }} = false" + @endif +> + merge(['class' => 'modal-box relative transform overflow-hidden rounded-md ext-left shadow-xl w-full sm:w-2/3 lg:w-1/3 m-2 sm:m-0']) }} + > + @if ($showClose) + + @endif + + {{ $slot }} + + + + + diff --git a/resources/views/holding/show.blade.php b/resources/views/holding/show.blade.php index 308c9c3..857755d 100644 --- a/resources/views/holding/show.blade.php +++ b/resources/views/holding/show.blade.php @@ -1,7 +1,7 @@
- @@ -10,9 +10,9 @@ 'symbol' => $holding->market_data->symbol, ]) - + - @@ -20,7 +20,7 @@ 'holding' => $holding ]) - + diff --git a/resources/views/livewire/holding-options-form.blade.php b/resources/views/livewire/holding-options-form.blade.php index 56c89e2..d923c51 100644 --- a/resources/views/livewire/holding-options-form.blade.php +++ b/resources/views/livewire/holding-options-form.blade.php @@ -44,7 +44,7 @@ new class extends Component { {{-- col-span-3 --}} authorize('fullAccess', $this->portfolio); - $portfolio = (new Portfolio())->fill($this->validate()); $portfolio->save(); @@ -66,15 +64,18 @@ new class extends Component { } }; ?> -
- +
+ + + @if (isset($this->portfolio)) @livewire('share-portfolio-form', ['portfolio' => $portfolio]) + @endif - + {{ __('Treat this portfolio as a "wishlist" (holdings will be excluded from realized gains, unrealized gains, and dividends)') }} diff --git a/resources/views/livewire/manage-transaction-form.blade.php b/resources/views/livewire/manage-transaction-form.blade.php index c034efb..51eda71 100644 --- a/resources/views/livewire/manage-transaction-form.blade.php +++ b/resources/views/livewire/manage-transaction-form.blade.php @@ -116,11 +116,10 @@ new class extends Component { label="{{ __('Portfolio') }}" wire:model="portfolio_id" required - :options="auth()->user()->portfolios" + :options="auth()->user()->portfolios()->fullAccess()->get()" option-label="title" placeholder="Select a portfolio" /> - @endif diff --git a/resources/views/livewire/share-portfolio-form.blade.php b/resources/views/livewire/share-portfolio-form.blade.php index de57436..2124040 100644 --- a/resources/views/livewire/share-portfolio-form.blade.php +++ b/resources/views/livewire/share-portfolio-form.blade.php @@ -21,6 +21,8 @@ new class extends Component { public int $fullAccess = 0; public array $permissions; + public bool $confirmingAccessDeletion = false; + public ?string $deletingAccessFor = null; // methods public function mount() @@ -57,10 +59,17 @@ new class extends Component { $this->success(__('Updated user\'s access permission to portfolio')); } - public function deleteUser(string $userId) + public function deleteUser(string $userId, bool $confirmed = false) { $this->authorize('fullAccess', $this->portfolio); + if (!$confirmed) { + $this->deletingAccessFor = $userId; + $this->confirmingAccessDeletion = true; + + return; + } + unset($this->permissions[$userId]); $this->portfolio->users()->sync($this->permissions); @@ -68,6 +77,10 @@ new class extends Component { $this->portfolio->refresh(); $this->success(__('Removed user\'s access to portfolio')); + + // reset + $this->confirmingAccessDeletion = false; + $this->deletingAccessFor = null; } public function addUser() @@ -100,18 +113,13 @@ new class extends Component { }; ?>
- @if ($this->portfolio) -
- @php - $owner = collect($this->portfolio?->users)->where('pivot.owner', 1)->first() ?? auth()->user(); - @endphp - {{ $owner->name }} + {{ $portfolio->owner->name }} - @if (auth()->user()->id == $owner->id) + @if (auth()->user()->id == $portfolio->owner->id) ({{ __('you') }}) @endif @@ -148,6 +156,7 @@ new class extends Component { :options="[['id' => 0, 'name' => __('Read only')], ['id' => 1, 'name' => __('Full access')]]" wire:model.live.number="permissions.{{ $user->id }}.full_access" /> + @if($user->id != auth()->user()->id) + @endif @endforeach - + + {{ __('Remove Access') }} + + + + {{ __('By removing this person\'s access, they will no longer be able to view this portfolio. They will lose access immediately.') }} + + + + + {{ __('Cancel') }} + + + + {{ __('Remove Access') }} + + + + +
@@ -172,6 +202,7 @@ new class extends Component { icon="o-envelope" placeholder="{{ __('Type an email address to share portfolio') }}" wire:model="emailAddress" + required /> - + - {{ __('Add people') }} + {{ __('Add People') }}
- @endif
\ No newline at end of file diff --git a/resources/views/livewire/transactions-list.blade.php b/resources/views/livewire/transactions-list.blade.php index e3f9ce5..15030e0 100644 --- a/resources/views/livewire/transactions-list.blade.php +++ b/resources/views/livewire/transactions-list.blade.php @@ -89,7 +89,7 @@ new class extends Component { @endforeach - @@ -98,5 +98,5 @@ new class extends Component { 'transaction' => $editingTransaction, ], key($editingTransaction->id ?? 'new')) - +
\ No newline at end of file diff --git a/resources/views/livewire/transactions-table.blade.php b/resources/views/livewire/transactions-table.blade.php index ebb039c..ba4dd38 100644 --- a/resources/views/livewire/transactions-table.blade.php +++ b/resources/views/livewire/transactions-table.blade.php @@ -112,7 +112,7 @@ new class extends Component { @endscope - @@ -120,5 +120,5 @@ new class extends Component { 'transaction' => $editingTransaction, ], key($editingTransaction->id ?? 'new')) - +
\ No newline at end of file diff --git a/resources/views/portfolio/show.blade.php b/resources/views/portfolio/show.blade.php index 2f6fe31..eeb9274 100644 --- a/resources/views/portfolio/show.blade.php +++ b/resources/views/portfolio/show.blade.php @@ -1,7 +1,7 @@
- @@ -9,7 +9,7 @@ 'portfolio' => $portfolio, ]) - +
- @livewire('manage-transaction-form') - +