15 changed files with 342 additions and 37 deletions
-
2web/components/Navbar.tsx
-
65web/components/dashboard/ApiKeyList.tsx
-
95web/components/dashboard/DeviceList.tsx
-
5web/components/dashboard/GenerateApiKey.tsx
-
2web/components/dashboard/UserStats.tsx
-
29web/pages/dashboard/index.tsx
-
2web/pages/index.tsx
-
2web/pages/login.tsx
-
2web/pages/register.tsx
-
20web/services/index.ts
-
21web/services/types.ts
-
61web/store/apiKeyListReducer.ts
-
4web/store/authReducer.ts
-
61web/store/deviceListReducer.ts
-
8web/store/store.ts
@ -0,0 +1,95 @@ |
|||
import { DeleteIcon, EmailIcon } from '@chakra-ui/icons' |
|||
import { |
|||
IconButton, |
|||
Spinner, |
|||
Table, |
|||
TableContainer, |
|||
Tbody, |
|||
Td, |
|||
Th, |
|||
Thead, |
|||
Tooltip, |
|||
Tr, |
|||
} from '@chakra-ui/react' |
|||
import { useEffect } from 'react' |
|||
import { useDispatch, useSelector } from 'react-redux' |
|||
import { sendSMSRequest } from '../../services' |
|||
import { selectAuth } from '../../store/authReducer' |
|||
import { |
|||
fetchDeviceList, |
|||
selectDeviceList, |
|||
} from '../../store/deviceListReducer' |
|||
|
|||
const DeviceList = () => { |
|||
const dispatch = useDispatch() |
|||
|
|||
const { user, accessToken } = useSelector(selectAuth) |
|||
useEffect(() => { |
|||
if (user && accessToken) { |
|||
dispatch(fetchDeviceList()) |
|||
} |
|||
}, [user, accessToken, dispatch]) |
|||
|
|||
const { data, loading } = useSelector(selectDeviceList) |
|||
|
|||
const onDelete = (apiKeyId: string) => {} |
|||
|
|||
return ( |
|||
<TableContainer> |
|||
<Table variant='simple'> |
|||
<Thead> |
|||
<Tr> |
|||
<Th>Your Devices</Th> |
|||
<Th>Status</Th> |
|||
<Th colSpan={2}>Actions</Th> |
|||
</Tr> |
|||
</Thead> |
|||
<Tbody> |
|||
{loading ? ( |
|||
<Tr> |
|||
<Td colSpan={3} textAlign='center'> |
|||
<Spinner size='lg' /> |
|||
</Td> |
|||
</Tr> |
|||
) : ( |
|||
<> |
|||
{data.length === 0 ? ( |
|||
<Tr> |
|||
<Td colSpan={3} textAlign='center'> |
|||
No Devices |
|||
</Td> |
|||
</Tr> |
|||
) : ( |
|||
data.map(({ _id, brand, model, enabled, createdAt }) => ( |
|||
<Tr key={_id}> |
|||
<Td>{`${brand}/ ${model}`}</Td> |
|||
<Td>{enabled ? 'enabled' : 'disabled'}</Td> |
|||
<Td> |
|||
<EmailIcon onDoubleClick={(e) => {}} /> |
|||
</Td> |
|||
<Td> |
|||
<Tooltip label='Double Click to delete'> |
|||
<IconButton |
|||
aria-label='Delete' |
|||
icon={<DeleteIcon />} |
|||
onDoubleClick={(e) => { |
|||
sendSMSRequest(_id, { |
|||
receivers: ['+251912657519'], |
|||
smsBody: 'Hello World', |
|||
}) |
|||
}} |
|||
/> |
|||
</Tooltip> |
|||
</Td> |
|||
</Tr> |
|||
)) |
|||
)} |
|||
</> |
|||
)} |
|||
</Tbody> |
|||
</Table> |
|||
</TableContainer> |
|||
) |
|||
} |
|||
|
|||
export default DeviceList |
|||
@ -0,0 +1,61 @@ |
|||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' |
|||
import type { PayloadAction } from '@reduxjs/toolkit' |
|||
import { getApiKeyListRequest } from '../services' |
|||
import { createStandaloneToast } from '@chakra-ui/react' |
|||
import { RootState } from './store' |
|||
|
|||
const toast = createStandaloneToast() |
|||
|
|||
const initialState = { |
|||
loading: false, |
|||
data: [], |
|||
} |
|||
|
|||
export const fetchApiKeyList = createAsyncThunk( |
|||
'apiKeyList/fetchApiKeys', |
|||
async (payload, thunkAPI) => { |
|||
try { |
|||
const res = await getApiKeyListRequest() |
|||
return res |
|||
} catch (e) { |
|||
toast({ |
|||
title: e.response.data.error || 'Failed to Fetch apiKeys', |
|||
status: 'error', |
|||
}) |
|||
return thunkAPI.rejectWithValue(e.response.data) |
|||
} |
|||
} |
|||
) |
|||
|
|||
export const apiKeyListSlice = createSlice({ |
|||
name: 'apiKeyList', |
|||
initialState, |
|||
reducers: { |
|||
clearApiKeyList: (state) => { |
|||
state.loading = false |
|||
state.data = [] |
|||
}, |
|||
}, |
|||
extraReducers: (builder) => { |
|||
builder |
|||
.addCase(fetchApiKeyList.pending, (state) => { |
|||
state.loading = true |
|||
}) |
|||
.addCase( |
|||
fetchApiKeyList.fulfilled, |
|||
(state, action: PayloadAction<any>) => { |
|||
state.loading = false |
|||
state.data = action.payload |
|||
} |
|||
) |
|||
.addCase(fetchApiKeyList.rejected, (state) => { |
|||
state.loading = false |
|||
}) |
|||
}, |
|||
}) |
|||
|
|||
export const { clearApiKeyList } = apiKeyListSlice.actions |
|||
|
|||
export const selectApiKeyList = (state: RootState) => state.apiKeyList |
|||
|
|||
export default apiKeyListSlice.reducer |
|||
@ -0,0 +1,61 @@ |
|||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' |
|||
import type { PayloadAction } from '@reduxjs/toolkit' |
|||
import { getDeviceListRequest } from '../services' |
|||
import { createStandaloneToast } from '@chakra-ui/react' |
|||
import { RootState } from './store' |
|||
|
|||
const toast = createStandaloneToast() |
|||
|
|||
const initialState = { |
|||
loading: false, |
|||
data: [], |
|||
} |
|||
|
|||
export const fetchDeviceList = createAsyncThunk( |
|||
'deviceList/fetchDevices', |
|||
async (payload, thunkAPI) => { |
|||
try { |
|||
const res = await getDeviceListRequest() |
|||
return res |
|||
} catch (e) { |
|||
toast({ |
|||
title: e.response.data.error || 'Failed to Fetch devices', |
|||
status: 'error', |
|||
}) |
|||
return thunkAPI.rejectWithValue(e.response.data) |
|||
} |
|||
} |
|||
) |
|||
|
|||
export const deviceListSlice = createSlice({ |
|||
name: 'deviceList', |
|||
initialState, |
|||
reducers: { |
|||
clearDeviceList: (state) => { |
|||
state.loading = false |
|||
state.data = [] |
|||
}, |
|||
}, |
|||
extraReducers: (builder) => { |
|||
builder |
|||
.addCase(fetchDeviceList.pending, (state) => { |
|||
state.loading = true |
|||
}) |
|||
.addCase( |
|||
fetchDeviceList.fulfilled, |
|||
(state, action: PayloadAction<any>) => { |
|||
state.loading = false |
|||
state.data = action.payload |
|||
} |
|||
) |
|||
.addCase(fetchDeviceList.rejected, (state) => { |
|||
state.loading = false |
|||
}) |
|||
}, |
|||
}) |
|||
|
|||
export const { clearDeviceList } = deviceListSlice.actions |
|||
|
|||
export const selectDeviceList = (state: RootState) => state.deviceList |
|||
|
|||
export default deviceListSlice.reducer |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue