mirror of
https://github.com/vernu/textbee.git
synced 2026-05-06 14:43:32 -04:00
feat(web): improve dashboard stats
This commit is contained in:
@@ -1,15 +1,27 @@
|
||||
import { Box, SimpleGrid, chakra } from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { selectApiKeyList } from '../../store/apiKeySlice'
|
||||
import { selectAuthUser } from '../../store/authSlice'
|
||||
import { selectDeviceList } from '../../store/deviceSlice'
|
||||
import UserStatsCard from './UserStatsCard'
|
||||
import {
|
||||
fetchStats,
|
||||
selectStatsData,
|
||||
selectStatsLoading,
|
||||
} from '../../store/statsSlice'
|
||||
import { useAppDispatch, useAppSelector } from '../../store/hooks'
|
||||
|
||||
const UserStats = () => {
|
||||
const authUser = useSelector(selectAuthUser)
|
||||
const deviceList = useSelector(selectDeviceList)
|
||||
const apiKeyList = useSelector(selectApiKeyList)
|
||||
|
||||
const { totalApiKeyCount, totalDeviceCount, totalSMSCount } =
|
||||
useAppSelector(selectStatsData)
|
||||
const statsLoading = useAppSelector(selectStatsLoading)
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchStats())
|
||||
}, [dispatch])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -26,13 +38,16 @@ const UserStats = () => {
|
||||
<SimpleGrid columns={{ base: 3 }} spacing={{ base: 5, lg: 8 }}>
|
||||
<UserStatsCard
|
||||
title={'Registered '}
|
||||
stat={`${deviceList?.length || '-:-'} Devices`}
|
||||
stat={`${statsLoading ? '-:-' : totalDeviceCount} Devices`}
|
||||
/>
|
||||
<UserStatsCard
|
||||
title={'Generated'}
|
||||
stat={`${apiKeyList?.length || '-:-'} API Keys`}
|
||||
stat={`${statsLoading ? '-:-' : totalApiKeyCount} API Keys`}
|
||||
/>
|
||||
<UserStatsCard
|
||||
title={'Sent'}
|
||||
stat={`${statsLoading ? '-:-' : totalSMSCount} SMS Sent`}
|
||||
/>
|
||||
<UserStatsCard title={'Sent'} stat={'-:- SMS'} />
|
||||
</SimpleGrid>
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
|
||||
10
web/services/statsService.ts
Normal file
10
web/services/statsService.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import httpClient from '../lib/httpClient'
|
||||
|
||||
class StatsService {
|
||||
async getStats() {
|
||||
const res = await httpClient.get(`/gateway/stats`)
|
||||
return res.data.data
|
||||
}
|
||||
}
|
||||
|
||||
export const statsService = new StatsService()
|
||||
56
web/store/statsSlice.ts
Normal file
56
web/store/statsSlice.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { createAsyncThunk, createSlice, isAnyOf } from '@reduxjs/toolkit'
|
||||
import type { PayloadAction } from '@reduxjs/toolkit'
|
||||
import { createStandaloneToast } from '@chakra-ui/react'
|
||||
import { RootState } from './store'
|
||||
import { statsService } from '../services/statsService'
|
||||
|
||||
const { toast } = createStandaloneToast()
|
||||
|
||||
const initialState = {
|
||||
loading: false,
|
||||
data: {
|
||||
totalApiKeyCount: 0,
|
||||
totalDeviceCount: 0,
|
||||
totalSMSCount: 0,
|
||||
},
|
||||
}
|
||||
|
||||
export const fetchStats = createAsyncThunk(
|
||||
'gateway/fetchStats',
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const res = await statsService.getStats()
|
||||
return res
|
||||
} catch (e) {
|
||||
toast({
|
||||
title: e.response.data.error || 'Failed to Fetch stats',
|
||||
status: 'error',
|
||||
})
|
||||
return rejectWithValue(e.response.data)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export const statsSlice = createSlice({
|
||||
name: 'stats',
|
||||
initialState,
|
||||
reducers: {},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(fetchStats.fulfilled, (state, action: PayloadAction<any>) => {
|
||||
state.loading = false
|
||||
state.data = action.payload
|
||||
})
|
||||
.addCase(fetchStats.rejected, (state) => {
|
||||
state.loading = false
|
||||
})
|
||||
.addMatcher(isAnyOf(fetchStats.pending), (state) => {
|
||||
state.loading = true
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const selectStatsLoading = (state: RootState) => state.stats.loading
|
||||
export const selectStatsData = (state: RootState) => state.stats.data
|
||||
|
||||
export default statsSlice.reducer
|
||||
@@ -2,12 +2,14 @@ import { configureStore } from '@reduxjs/toolkit'
|
||||
import apiKeyReducer from './apiKeySlice'
|
||||
import authReducer from './authSlice'
|
||||
import deviceReducer from './deviceSlice'
|
||||
import statsReducer from './statsSlice'
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
auth: authReducer,
|
||||
apiKey: apiKeyReducer,
|
||||
device: deviceReducer,
|
||||
stats: statsReducer,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user