Add group creation and show current groups
This commit is contained in:
419
resources/views/components/groups/⚡create.blade.php
Normal file
419
resources/views/components/groups/⚡create.blade.php
Normal file
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Crew;
|
||||
use App\Models\Image;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
|
||||
new class extends Component
|
||||
{
|
||||
use WithFileUploads;
|
||||
|
||||
public bool $isOpen = false;
|
||||
|
||||
public string $name = '';
|
||||
public string $description = '';
|
||||
|
||||
// Avatar state
|
||||
public bool $avatarModalOpen = false;
|
||||
public string $avatarTab = 'icon'; // icon | photo
|
||||
public string $iconSearch = '';
|
||||
public ?string $avatarIcon = null;
|
||||
|
||||
/** @var \Livewire\Features\SupportFileUploads\TemporaryUploadedFile|null */
|
||||
public $avatarPhoto = null;
|
||||
|
||||
/**
|
||||
* Icon list using your installed Blade icon packs.
|
||||
* Store the component string in DB (crews.avatar_icon).
|
||||
*/
|
||||
public array $icons = [
|
||||
['component' => 'phosphor-mountains', 'label' => 'Mountains'],
|
||||
['component' => 'phosphor-compass', 'label' => 'Compass'],
|
||||
['component' => 'phosphor-tent', 'label' => 'Tent'],
|
||||
['component' => 'phosphor-map-trifold', 'label' => 'Map'],
|
||||
['component' => 'phosphor-footprints', 'label' => 'Footprints'],
|
||||
['component' => 'phosphor-fire', 'label' => 'Fire'],
|
||||
['component' => 'phosphor-star', 'label' => 'Star'],
|
||||
['component' => 'phosphor-flag', 'label' => 'Flag'],
|
||||
['component' => 'phosphor-trophy', 'label' => 'Trophy'],
|
||||
['component' => 'phosphor-target', 'label' => 'Target'],
|
||||
['component' => 'solar-sun-linear', 'label' => 'Sun'],
|
||||
['component' => 'solar-moon-linear', 'label' => 'Moon'],
|
||||
['component' => 'bi-heart', 'label' => 'Heart'],
|
||||
];
|
||||
|
||||
public function openModal(): void
|
||||
{
|
||||
$this->resetValidation();
|
||||
$this->isOpen = true;
|
||||
}
|
||||
|
||||
public function closeModal(): void
|
||||
{
|
||||
$this->isOpen = false;
|
||||
$this->avatarModalOpen = false;
|
||||
}
|
||||
|
||||
public function openAvatarModal(): void
|
||||
{
|
||||
$this->resetValidation();
|
||||
$this->avatarModalOpen = true;
|
||||
}
|
||||
|
||||
public function closeAvatarModal(): void
|
||||
{
|
||||
$this->avatarModalOpen = false;
|
||||
}
|
||||
|
||||
public function setAvatarTab(string $tab): void
|
||||
{
|
||||
if (!in_array($tab, ['icon', 'photo'], true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->avatarTab = $tab;
|
||||
$this->resetValidation();
|
||||
}
|
||||
|
||||
public function selectIcon(string $component): void
|
||||
{
|
||||
$allowed = array_column($this->icons, 'component');
|
||||
if (!in_array($component, $allowed, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->avatarIcon = $component;
|
||||
$this->avatarPhoto = null;
|
||||
$this->avatarTab = 'icon';
|
||||
}
|
||||
|
||||
public function updatedAvatarPhoto(): void
|
||||
{
|
||||
if ($this->avatarPhoto) {
|
||||
$this->avatarIcon = null;
|
||||
$this->avatarTab = 'photo';
|
||||
}
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function filteredIcons(): array
|
||||
{
|
||||
$q = trim(mb_strtolower($this->iconSearch));
|
||||
if ($q === '') {
|
||||
return $this->icons;
|
||||
}
|
||||
|
||||
return array_values(array_filter($this->icons, function (array $icon) use ($q) {
|
||||
return str_contains(mb_strtolower($icon['label']), $q)
|
||||
|| str_contains(mb_strtolower($icon['component']), $q);
|
||||
}));
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function avatarPreviewType(): string
|
||||
{
|
||||
if ($this->avatarPhoto) {
|
||||
return 'photo';
|
||||
}
|
||||
if ($this->avatarIcon) {
|
||||
return 'icon';
|
||||
}
|
||||
return 'none';
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$this->validate([
|
||||
'name' => ['required', 'string', 'max:60'],
|
||||
'description' => ['nullable', 'string', 'max:140'],
|
||||
'avatarIcon' => ['nullable', 'string', 'max:100'],
|
||||
'avatarPhoto' => ['nullable', 'image', 'max:4096'],
|
||||
]);
|
||||
|
||||
$crew = Crew::create([
|
||||
'name' => $this->name,
|
||||
'description' => $this->description ?: null,
|
||||
'avatar_icon' => $this->avatarIcon,
|
||||
'image_id' => null,
|
||||
'cover_image_id' => null,
|
||||
]);
|
||||
|
||||
if ($this->avatarPhoto) {
|
||||
$disk = 'public';
|
||||
|
||||
$ext = $this->avatarPhoto->getClientOriginalExtension();
|
||||
$ext = $ext ? mb_strtolower($ext) : 'jpg';
|
||||
|
||||
$path = "crews/{$crew->id}/avatar.{$ext}";
|
||||
|
||||
Storage::disk($disk)->putFileAs(
|
||||
"crews/{$crew->id}",
|
||||
$this->avatarPhoto,
|
||||
"avatar.{$ext}"
|
||||
);
|
||||
|
||||
$absolute = Storage::disk($disk)->path($path);
|
||||
|
||||
$width = null;
|
||||
$height = null;
|
||||
|
||||
$sizeData = @getimagesize($absolute);
|
||||
if (is_array($sizeData)) {
|
||||
$width = $sizeData[0] ?? null;
|
||||
$height = $sizeData[1] ?? null;
|
||||
}
|
||||
|
||||
$image = Image::create([
|
||||
'disk' => $disk,
|
||||
'bucket' => null,
|
||||
'path' => $path,
|
||||
'original_name' => $this->avatarPhoto->getClientOriginalName(),
|
||||
'mime_type' => $this->avatarPhoto->getMimeType(),
|
||||
'size' => $this->avatarPhoto->getSize(),
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'variants' => null,
|
||||
'visibility' => 'public',
|
||||
'checksum' => null,
|
||||
'exif_stripped' => true,
|
||||
'uploaded_by_user_id' => Auth::id(),
|
||||
]);
|
||||
|
||||
$crew->image_id = $image->id;
|
||||
$crew->save();
|
||||
}
|
||||
|
||||
$crew->users()->attach(Auth::id());
|
||||
|
||||
// ToastMagic success
|
||||
$this->dispatch('toastmagic', type: 'success', message: 'Group created');
|
||||
|
||||
return redirect('/groups');
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div class="relative">
|
||||
<button type="button" wire:click="openModal" class="btn-primary w-full text-base">
|
||||
Create
|
||||
</button>
|
||||
|
||||
@if($isOpen)
|
||||
<div class="fixed inset-0 z-[9999]" role="dialog" aria-modal="true" wire:keydown.escape.window="closeModal">
|
||||
<button
|
||||
type="button"
|
||||
class="absolute inset-0 bg-black/50"
|
||||
wire:click="closeModal"
|
||||
aria-label="Close modal"
|
||||
></button>
|
||||
|
||||
<div class="absolute inset-0 bg-card">
|
||||
<div class="mx-auto flex h-full w-full max-w-[420px] flex-col px-6 pt-6 pb-8">
|
||||
<div class="flex items-center gap-3">
|
||||
<button type="button" wire:click="closeModal" class="grid h-10 w-10 place-items-center rounded-xl bg-background ring-1 ring-border">
|
||||
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h3 class="text-lg font-semibold">Create Group</h3>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 rounded-2xl bg-background p-4 ring-1 ring-border">
|
||||
<div class="mx-auto grid h-16 w-16 place-items-center rounded-2xl bg-muted">
|
||||
@if($this->avatarPreviewType === 'photo')
|
||||
<img src="{{ $avatarPhoto->temporaryUrl() }}" alt="Avatar preview" class="h-16 w-16 rounded-2xl object-cover" />
|
||||
@elseif($this->avatarPreviewType === 'icon')
|
||||
<x-dynamic-component :component="$avatarIcon" class="h-8 w-8 text-foreground" />
|
||||
@else
|
||||
<x-phosphor-mountains class="h-8 w-8 text-foreground/60" />
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
<p class="text-sm font-semibold text-foreground">
|
||||
{{ $name !== '' ? $name : 'Group Name' }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
{{ $description !== '' ? $description : 'Group description...' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<p class="text-sm font-semibold">Group Avatar</p>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
wire:click="openAvatarModal"
|
||||
class="mt-3 flex w-full items-center gap-3 rounded-2xl bg-background p-4 ring-1 ring-border"
|
||||
>
|
||||
<div class="grid h-12 w-12 place-items-center rounded-2xl border border-dashed border-border bg-muted">
|
||||
@if($this->avatarPreviewType === 'photo')
|
||||
<img src="{{ $avatarPhoto->temporaryUrl() }}" alt="Avatar preview" class="h-12 w-12 rounded-2xl object-cover" />
|
||||
@elseif($this->avatarPreviewType === 'icon')
|
||||
<x-dynamic-component :component="$avatarIcon" class="h-6 w-6 text-foreground" />
|
||||
@else
|
||||
<x-phosphor-mountains class="h-6 w-6 text-foreground" />
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="text-left">
|
||||
<p class="text-sm font-medium">Tap to pick an icon or upload a photo</p>
|
||||
<p class="mt-0.5 text-xs text-muted-foreground">This will show on your group.</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-col gap-3">
|
||||
<label class="rounded-2xl bg-background p-4 ring-1 ring-border">
|
||||
<p class="text-xs text-muted-foreground">Group Name</p>
|
||||
<input
|
||||
type="text"
|
||||
wire:model.live="name"
|
||||
class="mt-2 w-full rounded bg-transparent text-sm outline-none"
|
||||
placeholder="e.g. Weekend Warriors"
|
||||
/>
|
||||
@error('name')
|
||||
<p class="mt-2 text-xs text-red-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</label>
|
||||
|
||||
<label class="rounded-2xl bg-background p-4 ring-1 ring-border">
|
||||
<p class="text-xs text-muted-foreground">Description</p>
|
||||
<input
|
||||
type="text"
|
||||
wire:model.live="description"
|
||||
class="mt-2 w-full rounded bg-transparent text-sm outline-none"
|
||||
placeholder="What's this group about?"
|
||||
/>
|
||||
@error('description')
|
||||
<p class="mt-2 text-xs text-red-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mt-auto pt-6">
|
||||
<button type="button" wire:click="save" wire:loading.attr="disabled" class="btn-primary w-full text-base">
|
||||
<span wire:loading.remove wire:target="save">Create Group</span>
|
||||
<span wire:loading wire:target="save">Creating...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Avatar Picker Modal --}}
|
||||
@if($avatarModalOpen)
|
||||
<div class="absolute inset-0 z-[10000]" role="dialog" aria-modal="true" wire:keydown.escape.window="closeAvatarModal">
|
||||
<button
|
||||
type="button"
|
||||
class="absolute inset-0 bg-black/50"
|
||||
wire:click="closeAvatarModal"
|
||||
aria-label="Close avatar modal"
|
||||
></button>
|
||||
|
||||
<div class="absolute left-1/2 top-1/2 w-[92%] max-w-[420px] -translate-x-1/2 -translate-y-1/2 rounded-2xl bg-card p-5 shadow-xl ring-1 ring-border">
|
||||
<div class="flex items-center justify-between">
|
||||
<h4 class="text-base font-semibold">Group Avatar</h4>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="closeAvatarModal"
|
||||
class="grid h-9 w-9 place-items-center rounded-xl bg-background ring-1 ring-border"
|
||||
aria-label="Close"
|
||||
>
|
||||
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M6 6l12 12M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 rounded-2xl bg-muted p-1 ring-1 ring-border">
|
||||
<div class="grid grid-cols-2 gap-1">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="setAvatarTab('icon')"
|
||||
class="rounded-xl px-3 py-2 text-sm font-medium {{ $avatarTab === 'icon' ? 'bg-card ring-1 ring-border' : 'opacity-70' }}"
|
||||
>
|
||||
Icon
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="setAvatarTab('photo')"
|
||||
class="rounded-xl px-3 py-2 text-sm font-medium {{ $avatarTab === 'photo' ? 'bg-card ring-1 ring-border' : 'opacity-70' }}"
|
||||
>
|
||||
Photo
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($avatarTab === 'icon')
|
||||
<div class="mt-4">
|
||||
<div class="flex items-center gap-2 rounded-2xl bg-background px-3 py-2 ring-1 ring-border">
|
||||
<svg class="h-4 w-4 opacity-60" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M21 21l-4.3-4.3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<circle cx="11" cy="11" r="7" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<input
|
||||
type="text"
|
||||
wire:model.live="iconSearch"
|
||||
class="w-full bg-transparent text-sm outline-none"
|
||||
placeholder="Search icons..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 max-h-[320px] overflow-auto pr-1">
|
||||
<div class="grid grid-cols-6 gap-2 p-2">
|
||||
@foreach($this->filteredIcons as $icon)
|
||||
<button
|
||||
type="button"
|
||||
wire:click="selectIcon(@js($icon['component']))"
|
||||
class="grid h-12 w-12 place-items-center rounded-xl ring-1 ring-border {{ $avatarIcon === $icon['component'] ? 'bg-primary/15' : 'bg-background' }}"
|
||||
aria-label="Select icon {{ $icon['label'] }}"
|
||||
title="{{ $icon['label'] }}"
|
||||
>
|
||||
<x-dynamic-component :component="$icon['component']" class="h-6 w-6" />
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="mt-5">
|
||||
<label class="block cursor-pointer rounded-2xl bg-background p-5 ring-1 ring-border">
|
||||
<div class="grid place-items-center rounded-2xl border border-dashed border-border bg-muted px-6 py-8 text-center">
|
||||
<svg class="h-7 w-7" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M9 7a3 3 0 1 0 6 0a3 3 0 1 0-6 0Z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M4 20l5-6 4 4 3-3 4 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<p class="mt-2 text-sm font-medium">Upload Photo</p>
|
||||
<p class="mt-1 text-xs text-muted-foreground">Choose a photo for your group</p>
|
||||
|
||||
@if($avatarPhoto)
|
||||
<img src="{{ $avatarPhoto->temporaryUrl() }}" class="mt-4 h-20 w-20 rounded-2xl object-cover" alt="Uploaded preview" />
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<input type="file" class="hidden" wire:model="avatarPhoto" accept="image/*" />
|
||||
</label>
|
||||
|
||||
@error('avatarPhoto')
|
||||
<p class="mt-2 text-xs text-red-500">{{ $message }}</p>
|
||||
@enderror
|
||||
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<button type="button" wire:click="closeAvatarModal" class="btn-outline px-4 py-2 text-sm">
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
13
resources/views/components/groups/⚡join.blade.php
Normal file
13
resources/views/components/groups/⚡join.blade.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
new class extends Component
|
||||
{
|
||||
//
|
||||
};
|
||||
?>
|
||||
|
||||
<div>
|
||||
{{-- Always remember that you are absolutely unique. Just like everyone else. - Margaret Mead --}}
|
||||
</div>
|
||||
37
resources/views/components/⚡group-card.blade.php
Normal file
37
resources/views/components/⚡group-card.blade.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Crew;
|
||||
use Livewire\Component;
|
||||
|
||||
new class extends Component {
|
||||
public Crew $crew;
|
||||
|
||||
public function mount(Crew $crew): void
|
||||
{
|
||||
$this->crew = $crew;
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div
|
||||
class="card bg-card flex items-center gap-4 rounded-xl transition-colors hover:bg-secondary/50 active:scale-[0.98] p-4">
|
||||
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15 text-primary-foreground mb-2">
|
||||
<x-bi-people class="h-6 w-6 text-primary"/>
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<h3 class="truncate text-sm font-semibold">{{ $crew->name }}</h3>
|
||||
<p>{{ $crew->description }}</p>
|
||||
<div class="mt-1 flex items-center gap-3 text-xs text-muted-foreground">
|
||||
<span class="flex items-center gap-1">
|
||||
<x-bi-people class="h-3 w-3"/>
|
||||
{{ $crew->users_count }}
|
||||
</span>
|
||||
<span>
|
||||
{{ $crew->patches_count }} patches
|
||||
</span>
|
||||
<span class="text-primary font-medium">
|
||||
{{ $crew->patches_count }} earned
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,17 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Livewire\Component;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
new class extends Component
|
||||
{
|
||||
//
|
||||
public Collection $crews;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->crews = Auth::user()
|
||||
->crews()
|
||||
->withCount(['users', 'patches'])
|
||||
->get();
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div class="flex flex-col gap-6 px-4 pt-6 pb-4">
|
||||
<div>
|
||||
<p class="text-sm text-muted-foreground">Welcome back,</p>
|
||||
<h1 class="text-2xl font-bold text-foreground">Alex Rivera</h1>
|
||||
<h1 class="text-2xl font-bold text-foreground">{{ ucfirst(Auth::user()->name) }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
@@ -19,23 +29,37 @@ new class extends Component
|
||||
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15 text-primary-foreground mb-2">
|
||||
<x-bi-people class="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<span class="font-bold text-xl">2</span>
|
||||
<span class="font-bold text-xl">{{ $crews->count() }}</span>
|
||||
<span class="text-muted-foreground text-sm">Groups</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center gap-1 rounded-xl border border-border bg-card p-3">
|
||||
<div class="grid h-10 w-10 place-items-center rounded-xl bg-accent/15 text-primary-foreground mb-2">
|
||||
<x-solar-medal-ribbon-linear class="h-6 w-6 text-accent" />
|
||||
</div>
|
||||
<span class="font-bold text-xl">2</span>
|
||||
<span class="text-muted-foreground text-sm">Groups</span>
|
||||
<span class="font-bold text-xl">0</span>
|
||||
<span class="text-muted-foreground text-sm">Earned</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center gap-1 rounded-xl border border-border bg-card p-3">
|
||||
<div class="grid h-10 w-10 place-items-center rounded-xl bg-card-foreground/15 text-primary-foreground mb-2">
|
||||
<x-phosphor-trend-up class="h-6 w-6 text-card-foreground" />
|
||||
</div>
|
||||
<span class="font-bold text-xl">2</span>
|
||||
<span class="text-muted-foreground text-sm">Groups</span>
|
||||
<span class="font-bold text-xl">0</span>
|
||||
<span class="text-muted-foreground text-sm">In progress</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center justify-between mb-5 font-semibold">
|
||||
<p class="text-foreground text-base">Your Groups</p>
|
||||
<a class="text-primary" href="{{ route('groups') }}">View All</a>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
@foreach ($crews as $crew)
|
||||
<livewire:group-card :crew="$crew" :key="$crew->id" />
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Component;
|
||||
|
||||
new class extends Component
|
||||
{
|
||||
//
|
||||
new class extends Component {
|
||||
public Collection $crews;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->crews = Auth::user()
|
||||
->crews()
|
||||
->withCount(['users', 'patches'])
|
||||
->get();
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div>
|
||||
{{-- Order your soul. Reduce your wants. - Augustine --}}
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 px-4 pt-6 pb-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-xl font-bold text-foreground">Your Groups</h1>
|
||||
<div class="flex gap-2">
|
||||
<button class="btn-outline w-full text-base bg-background">Join</button>
|
||||
<livewire:groups.create/>
|
||||
</div>
|
||||
</div>
|
||||
@foreach($crews as $crew)
|
||||
<livewire:group-card :crew="$crew" :key="$crew->id"/>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user