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 BillingPlansTab = dynamic(() => import('@views/pages/account-settings/billing-plans'))
const NotificationsTab = dynamic(() => import('@views/pages/account-settings/notifications')) const NotificationsTab = dynamic(() => import('@views/pages/account-settings/notifications'))
const ConnectionsTab = dynamic(() => import('@views/pages/account-settings/connections')) const ConnectionsTab = dynamic(() => import('@views/pages/account-settings/connections'))
const SensorHubTab = dynamic(() => import('@views/pages/account-settings/sensor-hub'))
// Vars // Vars
const tabContentList = (): { [key: string]: ReactElement } => ({ const tabContentList = (): { [key: string]: ReactElement } => ({
@@ -19,7 +20,8 @@ const tabContentList = (): { [key: string]: ReactElement } => ({
security: <SecurityTab />, security: <SecurityTab />,
'billing-plans': <BillingPlansTab />, 'billing-plans': <BillingPlansTab />,
notifications: <NotificationsTab />, notifications: <NotificationsTab />,
connections: <ConnectionsTab /> connections: <ConnectionsTab />,
'sensor-hub': <SensorHubTab />
}) })
const AccountSettingsPage = () => { const AccountSettingsPage = () => {
+5 -4
View File
@@ -24,10 +24,11 @@ const AccountSettings = ({ tabContentList }: { tabContentList: { [key: string]:
return ( return (
<TabContext value={activeTab}> <TabContext value={activeTab}>
<Grid container spacing={6}> <Grid container spacing={6}>
{/* <Grid size={{ xs: 12 }}> <Grid size={{ xs: 12 }}>
<CustomTabList onChange={handleChange} variant='scrollable' pill='true'> <CustomTabList onChange={handleChange} variant='scrollable' pill='true'>
<Tab label='Account' icon={<i className='tabler-users' />} iconPosition='start' value='account' /> <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 <Tab
label='Billing & Plans' label='Billing & Plans'
icon={<i className='tabler-bookmark' />} icon={<i className='tabler-bookmark' />}
@@ -40,9 +41,9 @@ const AccountSettings = ({ tabContentList }: { tabContentList: { [key: string]:
iconPosition='start' iconPosition='start'
value='notifications' 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> </CustomTabList>
</Grid> */} </Grid>
<Grid size={{ xs: 12 }}> <Grid size={{ xs: 12 }}>
<TabPanel value={activeTab} className='p-0'> <TabPanel value={activeTab} className='p-0'>
{tabContentList[activeTab]} {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 // MUI Imports
import Grid from '@mui/material/Grid2' import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button' 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 // Component Imports
import CustomTextField from '@core/components/mui/TextField' import CustomTextField from '@core/components/mui/TextField'
@@ -18,10 +22,22 @@ type FormSensorHubProps = {
const FormSensorHub = ({ onBack }: FormSensorHubProps) => { const FormSensorHub = ({ onBack }: FormSensorHubProps) => {
const [name, setName] = useState('') const [name, setName] = useState('')
const [uuidSensor, setUuidSensor] = 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() 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 ( return (
@@ -40,6 +56,13 @@ const FormSensorHub = ({ onBack }: FormSensorHubProps) => {
</div> </div>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<Grid container spacing={4}> <Grid container spacing={4}>
{error && (
<Grid size={{ xs: 12 }}>
<Alert severity='error' onClose={() => setError(null)}>
{error}
</Alert>
</Grid>
)}
<Grid size={{ xs: 12 }}> <Grid size={{ xs: 12 }}>
<CustomTextField <CustomTextField
fullWidth fullWidth
@@ -59,11 +82,16 @@ const FormSensorHub = ({ onBack }: FormSensorHubProps) => {
/> />
</Grid> </Grid>
<Grid size={{ xs: 12 }} className='flex gap-2'> <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>
<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> </Button>
</Grid> </Grid>
</Grid> </Grid>