diff --git a/app/Livewire/Concerns/TogglesEntities.php b/app/Livewire/Concerns/TogglesEntities.php new file mode 100644 index 0000000..229dbd9 --- /dev/null +++ b/app/Livewire/Concerns/TogglesEntities.php @@ -0,0 +1,25 @@ +find($entityId); + + if ($entity === null || ! in_array($entity->type, ['switch', 'light'], true)) { + return; + } + + app(DeviceCommandService::class)->toggle($entity); + } +} diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php index 1fce672..a4b7d81 100644 --- a/app/Livewire/Dashboard.php +++ b/app/Livewire/Dashboard.php @@ -2,6 +2,7 @@ namespace App\Livewire; +use App\Livewire\Concerns\TogglesEntities; use App\Models\Room; use App\Services\HomeStatus; use Livewire\Attributes\Layout; @@ -11,6 +12,8 @@ use Livewire\Component; #[Layout('layouts.app')] class Dashboard extends Component { + use TogglesEntities; + /** Live update: any device state change re-renders (re-queries) the dashboard. */ #[On('echo-private:home,.DeviceStateChanged')] public function onDeviceStateChanged(): void diff --git a/app/Livewire/Devices/Index.php b/app/Livewire/Devices/Index.php index b709672..277b8ad 100644 --- a/app/Livewire/Devices/Index.php +++ b/app/Livewire/Devices/Index.php @@ -2,15 +2,22 @@ namespace App\Livewire\Devices; +use App\Livewire\Concerns\TogglesEntities; use App\Models\Device; use App\Models\Room; use Livewire\Attributes\Layout; +use Livewire\Attributes\On; use Livewire\Attributes\Url; use Livewire\Component; #[Layout('layouts.app')] class Index extends Component { + use TogglesEntities; + + #[On('echo-private:home,.DeviceStateChanged')] + public function onDeviceStateChanged(): void {} + #[Url(as: 'q')] public string $search = ''; diff --git a/resources/views/components/device-card.blade.php b/resources/views/components/device-card.blade.php new file mode 100644 index 0000000..994dfd8 --- /dev/null +++ b/resources/views/components/device-card.blade.php @@ -0,0 +1,59 @@ +@props(['device', 'controllable' => true]) + +@php + $entities = $device->entities; + $primary = $controllable ? $entities->first(fn ($e) => in_array($e->type, ['switch', 'light'], true)) : null; + $on = $primary ? (data_get($primary->state?->state, 'on') === true) : false; + $secondary = $primary ? $entities->reject(fn ($e) => $e->id === $primary->id) : $entities; + $online = $device->isOnline(); + $icon = match (true) { + $device->isCloud() => 'doorbell', + $primary?->type === 'light' => 'bolt', + $entities->contains(fn ($e) => $e->type === 'contact') => 'window', + $entities->contains(fn ($e) => $e->type === 'motion') => 'activity', + default => 'devices', + }; +@endphp + +
$on, + 'border-line-soft bg-surface hover:border-line' => ! $on, +])> +
+ $on, + 'bg-inset text-ink-2' => ! $on, + ])> + +
+ {{ $device->name }} +
+ {{ $device->room?->name ?? __('devices.no_room') }} + @if ($device->isCloud()) + + @endif +
+
+ + +
+ + @if ($secondary->isNotEmpty()) +
+ @foreach ($secondary as $entity) + + @endforeach +
+ @endif + + @if ($primary) +
+ $on, 'text-ink-3' => ! $on])>{{ $on ? __('devices.on') : __('devices.off') }} + +
+ @endif +
diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php index 4f3fd3c..6585b3b 100644 --- a/resources/views/livewire/dashboard.blade.php +++ b/resources/views/livewire/dashboard.blade.php @@ -26,33 +26,21 @@ - {{-- rooms + devices --}} -
-

{{ __('dashboard.rooms_title') }}

-
- @foreach ($groups as $group) - - - - @endforeach -
+ {{-- rooms + devices — a card per device, grouped by room --}} +
+ @foreach ($groups as $group) +
+
+

{{ $group['name'] }}

+ {{ count($group['devices']) }} +
+
+ @foreach ($group['devices'] as $device) + + @endforeach +
+
+ @endforeach
diff --git a/resources/views/livewire/devices/index.blade.php b/resources/views/livewire/devices/index.blade.php index 0a5dcf3..27bc310 100644 --- a/resources/views/livewire/devices/index.blade.php +++ b/resources/views/livewire/devices/index.blade.php @@ -31,23 +31,17 @@
{{ trans_choice('devices.count', $total, ['count' => $total]) }}
@forelse ($groups as $roomName => $devices) - - {{ $devices->count() }} -
+
+
+

{{ $roomName }}

+ {{ $devices->count() }} +
+ - +
@empty

{{ __('devices.none_match') }}

diff --git a/resources/views/livewire/rooms/show.blade.php b/resources/views/livewire/rooms/show.blade.php index 8b595fc..06af1cc 100644 --- a/resources/views/livewire/rooms/show.blade.php +++ b/resources/views/livewire/rooms/show.blade.php @@ -9,30 +9,15 @@ -
- @forelse ($room->devices as $device) - -
-
- - {{ $device->name }} - {{ $device->model }} -
-
- @foreach ($device->entities as $entity) -
- - @if (in_array($entity->type, ['switch', 'light'])) - - @endif -
- @endforeach -
-
-
- @empty +
+ @if ($room->devices->isEmpty())

{{ __('rooms.no_devices') }}

- @endforelse + @else +
+ @foreach ($room->devices as $device) + + @endforeach +
+ @endif
diff --git a/resources/views/livewire/windows.blade.php b/resources/views/livewire/windows.blade.php index 74557e6..97e010b 100644 --- a/resources/views/livewire/windows.blade.php +++ b/resources/views/livewire/windows.blade.php @@ -22,28 +22,49 @@ @foreach ($groups as $roomName => $sensors) - -
+
+
+

{{ $roomName }}

+ {{ $sensors->count() }} +
+
@foreach ($sensors as $sensor) @php $battery = $sensor->device->entities->firstWhere('type', 'battery'); $pct = $battery ? (int) data_get($battery->state, 'state.percent', 0) : null; + $pos = data_get($sensor->state, 'state.position') ?? (data_get($sensor->state, 'state.open') === true ? 'open' : 'closed'); + $isMotion = $sensor->type === 'motion'; + $alert = $isMotion ? (data_get($sensor->state, 'state.on') === true || data_get($sensor->state, 'state.active') === true) : $pos !== 'closed'; @endphp - - +
@endforeach @endif