Add Sensor Hub tab to account settings, integrating new SensorHubTab and related components for sensor management. Updated layout and added error handling in the sensor form.

This commit is contained in:
2026-02-19 15:07:21 +03:30
parent 48bf0921c7
commit 3871ec89f7
5 changed files with 122 additions and 11 deletions
@@ -12,6 +12,7 @@ const SecurityTab = dynamic(() => import('@views/pages/account-settings/security
const BillingPlansTab = dynamic(() => import('@views/pages/account-settings/billing-plans'))
const NotificationsTab = dynamic(() => import('@views/pages/account-settings/notifications'))
const ConnectionsTab = dynamic(() => import('@views/pages/account-settings/connections'))
const SensorHubTab = dynamic(() => import('@views/pages/account-settings/sensor-hub'))
// Vars
const tabContentList = (): { [key: string]: ReactElement } => ({
@@ -19,7 +20,8 @@ const tabContentList = (): { [key: string]: ReactElement } => ({
security: <SecurityTab />,
'billing-plans': <BillingPlansTab />,
notifications: <NotificationsTab />,
connections: <ConnectionsTab />
connections: <ConnectionsTab />,
'sensor-hub': <SensorHubTab />
})
const AccountSettingsPage = () => {
+5 -4
View File
@@ -24,10 +24,11 @@ const AccountSettings = ({ tabContentList }: { tabContentList: { [key: string]:
return (
<TabContext value={activeTab}>
<Grid container spacing={6}>
{/* <Grid size={{ xs: 12 }}>
<Grid size={{ xs: 12 }}>
<CustomTabList onChange={handleChange} variant='scrollable' pill='true'>
<Tab label='Account' icon={<i className='tabler-users' />} iconPosition='start' value='account' />
<Tab label='Security' icon={<i className='tabler-lock' />} iconPosition='start' value='security' />
<Tab label='SensorHub' icon={<i className='tabler-device-watch' />} iconPosition='start' value='sensor-hub' />
{/* <Tab label='Security' icon={<i className='tabler-lock' />} iconPosition='start' value='security' />
<Tab
label='Billing & Plans'
icon={<i className='tabler-bookmark' />}
@@ -40,9 +41,9 @@ const AccountSettings = ({ tabContentList }: { tabContentList: { [key: string]:
iconPosition='start'
value='notifications'
/>
<Tab label='Connections' icon={<i className='tabler-link' />} iconPosition='start' value='connections' />
<Tab label='Connections' icon={<i className='tabler-link' />} iconPosition='start' value='connections' /> */}
</CustomTabList>
</Grid> */}
</Grid>
<Grid size={{ xs: 12 }}>
<TabPanel value={activeTab} className='p-0'>
{tabContentList[activeTab]}
@@ -0,0 +1,79 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Typography from '@mui/material/Typography'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import Fade from '@mui/material/Fade'
// Hook Imports
import { useSensorHub } from '@/hooks/useSensorHub'
// API Imports
import type { Sensor } from '@/libs/api/services/sensorHubService'
// Component Imports
import SensorHubTable from '@views/sensorHub/SensorHubTable'
import OptionSensorHub from '@views/sensorHub/OptionSensorHub'
import FormSensorHub from '@views/sensorHub/FormSensorHub'
const transitionTimeout = { enter: 300, exit: 200 }
const SensorHubTabContent = () => {
const [showAddForm, setShowAddForm] = useState(false)
const { setSensorHub } = useSensorHub()
const handleBack = () => setShowAddForm(false)
const handleConfirm = (sensor: Sensor) => {
setSensorHub({ id: sensor.uuid_sensor, ...sensor })
}
return (
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Card>
<CardContent>
<Fade key={showAddForm ? 'form' : 'options'} in timeout={transitionTimeout}>
<div>
{showAddForm ? (
<FormSensorHub onBack={handleBack} />
) : (
<div className='flex flex-col gap-4'>
<div className='grid grid-cols-1 sm:grid-cols-[1fr_auto] items-center gap-4'>
<div className='flex flex-col gap-0.5'>
<Typography variant='h6' fontWeight={600}>
انتخاب سنسور
</Typography>
<Typography variant='body2' color='text.secondary' sx={{ lineHeight: 1.5 }}>
سنسور مورد نظر را انتخاب کنید یا سنسور جدید اضافه کنید
</Typography>
</div>
<Button
variant='contained'
color='primary'
startIcon={<i className='tabler-plus text-xl' />}
onClick={() => setShowAddForm(true)}
>
اضافه کردن سنسور
</Button>
</div>
<OptionSensorHub onConfirm={handleConfirm} />
</div>
)}
</div>
</Fade>
</CardContent>
</Card>
</Grid>
</Grid>
)
}
export default SensorHubTabContent
@@ -0,0 +1 @@
export { default } from './SensorHubTabContent'
+34 -6
View File
@@ -6,7 +6,11 @@ import { useState } from 'react'
// MUI Imports
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Typography from '@mui/material/Typography'
import CircularProgress from '@mui/material/CircularProgress'
import Alert from '@mui/material/Alert'
// API Imports
import { sensorHubService } from '@/libs/api'
// Component Imports
import CustomTextField from '@core/components/mui/TextField'
@@ -18,10 +22,22 @@ type FormSensorHubProps = {
const FormSensorHub = ({ onBack }: FormSensorHubProps) => {
const [name, setName] = useState('')
const [uuidSensor, setUuidSensor] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
// TODO: Call API to add sensor
setError(null)
setLoading(true)
try {
await sensorHubService.addSensor({ name, uuid_sensor: uuidSensor })
onBack()
} catch (err: unknown) {
const message = err && typeof err === 'object' && 'message' in err ? String((err as { message: string }).message) : 'خطا در ذخیره سنسور'
setError(message)
} finally {
setLoading(false)
}
}
return (
@@ -40,6 +56,13 @@ const FormSensorHub = ({ onBack }: FormSensorHubProps) => {
</div>
<form onSubmit={handleSubmit}>
<Grid container spacing={4}>
{error && (
<Grid size={{ xs: 12 }}>
<Alert severity='error' onClose={() => setError(null)}>
{error}
</Alert>
</Grid>
)}
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
@@ -59,11 +82,16 @@ const FormSensorHub = ({ onBack }: FormSensorHubProps) => {
/>
</Grid>
<Grid size={{ xs: 12 }} className='flex gap-2'>
<Button variant='tonal' color='secondary' onClick={onBack}>
<Button variant='tonal' color='secondary' onClick={onBack} disabled={loading}>
انصراف
</Button>
<Button variant='contained' type='submit' startIcon={<i className='tabler-plus' />}>
ذخیره سنسور
<Button
variant='contained'
type='submit'
disabled={loading}
startIcon={loading ? <CircularProgress size={16} color='inherit' /> : <i className='tabler-plus' />}
>
{loading ? 'در حال ذخیره...' : 'ذخیره سنسور'}
</Button>
</Grid>
</Grid>