|
@@ -1,6 +1,7 @@
|
|
|
import { useState, useEffect, useRef } from 'react';
|
|
import { useState, useEffect, useRef } from 'react';
|
|
|
import { useMutation, useQueryClient, useQuery } from '@tanstack/react-query';
|
|
import { useMutation, useQueryClient, useQuery } from '@tanstack/react-query';
|
|
|
import { X, Save, Loader2, Wifi, WifiOff, CheckCircle, Bell, Clock, LayoutGrid, Search, Plug, Power, Home, Radio, Eye } from 'lucide-react';
|
|
import { X, Save, Loader2, Wifi, WifiOff, CheckCircle, Bell, Clock, LayoutGrid, Search, Plug, Power, Home, Radio, Eye } from 'lucide-react';
|
|
|
|
|
+import { useTranslation } from 'react-i18next';
|
|
|
import { api } from '../api/client';
|
|
import { api } from '../api/client';
|
|
|
import type { SmartPlug, SmartPlugCreate, SmartPlugUpdate, DiscoveredTasmotaDevice } from '../api/client';
|
|
import type { SmartPlug, SmartPlugCreate, SmartPlugUpdate, DiscoveredTasmotaDevice } from '../api/client';
|
|
|
import { Button } from './Button';
|
|
import { Button } from './Button';
|
|
@@ -11,6 +12,7 @@ interface AddSmartPlugModalProps {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
|
|
+ const { t } = useTranslation();
|
|
|
const queryClient = useQueryClient();
|
|
const queryClient = useQueryClient();
|
|
|
const isEditing = !!plug;
|
|
const isEditing = !!plug;
|
|
|
|
|
|
|
@@ -469,7 +471,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
{isScanning && scanProgress.total > 0 && (
|
|
{isScanning && scanProgress.total > 0 && (
|
|
|
<div className="space-y-1">
|
|
<div className="space-y-1">
|
|
|
<div className="flex justify-between text-xs text-bambu-gray">
|
|
<div className="flex justify-between text-xs text-bambu-gray">
|
|
|
- <span>Scanning network...</span>
|
|
|
|
|
|
|
+ <span>{t('smartPlugs.addSmartPlug.scanningNetwork')}</span>
|
|
|
<span>{scanProgress.scanned} / {scanProgress.total}</span>
|
|
<span>{scanProgress.scanned} / {scanProgress.total}</span>
|
|
|
</div>
|
|
</div>
|
|
|
<div className="w-full bg-bambu-dark-tertiary rounded-full h-2">
|
|
<div className="w-full bg-bambu-dark-tertiary rounded-full h-2">
|
|
@@ -538,7 +540,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
disabled
|
|
disabled
|
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-bambu-gray cursor-not-allowed opacity-50"
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-bambu-gray cursor-not-allowed opacity-50"
|
|
|
>
|
|
>
|
|
|
- <option>Choose an entity...</option>
|
|
|
|
|
|
|
+ <option>{t('smartPlugs.addSmartPlug.chooseEntity')}</option>
|
|
|
</select>
|
|
</select>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -585,7 +587,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
setIsEntityDropdownOpen(true);
|
|
setIsEntityDropdownOpen(true);
|
|
|
setHaEntitySearch('');
|
|
setHaEntitySearch('');
|
|
|
}}
|
|
}}
|
|
|
- placeholder="Search entities..."
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.searchEntities')}
|
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
{haEntityId && !isEntityDropdownOpen && (
|
|
{haEntityId && !isEntityDropdownOpen && (
|
|
@@ -697,7 +699,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
setIsPowerDropdownOpen(true);
|
|
setIsPowerDropdownOpen(true);
|
|
|
setPowerSensorSearch('');
|
|
setPowerSensorSearch('');
|
|
|
}}
|
|
}}
|
|
|
- placeholder="Search power sensors..."
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.searchPowerSensors')}
|
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
{haPowerEntity && !isPowerDropdownOpen && (
|
|
{haPowerEntity && !isPowerDropdownOpen && (
|
|
@@ -781,7 +783,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
setIsEnergyTodayDropdownOpen(true);
|
|
setIsEnergyTodayDropdownOpen(true);
|
|
|
setEnergyTodaySearch('');
|
|
setEnergyTodaySearch('');
|
|
|
}}
|
|
}}
|
|
|
- placeholder="Search energy sensors..."
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.searchEnergySensors')}
|
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
{haEnergyTodayEntity && !isEnergyTodayDropdownOpen && (
|
|
{haEnergyTodayEntity && !isEnergyTodayDropdownOpen && (
|
|
@@ -865,7 +867,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
setIsEnergyTotalDropdownOpen(true);
|
|
setIsEnergyTotalDropdownOpen(true);
|
|
|
setEnergyTotalSearch('');
|
|
setEnergyTotalSearch('');
|
|
|
}}
|
|
}}
|
|
|
- placeholder="Search energy sensors..."
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.searchEnergySensors')}
|
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
{haEnergyTotalEntity && !isEnergyTotalDropdownOpen && (
|
|
{haEnergyTotalEntity && !isEnergyTotalDropdownOpen && (
|
|
@@ -957,7 +959,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="text"
|
|
type="text"
|
|
|
value={mqttPowerTopic}
|
|
value={mqttPowerTopic}
|
|
|
onChange={(e) => setMqttPowerTopic(e.target.value)}
|
|
onChange={(e) => setMqttPowerTopic(e.target.value)}
|
|
|
- placeholder="zigbee2mqtt/shelly-working-room"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.mqttPowerTopic')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -968,7 +970,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="text"
|
|
type="text"
|
|
|
value={mqttPowerPath}
|
|
value={mqttPowerPath}
|
|
|
onChange={(e) => setMqttPowerPath(e.target.value)}
|
|
onChange={(e) => setMqttPowerPath(e.target.value)}
|
|
|
- placeholder="power_l1"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.mqttPowerPath')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -1009,7 +1011,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="text"
|
|
type="text"
|
|
|
value={mqttEnergyPath}
|
|
value={mqttEnergyPath}
|
|
|
onChange={(e) => setMqttEnergyPath(e.target.value)}
|
|
onChange={(e) => setMqttEnergyPath(e.target.value)}
|
|
|
- placeholder="energy_l1"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.mqttEnergyPath')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -1050,7 +1052,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="text"
|
|
type="text"
|
|
|
value={mqttStatePath}
|
|
value={mqttStatePath}
|
|
|
onChange={(e) => setMqttStatePath(e.target.value)}
|
|
onChange={(e) => setMqttStatePath(e.target.value)}
|
|
|
- placeholder="state_l1"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.mqttStatePath')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -1060,7 +1062,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="text"
|
|
type="text"
|
|
|
value={mqttStateOnValue}
|
|
value={mqttStateOnValue}
|
|
|
onChange={(e) => setMqttStateOnValue(e.target.value)}
|
|
onChange={(e) => setMqttStateOnValue(e.target.value)}
|
|
|
- placeholder="ON, true, 1"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.mqttStateOnValue')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -1087,7 +1089,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
setIpAddress(e.target.value);
|
|
setIpAddress(e.target.value);
|
|
|
setTestResult(null);
|
|
setTestResult(null);
|
|
|
}}
|
|
}}
|
|
|
- placeholder="192.168.1.100"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.ipAddress')}
|
|
|
className="flex-1 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
className="flex-1 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
<Button
|
|
<Button
|
|
@@ -1128,7 +1130,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
) : (
|
|
) : (
|
|
|
<>
|
|
<>
|
|
|
<WifiOff className="w-5 h-5" />
|
|
<WifiOff className="w-5 h-5" />
|
|
|
- <span>Connection failed</span>
|
|
|
|
|
|
|
+ <span>{t('smartPlugs.addSmartPlug.connectionFailed')}</span>
|
|
|
</>
|
|
</>
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
@@ -1141,7 +1143,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="text"
|
|
type="text"
|
|
|
value={name}
|
|
value={name}
|
|
|
onChange={(e) => setName(e.target.value)}
|
|
onChange={(e) => setName(e.target.value)}
|
|
|
- placeholder="Living Room Plug"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.name')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -1156,7 +1158,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="text"
|
|
type="text"
|
|
|
value={username}
|
|
value={username}
|
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
|
- placeholder="admin"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.username')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -1166,7 +1168,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="password"
|
|
type="password"
|
|
|
value={password}
|
|
value={password}
|
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
|
- placeholder="********"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.password')}
|
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -1225,7 +1227,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="number"
|
|
type="number"
|
|
|
value={powerAlertHigh}
|
|
value={powerAlertHigh}
|
|
|
onChange={(e) => setPowerAlertHigh(e.target.value)}
|
|
onChange={(e) => setPowerAlertHigh(e.target.value)}
|
|
|
- placeholder="e.g. 200"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.powerAlertHigh')}
|
|
|
min="0"
|
|
min="0"
|
|
|
max="5000"
|
|
max="5000"
|
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
@@ -1237,7 +1239,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
|
|
|
type="number"
|
|
type="number"
|
|
|
value={powerAlertLow}
|
|
value={powerAlertLow}
|
|
|
onChange={(e) => setPowerAlertLow(e.target.value)}
|
|
onChange={(e) => setPowerAlertLow(e.target.value)}
|
|
|
- placeholder="e.g. 10"
|
|
|
|
|
|
|
+ placeholder={t('smartPlugs.addSmartPlug.placeholders.powerAlertLow')}
|
|
|
min="0"
|
|
min="0"
|
|
|
max="5000"
|
|
max="5000"
|
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|
|
className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
|