mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 21:47:39 +02:00
- Added confirmation modal to sidebar's quick power switch
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Plug, Power, PowerOff, Loader2, Wifi, WifiOff, Zap } from 'lucide-react';
|
||||
import { api } from '../api/client';
|
||||
import type { SmartPlug } from '../api/client';
|
||||
import { ConfirmModal } from './ConfirmModal';
|
||||
|
||||
interface SwitchbarPopoverProps {
|
||||
onClose: () => void;
|
||||
@@ -9,6 +11,7 @@ interface SwitchbarPopoverProps {
|
||||
|
||||
function SwitchItem({ plug }: { plug: SmartPlug }) {
|
||||
const queryClient = useQueryClient();
|
||||
const [confirmAction, setConfirmAction] = useState<'on' | 'off' | null>(null);
|
||||
|
||||
// Fetch current status
|
||||
const { data: status, isLoading: statusLoading } = useQuery({
|
||||
@@ -29,66 +32,86 @@ function SwitchItem({ plug }: { plug: SmartPlug }) {
|
||||
const isReachable = status?.reachable ?? false;
|
||||
const isPending = controlMutation.isPending;
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (confirmAction) {
|
||||
controlMutation.mutate(confirmAction);
|
||||
setConfirmAction(null);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between py-2 px-3 hover:bg-bambu-dark-tertiary rounded-lg transition-colors">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`p-1.5 rounded ${isReachable ? (isOn ? 'bg-bambu-green/20' : 'bg-bambu-dark') : 'bg-red-500/20'}`}>
|
||||
<Plug className={`w-4 h-4 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-400'}`} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-white font-medium">{plug.name}</p>
|
||||
<div className="flex items-center gap-1 text-xs">
|
||||
{statusLoading ? (
|
||||
<Loader2 className="w-3 h-3 text-bambu-gray animate-spin" />
|
||||
) : isReachable ? (
|
||||
<>
|
||||
<Wifi className="w-3 h-3 text-bambu-green" />
|
||||
<span className={isOn ? 'text-bambu-green' : 'text-bambu-gray'}>{status?.state || 'Unknown'}</span>
|
||||
{status?.energy?.power !== null && status?.energy?.power !== undefined && (
|
||||
<>
|
||||
<span className="text-bambu-gray mx-1">|</span>
|
||||
<Zap className="w-3 h-3 text-yellow-400" />
|
||||
<span className="text-yellow-400">{Math.round(status.energy.power)}W</span>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<WifiOff className="w-3 h-3 text-red-400" />
|
||||
<span className="text-red-400">Offline</span>
|
||||
</>
|
||||
)}
|
||||
<>
|
||||
<div className="flex items-center justify-between py-2 px-3 hover:bg-bambu-dark-tertiary rounded-lg transition-colors">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`p-1.5 rounded ${isReachable ? (isOn ? 'bg-bambu-green/20' : 'bg-bambu-dark') : 'bg-red-500/20'}`}>
|
||||
<Plug className={`w-4 h-4 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-400'}`} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-white font-medium">{plug.name}</p>
|
||||
<div className="flex items-center gap-1 text-xs">
|
||||
{statusLoading ? (
|
||||
<Loader2 className="w-3 h-3 text-bambu-gray animate-spin" />
|
||||
) : isReachable ? (
|
||||
<>
|
||||
<Wifi className="w-3 h-3 text-bambu-green" />
|
||||
<span className={isOn ? 'text-bambu-green' : 'text-bambu-gray'}>{status?.state || 'Unknown'}</span>
|
||||
{status?.energy?.power !== null && status?.energy?.power !== undefined && (
|
||||
<>
|
||||
<span className="text-bambu-gray mx-1">|</span>
|
||||
<Zap className="w-3 h-3 text-yellow-400" />
|
||||
<span className="text-yellow-400">{Math.round(status.energy.power)}W</span>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<WifiOff className="w-3 h-3 text-red-400" />
|
||||
<span className="text-red-400">Offline</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-1">
|
||||
<button
|
||||
onClick={() => setConfirmAction('on')}
|
||||
disabled={!isReachable || isPending}
|
||||
className={`p-1.5 rounded transition-colors ${
|
||||
isOn
|
||||
? 'bg-bambu-green text-white'
|
||||
: 'bg-bambu-dark text-bambu-gray hover:text-white'
|
||||
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
title="Turn On"
|
||||
>
|
||||
{isPending ? <Loader2 className="w-4 h-4 animate-spin" /> : <Power className="w-4 h-4" />}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setConfirmAction('off')}
|
||||
disabled={!isReachable || isPending}
|
||||
className={`p-1.5 rounded transition-colors ${
|
||||
!isOn && isReachable
|
||||
? 'bg-bambu-dark-tertiary text-white'
|
||||
: 'bg-bambu-dark text-bambu-gray hover:text-white'
|
||||
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
title="Turn Off"
|
||||
>
|
||||
{isPending ? <Loader2 className="w-4 h-4 animate-spin" /> : <PowerOff className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-1">
|
||||
<button
|
||||
onClick={() => controlMutation.mutate('on')}
|
||||
disabled={!isReachable || isPending}
|
||||
className={`p-1.5 rounded transition-colors ${
|
||||
isOn
|
||||
? 'bg-bambu-green text-white'
|
||||
: 'bg-bambu-dark text-bambu-gray hover:text-white'
|
||||
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
title="Turn On"
|
||||
>
|
||||
{isPending ? <Loader2 className="w-4 h-4 animate-spin" /> : <Power className="w-4 h-4" />}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => controlMutation.mutate('off')}
|
||||
disabled={!isReachable || isPending}
|
||||
className={`p-1.5 rounded transition-colors ${
|
||||
!isOn && isReachable
|
||||
? 'bg-bambu-dark-tertiary text-white'
|
||||
: 'bg-bambu-dark text-bambu-gray hover:text-white'
|
||||
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
title="Turn Off"
|
||||
>
|
||||
{isPending ? <Loader2 className="w-4 h-4 animate-spin" /> : <PowerOff className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{confirmAction && (
|
||||
<ConfirmModal
|
||||
title={`Turn ${confirmAction === 'on' ? 'On' : 'Off'} Smart Plug`}
|
||||
message={`Are you sure you want to turn ${confirmAction === 'on' ? 'on' : 'off'} "${plug.name}"?`}
|
||||
confirmText={confirmAction === 'on' ? 'Turn On' : 'Turn Off'}
|
||||
variant={confirmAction === 'off' ? 'warning' : 'default'}
|
||||
onConfirm={handleConfirm}
|
||||
onCancel={() => setConfirmAction(null)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user