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
78fc0508
Commit
78fc0508
authored
Jul 30, 2025
by
asranov0003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add cinfo
parent
c8cdb45d
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
140 additions
and
77 deletions
+140
-77
CDeviceSelect.css
src/components/CDeviceSelect/CDeviceSelect.css
+8
-0
CDeviceSelect.tsx
src/components/CDeviceSelect/CDeviceSelect.tsx
+17
-0
CInfo.tsx
src/components/CInfo/CInfo.tsx
+84
-0
index.ts
src/components/CInfo/index.ts
+1
-0
Header.tsx
src/layouts/Header/Header.tsx
+2
-67
SectionHeader.tsx
src/layouts/SectionHeader/SectionHeader.tsx
+28
-10
No files found.
src/components/CDeviceSelect/CDeviceSelect.css
View file @
78fc0508
...
@@ -61,6 +61,14 @@
...
@@ -61,6 +61,14 @@
color
:
var
(
--on-text-color
);
color
:
var
(
--on-text-color
);
}
}
.cdeviceselect-info
{
background
:
var
(
--light-gray-color
);
}
.cdeviceselect-info
:hover
{
background
:
var
(
--light-gray-color
);
}
.cdeviceselect-arrow
{
.cdeviceselect-arrow
{
margin-left
:
auto
;
margin-left
:
auto
;
font-size
:
0.8rem
;
font-size
:
0.8rem
;
...
...
src/components/CDeviceSelect/CDeviceSelect.tsx
View file @
78fc0508
...
@@ -2,6 +2,8 @@ import React, { useEffect, useRef, useState } from "react";
...
@@ -2,6 +2,8 @@ import React, { useEffect, useRef, useState } from "react";
import
"./CDeviceSelect.css"
;
import
"./CDeviceSelect.css"
;
import
type
{
CDeviceSelectProps
}
from
"./CDeviceSelect.types"
;
import
type
{
CDeviceSelectProps
}
from
"./CDeviceSelect.types"
;
import
{
FaChevronDown
,
FaChevronUp
}
from
"react-icons/fa"
;
import
{
FaChevronDown
,
FaChevronUp
}
from
"react-icons/fa"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
CInfo
from
"../CInfo"
;
const
CDeviceSelect
:
React
.
FC
<
CDeviceSelectProps
>
=
({
const
CDeviceSelect
:
React
.
FC
<
CDeviceSelectProps
>
=
({
devices
,
devices
,
...
@@ -13,7 +15,9 @@ const CDeviceSelect: React.FC<CDeviceSelectProps> = ({
...
@@ -13,7 +15,9 @@ const CDeviceSelect: React.FC<CDeviceSelectProps> = ({
placeholder
=
"Select Device"
,
placeholder
=
"Select Device"
,
})
=>
{
})
=>
{
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
isOpenInfoModal
,
setIsOpenInfoModal
]
=
useState
(
false
);
const
ref
=
useRef
<
HTMLDivElement
>
(
null
);
const
ref
=
useRef
<
HTMLDivElement
>
(
null
);
const
{
t
}
=
useTranslation
();
useEffect
(()
=>
{
useEffect
(()
=>
{
const
handleClickOutside
=
(
e
:
MouseEvent
)
=>
{
const
handleClickOutside
=
(
e
:
MouseEvent
)
=>
{
...
@@ -25,6 +29,10 @@ const CDeviceSelect: React.FC<CDeviceSelectProps> = ({
...
@@ -25,6 +29,10 @@ const CDeviceSelect: React.FC<CDeviceSelectProps> = ({
return
()
=>
document
.
removeEventListener
(
"mousedown"
,
handleClickOutside
);
return
()
=>
document
.
removeEventListener
(
"mousedown"
,
handleClickOutside
);
},
[]);
},
[]);
const
toggleInfoModal
=
()
=>
{
setIsOpenInfoModal
((
prev
)
=>
!
prev
);
};
return
(
return
(
<>
<>
<
div
<
div
...
@@ -59,9 +67,18 @@ const CDeviceSelect: React.FC<CDeviceSelectProps> = ({
...
@@ -59,9 +67,18 @@ const CDeviceSelect: React.FC<CDeviceSelectProps> = ({
<
span
>
{
device
.
name
}
</
span
>
<
span
>
{
device
.
name
}
</
span
>
</
div
>
</
div
>
))
}
))
}
<
div
className=
"cdeviceselect-option cdeviceselect-info"
onClick=
{
toggleInfoModal
}
>
<
span
>
{
t
(
"help.howToStart"
)
}
</
span
>
</
div
>
</
div
>
</
div
>
)
}
)
}
</
div
>
</
div
>
<
CInfo
isOpen=
{
isOpenInfoModal
}
onToggle=
{
toggleInfoModal
}
/>
</>
</>
);
);
};
};
...
...
src/components/CInfo/CInfo.tsx
0 → 100644
View file @
78fc0508
import
React
from
"react"
;
import
CModal
from
"../CModal"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
CButton
from
"../CButton"
;
interface
CInfoProps
{
isOpen
:
boolean
;
onToggle
:
()
=>
void
;
}
const
CInfo
:
React
.
FC
<
CInfoProps
>
=
({
isOpen
,
onToggle
})
=>
{
const
{
t
}
=
useTranslation
();
const
share
=
()
=>
{
const
message
=
"https://t.me/CyberNannyAppBot"
;
if
(
window
.
Telegram
?.
WebApp
?.
openTelegramLink
)
{
window
.
Telegram
.
WebApp
.
openTelegramLink
(
`https://t.me/share/url?url=
${
encodeURIComponent
(
message
)}
`
);
}
};
return
(
<
CModal
isOpen=
{
isOpen
}
onToggle=
{
onToggle
}
content=
{
<
div
className=
"modal__box"
>
<
h3
className=
"modal__box__title"
>
{
t
(
"help.howToStart"
)
}
</
h3
>
<
div
>
<
h4
>
{
t
(
"help.parentPhone"
)
}
</
h4
>
<
p
>
{
t
(
"help.parentPhoneDesc1"
)
}
</
p
>
<
p
>
{
t
(
"help.parentPhoneDesc2"
)
}
</
p
>
<
p
>
{
t
(
"help.parentPhoneDesc3"
)
}
</
p
>
</
div
>
<
div
>
<
h4
>
{
t
(
"help.childPhone"
)
}
</
h4
>
<
p
>
{
t
(
"help.childPhoneDesc1"
)
}
</
p
>
<
p
>
{
t
(
"help.childPhoneDesc2"
)
}
</
p
>
<
p
>
{
t
(
"help.childPhoneDesc3"
)
}
</
p
>
</
div
>
<
br
/>
<
p
>
{
t
(
"help.howToStartDesc"
)
}
</
p
>
<
a
href=
"https://apps.apple.com/uz/app/%D0%BA%D0%B8%D0%B1%D0%B5%D1%80%D0%BD%D1%8F%D0%BD%D1%8F/id6740760058"
target=
"_blank"
rel=
"noopener noreferrer"
>
{
t
(
"common.downloadForIos"
)
}
</
a
>
<
a
href=
"https://play.google.com/store/apps/details?id=com.thecybernanny.adroapp"
target=
"_blank"
rel=
"noopener noreferrer"
>
{
t
(
"common.downloadForAndroid"
)
}
</
a
>
<
div
className=
"modal__box__actions"
>
<
CButton
title=
{
t
(
"button.share"
)
}
variant=
"primary"
onClick=
{
share
}
/>
<
CButton
title=
{
t
(
"button.ok"
)
}
onClick=
{
onToggle
}
variant=
"primary"
/>
</
div
>
</
div
>
}
/>
);
};
export
default
CInfo
;
src/components/CInfo/index.ts
0 → 100644
View file @
78fc0508
export
{
default
}
from
"./CInfo"
;
src/layouts/Header/Header.tsx
View file @
78fc0508
...
@@ -27,7 +27,7 @@ import CDeviceSelect from "../../components/CDeviceSelect";
...
@@ -27,7 +27,7 @@ import CDeviceSelect from "../../components/CDeviceSelect";
import
{
logout
}
from
"../../stores/slices/authSlice"
;
import
{
logout
}
from
"../../stores/slices/authSlice"
;
import
TheCybernanny
from
"../../assets/images/TheCybernanny.png"
;
import
TheCybernanny
from
"../../assets/images/TheCybernanny.png"
;
import
CButton
from
"../../components/CButton"
;
import
CButton
from
"../../components/CButton"
;
import
C
Modal
from
"../../components/CModal
"
;
import
C
Info
from
"../../components/CInfo
"
;
const
Header
:
React
.
FC
=
()
=>
{
const
Header
:
React
.
FC
=
()
=>
{
const
[
isSidebarOpen
,
setIsSidebarOpen
]
=
useState
(
false
);
const
[
isSidebarOpen
,
setIsSidebarOpen
]
=
useState
(
false
);
...
@@ -60,16 +60,6 @@ const Header: React.FC = () => {
...
@@ -60,16 +60,6 @@ const Header: React.FC = () => {
setIsOpenInfoModal
((
prev
)
=>
!
prev
);
setIsOpenInfoModal
((
prev
)
=>
!
prev
);
};
};
const
share
=
()
=>
{
const
message
=
"https://t.me/CyberNannyAppBot"
;
if
(
window
.
Telegram
?.
WebApp
?.
openTelegramLink
)
{
window
.
Telegram
.
WebApp
.
openTelegramLink
(
`https://t.me/share/url?url=
${
encodeURIComponent
(
message
)}
`
);
}
};
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
isSidebarOpen
)
{
if
(
isSidebarOpen
)
{
document
.
addEventListener
(
"mousedown"
,
handleOutsideClick
);
document
.
addEventListener
(
"mousedown"
,
handleOutsideClick
);
...
@@ -207,62 +197,7 @@ const Header: React.FC = () => {
...
@@ -207,62 +197,7 @@ const Header: React.FC = () => {
</
div
>
</
div
>
)
}
)
}
<
CModal
<
CInfo
isOpen=
{
isOpenInfoModal
}
onToggle=
{
toggleInfoModal
}
/>
isOpen=
{
isOpenInfoModal
}
onToggle=
{
toggleInfoModal
}
content=
{
<
div
className=
"modal__box"
>
<
h3
className=
"modal__box__title"
>
{
t
(
"help.howToStart"
)
}
</
h3
>
<
div
>
<
h4
>
{
t
(
"help.parentPhone"
)
}
</
h4
>
<
p
>
{
t
(
"help.parentPhoneDesc1"
)
}
</
p
>
<
p
>
{
t
(
"help.parentPhoneDesc2"
)
}
</
p
>
<
p
>
{
t
(
"help.parentPhoneDesc3"
)
}
</
p
>
</
div
>
<
div
>
<
h4
>
{
t
(
"help.childPhone"
)
}
</
h4
>
<
p
>
{
t
(
"help.childPhoneDesc1"
)
}
</
p
>
<
p
>
{
t
(
"help.childPhoneDesc2"
)
}
</
p
>
<
p
>
{
t
(
"help.childPhoneDesc3"
)
}
</
p
>
</
div
>
<
br
/>
<
p
>
{
t
(
"help.howToStartDesc"
)
}
</
p
>
<
a
href=
"https://apps.apple.com/uz/app/%D0%BA%D0%B8%D0%B1%D0%B5%D1%80%D0%BD%D1%8F%D0%BD%D1%8F/id6740760058"
target=
"_blank"
rel=
"noopener noreferrer"
>
{
t
(
"common.downloadForIos"
)
}
</
a
>
<
a
href=
"https://play.google.com/store/apps/details?id=com.thecybernanny.adroapp"
target=
"_blank"
rel=
"noopener noreferrer"
>
{
t
(
"common.downloadForAndroid"
)
}
</
a
>
<
div
className=
"modal__box__actions"
>
<
CButton
title=
{
t
(
"button.share"
)
}
variant=
"primary"
onClick=
{
share
}
/>
<
CButton
title=
{
t
(
"button.ok"
)
}
onClick=
{
toggleInfoModal
}
variant=
"primary"
/>
</
div
>
</
div
>
}
/>
</>
</>
);
);
};
};
...
...
src/layouts/SectionHeader/SectionHeader.tsx
View file @
78fc0508
import
React
from
"react"
;
import
React
,
{
useState
}
from
"react"
;
import
"./SectionHeader.css"
;
import
"./SectionHeader.css"
;
import
{
Link
,
useNavigate
}
from
"react-router-dom"
;
import
{
Link
,
useNavigate
}
from
"react-router-dom"
;
import
{
import
{
...
@@ -10,12 +10,15 @@ import CDeviceSelect from "../../components/CDeviceSelect";
...
@@ -10,12 +10,15 @@ import CDeviceSelect from "../../components/CDeviceSelect";
import
{
setSelectedDevice
}
from
"../../stores/slices/deviceSlice"
;
import
{
setSelectedDevice
}
from
"../../stores/slices/deviceSlice"
;
import
{
BiArrowBack
}
from
"react-icons/bi"
;
import
{
BiArrowBack
}
from
"react-icons/bi"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
CButton
from
"../../components/CButton"
;
import
CInfo
from
"../../components/CInfo"
;
interface
SectionHeaderProps
{
interface
SectionHeaderProps
{
to
?:
string
;
to
?:
string
;
}
}
const
SectionHeader
:
React
.
FC
<
SectionHeaderProps
>
=
({
to
})
=>
{
const
SectionHeader
:
React
.
FC
<
SectionHeaderProps
>
=
({
to
})
=>
{
const
[
isOpenInfoModal
,
setIsOpenInfoModal
]
=
useState
(
false
);
const
{
devices
,
selectedDevice
}
=
useAppSelector
(
const
{
devices
,
selectedDevice
}
=
useAppSelector
(
(
state
:
RootState
)
=>
state
.
device
(
state
:
RootState
)
=>
state
.
device
);
);
...
@@ -30,6 +33,10 @@ const SectionHeader: React.FC<SectionHeaderProps> = ({ to }) => {
...
@@ -30,6 +33,10 @@ const SectionHeader: React.FC<SectionHeaderProps> = ({ to }) => {
}
}
};
};
const
toggleInfoModal
=
()
=>
{
setIsOpenInfoModal
((
prev
)
=>
!
prev
);
};
return
(
return
(
<
div
className=
"sectionheader"
>
<
div
className=
"sectionheader"
>
<
Link
<
Link
...
@@ -40,15 +47,26 @@ const SectionHeader: React.FC<SectionHeaderProps> = ({ to }) => {
...
@@ -40,15 +47,26 @@ const SectionHeader: React.FC<SectionHeaderProps> = ({ to }) => {
<
BiArrowBack
className=
"sectionheader__link__icon"
/>
<
BiArrowBack
className=
"sectionheader__link__icon"
/>
</
Link
>
</
Link
>
<
CDeviceSelect
{
devices
.
length
>
0
?
(
devices=
{
devices
}
<
CDeviceSelect
selectedDevice=
{
selectedDevice
}
devices=
{
devices
}
onDeviceChange=
{
(
name
)
=>
dispatch
(
setSelectedDevice
(
name
))
}
selectedDevice=
{
selectedDevice
}
disabled=
{
!
devices
.
length
}
onDeviceChange=
{
(
name
)
=>
dispatch
(
setSelectedDevice
(
name
))
}
style=
{
{
width
:
"220px"
}
}
disabled=
{
!
devices
.
length
}
className=
"header__device-select"
style=
{
{
width
:
"220px"
}
}
placeholder=
{
t
(
"common.selectDevice"
)
}
className=
"header__device-select"
/>
placeholder=
{
t
(
"common.selectDevice"
)
}
/>
)
:
(
<
CButton
title=
{
t
(
"help.howToStart"
)
}
onClick=
{
toggleInfoModal
}
variant=
"primary"
style=
{
{
width
:
"114.66px"
}
}
/>
)
}
<
CInfo
isOpen=
{
isOpenInfoModal
}
onToggle=
{
toggleInfoModal
}
/>
</
div
>
</
div
>
);
);
};
};
...
...
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