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
c2f610c4
Commit
c2f610c4
authored
Jul 14, 2025
by
asranov0003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add permissions page
parent
dcfa5d70
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
257 additions
and
3 deletions
+257
-3
App.tsx
src/App.tsx
+12
-1
en.json
src/locales/en/en.json
+29
-0
ru.json
src/locales/ru/ru.json
+29
-0
Permissions.css
src/pages/Permissions/Permissions.css
+41
-0
Permissions.tsx
src/pages/Permissions/Permissions.tsx
+146
-2
No files found.
src/App.tsx
View file @
c2f610c4
import
React
from
"react"
;
import
React
,
{
useEffect
}
from
"react"
;
import
Router
from
"./routes/Router"
;
import
useTelegramExpand
from
"./hooks/useTelegramExpand"
;
import
{
TG_USER_ID
}
from
"./constants/constants"
;
import
{
useAppDispatch
}
from
"./stores/store"
;
import
{
fetchDevices
}
from
"./stores/slices/deviceSlice"
;
const
App
:
React
.
FC
=
()
=>
{
const
dispatch
=
useAppDispatch
();
useTelegramExpand
();
useEffect
(()
=>
{
if
(
localStorage
.
getItem
(
`token-
${
TG_USER_ID
}
`
))
{
dispatch
(
fetchDevices
());
}
},
[
dispatch
]);
return
<
Router
/>;
};
...
...
src/locales/en/en.json
View file @
c2f610c4
{
"common"
:
{
"yes"
:
"Yes"
,
"no"
:
"No"
,
"granted"
:
"Granted"
,
"denied"
:
"Denied"
},
"auth"
:
{
"entrance"
:
"Sign In"
,
"login"
:
"Login"
,
...
...
@@ -64,6 +70,29 @@
"recoverPassword"
:
"Recover password"
,
"logout"
:
"Logout"
},
"permissions"
:
{
"title"
:
"Permissions"
,
"installedApp"
:
"Installed apps"
,
"installedAppDescription"
:
"Given access to collect data about the apps installed on the phone"
,
"microphone"
:
"Microphone"
,
"microphoneDescription"
:
"Allow you to record the surroundings of your child's device"
,
"acctivity"
:
"Activity Recognition"
,
"activityDescription"
:
"Allows you to track your child's activity"
,
"location"
:
"Location"
,
"locationDescription"
:
"The app will collect your child's location, even while it is closed"
,
"accessibility"
:
"Accessibility"
,
"accessibilityDesctiption"
:
"This permission allows you to block unwanted apps and websites, and set screeen time limits"
,
"systemAlert"
:
"Draw Over Apps"
,
"systemAlertDescription"
:
"This permission is necessary to control access and allow only permitted apps."
,
"batteryOptimization"
:
"Battery Optimization"
,
"batteryOptimizationDescription"
:
"Battery optimization should be turn off to allow this app to work in the background"
,
"deviceAdmin"
:
"Device Admin"
,
"deviceAdminDescription"
:
"Admin rights are necessary to block the device and protect it from being deleted"
,
"notifications"
:
"Notifications"
,
"notificationsDescription"
:
"Necessary to show notifications"
,
"phoneState"
:
"Phone State"
,
"phoneStateDescription"
:
"This allows you to know the state of the child's phone, e.g., battery charge"
},
"pincode"
:
{
"enterTitle"
:
"Enter your PIN Code"
,
"createTitle"
:
"Create your PIN Code"
,
...
...
src/locales/ru/ru.json
View file @
c2f610c4
{
"common"
:
{
"yes"
:
"Да"
,
"no"
:
"Нет"
,
"granted"
:
"Вкл"
,
"denied"
:
"Выкл"
},
"auth"
:
{
"entrance"
:
"Вход"
,
"login"
:
"Логин"
,
...
...
@@ -64,6 +70,29 @@
"recoverPassword"
:
"Восстановить пароль"
,
"logout"
:
"Выйти"
},
"permissions"
:
{
"title"
:
"Разрешения"
,
"installedApp"
:
"Установленные приложения"
,
"installedAppDescription"
:
"Предоставляет доступ к сбору данных о приложениях, установленных на телефоне."
,
"microphone"
:
"Микрофон"
,
"microphoneDescription"
:
"Позволяет записывать окружающие звуки устройства вашего ребенка."
,
"activity"
:
"Распознавание активности"
,
"activityDescription"
:
"Позволяет отслеживать активность вашего ребенка."
,
"location"
:
"Местоположение"
,
"locationDescription"
:
"Приложение будет собирать данные о местоположении ребенка, даже если оно закрыто."
,
"accessibility"
:
"Службы доступности"
,
"accessibilityDesctiption"
:
"Это разрешение позволяет блокировать нежелательные приложения и сайты, а также устанавливать лимиты экранного времени."
,
"systemAlert"
:
"Наложение окон"
,
"systemAlertDescription"
:
"Это разрешение необходимо для контроля доступа и допуска только к разрешенным приложениям."
,
"batteryOptimization"
:
"Оптимизация батареи"
,
"batteryOptimizationDescription"
:
"Оптимизацию батареи следует отключить, чтобы приложение могло работать в фоновом режиме."
,
"deviceAdmin"
:
"Права администратора"
,
"deviceAdminDescription"
:
"Права администратора необходимы для блокировки устройства и защиты от удаления."
,
"notifications"
:
"Уведомления"
,
"notificationsDescription"
:
"Необходимо для отображения уведомлений."
,
"phoneState"
:
"Состояние телефона"
,
"phoneStateDescription"
:
"Позволяет узнать состояние телефона ребенка, например уровень заряда батареи."
},
"pincode"
:
{
"enterTitle"
:
"Введите PIN-код"
,
"createTitle"
:
"Создайте PIN-код"
,
...
...
src/pages/Permissions/Permissions.css
View file @
c2f610c4
.permissions__content
{
display
:
flex
;
flex-direction
:
column
;
gap
:
1rem
;
}
.permissions__content__items
{
display
:
flex
;
flex-direction
:
column
;
gap
:
0.5rem
;
}
.permissions__content__item
{
display
:
flex
;
flex-direction
:
column
;
padding
:
1rem
;
background
:
var
(
--content-bg-color
);
border-radius
:
10px
;
}
.permissions__content__item__header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
.permissions__content__item__header
div
{
display
:
flex
;
align-items
:
center
;
gap
:
0.5rem
;
}
.permissions__content__item__header
div
p
{
font-weight
:
bold
;
}
.permission__content__item__desc
{
font-size
:
0.875rem
;
margin-top
:
0.5rem
;
}
\ No newline at end of file
src/pages/Permissions/Permissions.tsx
View file @
c2f610c4
import
React
from
"react"
;
import
React
,
{
useEffect
,
useState
,
type
ReactNode
}
from
"react"
;
import
"./Permissions.css"
;
import
SectionHeader
from
"../../layouts/SectionHeader"
;
import
{
useAppSelector
,
type
RootState
}
from
"../../stores/store"
;
import
{
IoAccessibilitySharp
,
IoApps
,
IoBatteryHalfOutline
,
IoCopyOutline
,
IoPhonePortraitOutline
,
IoWalkSharp
,
}
from
"react-icons/io5"
;
import
{
FaMicrophone
,
FaUser
}
from
"react-icons/fa"
;
import
{
FaLocationDot
}
from
"react-icons/fa6"
;
import
{
IoMdNotifications
}
from
"react-icons/io"
;
import
{
useTranslation
}
from
"react-i18next"
;
interface
IPermission
{
id
:
string
;
title
:
string
;
description
:
string
;
icon
:
ReactNode
;
permission
:
string
;
isGranted
:
boolean
;
}
const
Permissions
:
React
.
FC
=
()
=>
{
return
<
div
>
Permissions
</
div
>;
const
[
permissions
,
setPermissions
]
=
useState
<
IPermission
[]
>
([]);
const
{
selectedDevice
}
=
useAppSelector
((
state
:
RootState
)
=>
state
.
device
);
const
{
t
}
=
useTranslation
();
const
permissionMeta
:
Record
<
string
,
{
title
:
string
;
description
:
string
;
icon
:
ReactNode
}
>
=
{
INSTALLED_APPS
:
{
title
:
t
(
"permissions.installedApp"
),
description
:
t
(
"permissions.installedAppDescription"
),
icon
:
<
IoApps
className=
"permission__icon"
/>,
},
RECORD_AUDIO
:
{
title
:
t
(
"permissions.microphone"
),
description
:
t
(
"permissions.microphoneDescription"
),
icon
:
<
FaMicrophone
className=
"permission__icon"
/>,
},
ACTIVITY_RECOGNITION
:
{
title
:
t
(
"permissions.activity"
),
description
:
t
(
"permissions.activityDescription"
),
icon
:
<
IoWalkSharp
className=
"permission__icon"
/>,
},
BACKGROUND_LOCATION
:
{
title
:
t
(
"permissions.location"
),
description
:
t
(
"permissions.locationDescription"
),
icon
:
<
FaLocationDot
className=
"permission__icon"
/>,
},
ACCESSIBILITY_SERVICE
:
{
title
:
t
(
"permissions.accessibility"
),
description
:
t
(
"permissions.accessibilityDescription"
),
icon
:
<
IoAccessibilitySharp
className=
"permission__icon"
/>,
},
SYSTEM_ALERT_WINDOW
:
{
title
:
t
(
"permissions.systemAlert"
),
description
:
t
(
"permissions.systemAlertDescription"
),
icon
:
<
IoCopyOutline
className=
"permission__icon"
/>,
},
IGNORE_BATTERY_OPTIMIZATIONS
:
{
title
:
t
(
"permissions.batteryOptimization"
),
description
:
t
(
"permissions.batteryOptimizationDescription"
),
icon
:
<
IoBatteryHalfOutline
className=
"permission__icon"
/>,
},
DEVICE_ADMIN
:
{
title
:
t
(
"permissions.deviceAdmin"
),
description
:
t
(
"permissions.deviceAdminDescription"
),
icon
:
<
FaUser
className=
"permission__icon"
/>,
},
POST_NOTIFICATIONS
:
{
title
:
t
(
"permissions.notifications"
),
description
:
t
(
"permissions.notificationsDescription"
),
icon
:
<
IoMdNotifications
className=
"permission__icon"
/>,
},
READ_PHONE_STATE
:
{
title
:
t
(
"permissions.phoneState"
),
description
:
t
(
"permissions.phoneStateDescription"
),
icon
:
<
IoPhonePortraitOutline
className=
"permission__icon"
/>,
},
};
useEffect
(()
=>
{
if
(
!
selectedDevice
?.
deviceInfo
?.
permissions
)
return
;
const
updatedPermissions
:
IPermission
[]
=
selectedDevice
.
deviceInfo
.
permissions
.
map
((
perm
,
index
)
=>
{
const
meta
=
permissionMeta
[
perm
.
permission
]
||
{
title
:
perm
.
permission
,
description
:
"No description available"
,
icon
:
<
i
className=
"icon-default"
/>,
};
return
{
id
:
`
${
index
}
`
,
title
:
meta
.
title
,
description
:
meta
.
description
,
icon
:
meta
.
icon
,
permission
:
perm
.
permission
,
isGranted
:
perm
.
isGranted
,
};
});
setPermissions
(
updatedPermissions
);
},
[
selectedDevice
]);
return
(
<
div
className=
"permissions wrapper"
>
<
SectionHeader
to=
"/home"
/>
<
div
className=
"permissions__content"
>
<
h3
className=
"permissions__content__title"
>
{
t
(
"permissions.title"
)
}
</
h3
>
<
div
className=
"permissions__content__items"
>
{
permissions
.
map
((
permission
)
=>
{
return
(
<
div
key=
{
permission
.
id
}
className=
"permissions__content__item"
>
<
div
className=
"permissions__content__item__header"
>
<
div
>
{
permission
.
icon
}
<
p
>
{
permission
.
title
}
</
p
>
</
div
>
<
div
>
{
permission
.
isGranted
?
(
<
p
className=
"text-success"
>
{
t
(
"common.granted"
)
}
</
p
>
)
:
(
<
p
className=
"text-danger"
>
{
t
(
"common.denied"
)
}
</
p
>
)
}
</
div
>
</
div
>
<
p
className=
"permission__content__item__desc"
>
{
permission
.
description
}
</
p
>
</
div
>
);
})
}
</
div
>
</
div
>
</
div
>
);
};
export
default
Permissions
;
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