Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
thecybernanny-webapp
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
asranov0003
thecybernanny-webapp
Commits
3a26228b
Commit
3a26228b
authored
Jul 29, 2025
by
asranov0003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add data slice
parent
f1d34baa
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
185 additions
and
6 deletions
+185
-6
constants.ts
src/constants/constants.ts
+2
-0
Routes.tsx
src/pages/Routes/Routes.tsx
+90
-6
dataSlice.ts
src/stores/slices/dataSlice.ts
+91
-0
store.ts
src/stores/store.ts
+2
-0
No files found.
src/constants/constants.ts
View file @
3a26228b
export
const
API_URL
=
"https://cabinet.thecybernanny.com/nanny/backend/rpc"
;
// PROD
// export const API_URL = "https://cabinet.dev.thecybernanny.com/nanny/backend/rpc"; // DEV
export
const
GOOGLE_MAPS_API_KEY
=
"AIzaSyABfhzIz1S4kpWvIMtsDD6XIjo2F7r-mTs"
;
export
const
TG_USER_ID
=
window
.
Telegram
.
WebApp
.
initDataUnsafe
?.
user
?.
id
||
0
;
export
const
TOKEN
=
localStorage
.
getItem
(
`token-
${
TG_USER_ID
}
`
)
||
""
;
src/pages/Routes/Routes.tsx
View file @
3a26228b
import
React
from
"react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
"./Routes.css"
;
import
SectionHeader
from
"../../layouts/SectionHeader"
;
import
CButton
from
"../../components/CButton"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
GoogleMapReact
from
"google-map-react"
;
import
{
useAppDispatch
,
useAppSelector
,
type
RootState
,
}
from
"../../stores/store"
;
import
{
getRouteHistory
}
from
"../../stores/slices/dataSlice"
;
const
Routes
:
React
.
FC
=
()
=>
{
const
[
fromDate
,
setFromDate
]
=
useState
(
""
);
const
[
fromTime
,
setFromTime
]
=
useState
(
""
);
const
[
toDate
,
setToDate
]
=
useState
(
""
);
const
[
toTime
,
setToTime
]
=
useState
(
""
);
const
{
selectedDevice
}
=
useAppSelector
((
state
:
RootState
)
=>
state
.
device
);
const
{
routeHistory
,
isRouteHistoryLoading
}
=
useAppSelector
(
(
state
:
RootState
)
=>
state
.
data
);
const
dispatch
=
useAppDispatch
();
const
{
t
}
=
useTranslation
();
useEffect
(()
=>
{
if
(
selectedDevice
)
{
const
now
=
new
Date
();
const
yesterday
=
new
Date
(
now
);
yesterday
.
setDate
(
now
.
getDate
()
-
1
);
setFromDate
(
yesterday
.
toISOString
().
slice
(
0
,
10
));
setFromTime
(
"00:00"
);
setToDate
(
now
.
toISOString
().
slice
(
0
,
10
));
setToTime
(
"23:59"
);
dispatch
(
getRouteHistory
({
deviceId
:
selectedDevice
.
id
,
dateFrom
:
yesterday
,
dateTo
:
now
,
recStart
:
0
,
recLimit
:
1000
,
})
);
}
},
[
dispatch
,
selectedDevice
]);
const
handleSearch
=
()
=>
{
if
(
!
selectedDevice
)
return
;
const
dateFrom
=
new
Date
(
`
${
fromDate
}
T
${
fromTime
}
`
);
const
dateTo
=
new
Date
(
`
${
toDate
}
T
${
toTime
}
`
);
dispatch
(
getRouteHistory
({
deviceId
:
selectedDevice
.
id
,
dateFrom
,
dateTo
,
recStart
:
0
,
recLimit
:
1000
,
})
);
};
useEffect
(()
=>
{
console
.
log
(
"routeHistory"
,
routeHistory
);
},
[
routeHistory
]);
return
(
<
div
className=
"routes wrapper"
>
<
SectionHeader
to=
"/home"
/>
...
...
@@ -28,21 +88,45 @@ const Routes: React.FC = () => {
<
div
className=
"routes__filter__date"
>
<
label
htmlFor=
"from"
>
{
t
(
"common.from"
)
}
</
label
>
<
div
>
<
input
type=
"date"
id=
"from"
/>
<
input
type=
"time"
id=
"from-time"
/>
<
input
type=
"date"
id=
"from"
value=
{
fromDate
}
onChange=
{
(
e
)
=>
setFromDate
(
e
.
target
.
value
)
}
/>
<
input
type=
"time"
id=
"from-time"
value=
{
fromTime
}
onChange=
{
(
e
)
=>
setFromTime
(
e
.
target
.
value
)
}
/>
</
div
>
</
div
>
<
div
className=
"routes__filter__date"
>
<
label
htmlFor=
"to"
>
{
t
(
"common.to"
)
}
</
label
>
<
div
>
<
input
type=
"date"
id=
"to"
/>
<
input
type=
"time"
id=
"to-time"
/>
<
input
type=
"date"
id=
"to"
value=
{
toDate
}
onChange=
{
(
e
)
=>
setToDate
(
e
.
target
.
value
)
}
/>
<
input
type=
"time"
id=
"to-time"
value=
{
toTime
}
onChange=
{
(
e
)
=>
setToTime
(
e
.
target
.
value
)
}
/>
</
div
>
</
div
>
</
div
>
<
CButton
title=
{
t
(
"button.search"
)
}
/>
<
CButton
title=
{
t
(
"button.search"
)
}
onClick=
{
handleSearch
}
isLoading=
{
isRouteHistoryLoading
}
/>
</
div
>
</
div
>
</
div
>
...
...
src/stores/slices/dataSlice.ts
0 → 100644
View file @
3a26228b
import
{
createAsyncThunk
,
createSlice
}
from
"@reduxjs/toolkit"
;
import
{
sendRpcRequest
}
from
"../../services/apiClient"
;
interface
IRouteHistory
{
date
:
string
;
location
:
{
lat
:
string
;
lon
:
string
;
};
}
interface
IDataState
{
routeHistory
:
IRouteHistory
[];
isRouteHistoryLoading
:
boolean
;
routeHistoryError
:
string
|
null
;
}
const
initialState
:
IDataState
=
{
routeHistory
:
[],
isRouteHistoryLoading
:
false
,
routeHistoryError
:
null
,
};
export
const
getRouteHistory
=
createAsyncThunk
(
"data/getRouteHistory"
,
async
(
{
deviceId
,
dateFrom
,
dateTo
,
recStart
=
0
,
recLimit
=
1000
,
}:
{
deviceId
:
string
;
dateFrom
:
Date
;
dateTo
:
Date
;
recStart
?:
number
;
recLimit
?:
number
;
},
{
rejectWithValue
}
)
=>
{
try
{
const
response
=
await
sendRpcRequest
<
{
list
:
IRouteHistory
[]
}
>
(
"data.getroutehistory"
,
{
deviceId
,
dateFrom
,
dateTo
,
recStart
,
recLimit
,
}
);
return
response
.
list
;
}
catch
(
error
:
unknown
)
{
if
(
typeof
error
===
"object"
&&
error
!==
null
&&
"message"
in
error
&&
typeof
error
.
message
===
"string"
)
{
return
rejectWithValue
(
error
.
message
);
}
return
rejectWithValue
(
"Unknown error occurred"
);
}
}
);
const
dataSlice
=
createSlice
({
name
:
"data"
,
initialState
,
reducers
:
{},
extraReducers
:
(
builder
)
=>
{
builder
.
addCase
(
getRouteHistory
.
pending
,
(
state
)
=>
{
state
.
isRouteHistoryLoading
=
true
;
state
.
routeHistoryError
=
null
;
})
.
addCase
(
getRouteHistory
.
fulfilled
,
(
state
,
action
)
=>
{
state
.
isRouteHistoryLoading
=
false
;
state
.
routeHistory
=
action
.
payload
;
})
.
addCase
(
getRouteHistory
.
rejected
,
(
state
,
action
)
=>
{
state
.
isRouteHistoryLoading
=
false
;
state
.
routeHistoryError
=
action
.
payload
as
string
;
});
},
});
export
default
dataSlice
.
reducer
;
src/stores/store.ts
View file @
3a26228b
...
...
@@ -9,6 +9,7 @@ import browserHistorySlice from "./slices/browserHistorySlice";
import
callHistorySlice
from
"./slices/callHistorySlice"
;
import
messengerHistorySlice
from
"./slices/messengerHistorySlice"
;
import
usageLimitSlice
from
"./slices/usageLimitSlice"
;
import
dataSlice
from
"./slices/dataSlice"
;
import
{
useDispatch
,
useSelector
,
...
...
@@ -27,6 +28,7 @@ export const store = configureStore({
callHistory
:
callHistorySlice
,
messengerHistory
:
messengerHistorySlice
,
usageLimit
:
usageLimitSlice
,
data
:
dataSlice
,
},
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment