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
7ad3afd9
Commit
7ad3afd9
authored
Sep 23, 2025
by
asranov0003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: make delete data
parent
aab2f9f5
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
275 additions
and
5 deletions
+275
-5
en.json
src/locales/en/en.json
+10
-1
ru.json
src/locales/ru/ru.json
+10
-1
uz.json
src/locales/uz/uz.json
+10
-1
Settings.css
src/pages/Settings/Settings.css
+49
-0
Settings.tsx
src/pages/Settings/Settings.tsx
+126
-2
accountSlice.ts
src/stores/slices/accountSlice.ts
+70
-0
No files found.
src/locales/en/en.json
View file @
7ad3afd9
...
...
@@ -114,7 +114,16 @@
"recoverPassword"
:
"Recover password"
,
"changePassword"
:
"Change password"
,
"subscribeNow"
:
"Subscribe now"
,
"logout"
:
"Logout"
"logout"
:
"Logout"
,
"myDevices"
:
"My devices"
,
"noDevices"
:
"No devices found"
,
"deleteData"
:
"Delete data"
,
"deleteAudio"
:
"Delete audio"
,
"deleteAudioDesc"
:
"Are you sure you want to delete all audio files?"
,
"deleteImages"
:
"Delete images"
,
"deleteImagesDesc"
:
"Are you sure you want to delete all images?"
,
"deleteMedia"
:
"Delete media"
,
"deleteMediaDesc"
:
"Are you sure you want to delete all media files?"
},
"permissions"
:
{
"title"
:
"Permissions"
,
...
...
src/locales/ru/ru.json
View file @
7ad3afd9
...
...
@@ -114,7 +114,16 @@
"recoverPassword"
:
"Восстановить пароль"
,
"changePassword"
:
"Сменить пароль"
,
"subscribeNow"
:
"Оформить подписку"
,
"logout"
:
"Выйти"
"logout"
:
"Выйти"
,
"myDevices"
:
"Мои устройства"
,
"noDevices"
:
"Устройства не найдены"
,
"deleteData"
:
"Удалить данные"
,
"deleteAudio"
:
"Удалить аудио"
,
"deleteAudioDesc"
:
"Вы действительно хотите удалить все аудио-файлы?"
,
"deleteImages"
:
"Удалить изображения"
,
"deleteImagesDesc"
:
"Вы действительно хотите удалить все изображения?"
,
"deleteMedia"
:
"Удалить медиа"
,
"deleteMediaDesc"
:
"Вы действительно хотите удалить все медиа-файлы?"
},
"permissions"
:
{
"title"
:
"Разрешения"
,
...
...
src/locales/uz/uz.json
View file @
7ad3afd9
...
...
@@ -114,7 +114,16 @@
"recoverPassword"
:
"Parolni tiklash"
,
"changePassword"
:
"Parolni o'zgartirish"
,
"subscribeNow"
:
"Obuna bo'lish"
,
"logout"
:
"Chiqish"
"logout"
:
"Chiqish"
,
"myDevices"
:
"Mening qurilmalarim"
,
"noDevices"
:
"Hech qanday qurilma topilmadi"
,
"deleteData"
:
"Ma'lumotlarni o'chirish"
,
"deleteAudio"
:
"Audio fayllarni o'chirish"
,
"deleteAudioDesc"
:
"Siz haqiqatan ham barcha audio fayllarni o'chirmoqchimisiz?"
,
"deleteImages"
:
"Rasm fayllarni o'chirish"
,
"deleteImagesDesc"
:
"Siz haqiqatan ham barcha rasm fayllarni o'chirmoqchimisiz?"
,
"deleteMedia"
:
"Media fayllarni o'chirish"
,
"deleteMediaDesc"
:
"Siz haqiqatan ham barcha media fayllarni o'chirmoqchimisiz?"
},
"permissions"
:
{
"title"
:
"Ruxsatlar"
,
...
...
src/pages/Settings/Settings.css
View file @
7ad3afd9
...
...
@@ -26,4 +26,52 @@
.settings__content__action__icon
{
font-size
:
1.2rem
;
}
.settings__data__header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
background
:
var
(
--background-color
);
color
:
var
(
--text-color
);
border
:
1px
solid
var
(
--gray-color
);
padding
:
0.75rem
1rem
;
border-radius
:
0.5rem
;
cursor
:
pointer
;
}
.settings__data__item
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
padding
:
0.75rem
1rem
;
border-bottom
:
1px
solid
var
(
--text-color
);
}
.settings__data__item__info
{
display
:
flex
;
align-items
:
center
;
gap
:
0.5rem
;
}
.settings__data__item__info__icon
{
font-size
:
1.275rem
;
}
.settings__data__item__actions__icon
{
font-size
:
1.275rem
;
cursor
:
pointer
;
}
.settings__data__item__actions
{
display
:
flex
;
align-items
:
center
;
gap
:
0.5rem
;
}
.settings__data__no
{
text-align
:
center
;
color
:
var
(
--text-danger
);
margin
:
0.5rem
0
;
font-size
:
0.875rem
;
}
\ No newline at end of file
src/pages/Settings/Settings.tsx
View file @
7ad3afd9
...
...
@@ -19,8 +19,36 @@ import CModal from "../../components/CModal";
import
CButton
from
"../../components/CButton"
;
import
{
Link
}
from
"react-router-dom"
;
import
CInput
from
"../../components/CInput"
;
import
{
checkPassword
,
setTimezone
}
from
"../../stores/slices/accountSlice"
;
import
{
checkPassword
,
deleteAudio
,
deleteImage
,
deleteMedia
,
setTimezone
,
}
from
"../../stores/slices/accountSlice"
;
import
{
TIME_ZONES
}
from
"../../constants/timezones"
;
import
{
FaChevronDown
,
FaChevronUp
,
FaImages
}
from
"react-icons/fa"
;
import
{
FaRegTrashCan
}
from
"react-icons/fa6"
;
import
{
RiHeadphoneFill
}
from
"react-icons/ri"
;
import
{
GrMultimedia
}
from
"react-icons/gr"
;
const
deleteDatas
=
[
{
id
:
1
,
name
:
"settings.deleteAudio"
,
icon
:
<
RiHeadphoneFill
className=
"settings__data__item__info__icon"
/>,
},
{
id
:
2
,
name
:
"settings.deleteImages"
,
icon
:
<
FaImages
className=
"settings__data__item__info__icon"
/>,
},
{
id
:
3
,
name
:
"settings.deleteMedia"
,
icon
:
<
GrMultimedia
className=
"settings__data__item__info__icon"
/>,
},
];
const
Settings
:
React
.
FC
=
()
=>
{
const
[
password
,
setPassword
]
=
useState
(
""
);
...
...
@@ -31,12 +59,19 @@ const Settings: React.FC = () => {
const
[
isOpenLogoutModal
,
setIsOpenLogoutModal
]
=
useState
(
false
);
const
[
isOpenDeleteAccountModal
,
setIsOpenDeleteAccountModal
]
=
useState
(
false
);
const
[
isOpenDeleteData
,
setIsOpenDeleteData
]
=
useState
(
false
);
const
[
selectedDeleteData
,
setSelectedDeleteData
]
=
useState
<
null
|
number
>
(
null
);
const
[
isOpenDeleteDataModal
,
setIsOpenDeleteDataModal
]
=
useState
(
false
);
const
{
language
,
changeLanguage
}
=
useLanguage
();
const
{
t
}
=
useTranslation
();
const
{
isCheckPasswordLoading
,
errorCheckPassword
}
=
useAppSelector
(
(
state
:
RootState
)
=>
state
.
account
);
const
{
session
}
=
useAppSelector
((
state
:
RootState
)
=>
state
.
account
);
const
{
session
,
deletingData
}
=
useAppSelector
(
(
state
:
RootState
)
=>
state
.
account
);
const
dispatch
=
useAppDispatch
();
const
toggleLogoutModal
=
()
=>
{
...
...
@@ -47,6 +82,33 @@ const Settings: React.FC = () => {
setIsOpenDeleteAccountModal
((
prev
)
=>
!
prev
);
};
const
toggleIsOpenDeleteData
=
()
=>
{
setIsOpenDeleteData
((
prev
)
=>
!
prev
);
};
const
toggleIsOpenDeleteDataModal
=
()
=>
{
setIsOpenDeleteDataModal
((
prev
)
=>
!
prev
);
};
const
handleDeleteData
=
async
()
=>
{
try
{
if
(
selectedDeleteData
)
{
if
(
selectedDeleteData
===
1
)
{
await
dispatch
(
deleteAudio
());
}
else
if
(
selectedDeleteData
===
2
)
{
await
dispatch
(
deleteImage
());
}
else
if
(
selectedDeleteData
===
3
)
{
await
dispatch
(
deleteMedia
());
}
}
}
catch
(
error
)
{
console
.
error
(
"Error deleting data:"
,
error
);
}
finally
{
setIsOpenDeleteDataModal
(
false
);
setSelectedDeleteData
(
null
);
}
};
useEffect
(()
=>
{
if
(
session
.
timeZoneStr
)
{
const
tz
=
TIME_ZONES
.
find
((
tz
)
=>
tz
.
ianaId
===
session
.
timeZoneStr
);
...
...
@@ -118,6 +180,41 @@ const Settings: React.FC = () => {
}
}
/>
<
div
>
<
div
onClick=
{
toggleIsOpenDeleteData
}
className=
"settings__data__header"
>
<
p
>
{
t
(
"settings.deleteData"
)
}
</
p
>
{
isOpenDeleteData
?
<
FaChevronUp
/>
:
<
FaChevronDown
/>
}
</
div
>
{
isOpenDeleteData
&&
(
<
div
className=
"settings__data__list"
>
{
deleteDatas
.
map
((
data
)
=>
{
return
(
<
div
key=
{
data
.
id
}
className=
"settings__data__item"
>
<
div
className=
"settings__data__item__info"
>
{
data
.
icon
}
<
p
>
{
t
(
data
.
name
)
}
</
p
>
</
div
>
<
div
className=
"settings__data__item__actions"
>
<
FaRegTrashCan
className=
"settings__data__item__actions__icon text-danger"
onClick=
{
()
=>
{
setSelectedDeleteData
(
data
.
id
);
toggleIsOpenDeleteDataModal
();
}
}
/>
</
div
>
</
div
>
);
})
}
</
div
>
)
}
</
div
>
<
h3
>
{
t
(
"settings.account"
)
}
</
h3
>
<
div
...
...
@@ -194,6 +291,33 @@ const Settings: React.FC = () => {
</
div
>
}
/>
<
CModal
isOpen=
{
isOpenDeleteDataModal
}
onToggle=
{
toggleIsOpenDeleteDataModal
}
content=
{
<
div
className=
"modal__box"
>
<
h3
className=
"modal__box__title"
>
{
t
(
"settings.deleteData"
)
}
</
h3
>
<
p
style=
{
{
textAlign
:
"center"
}
}
>
{
selectedDeleteData
===
1
&&
t
(
"settings.deleteAudioDesc"
)
}
{
selectedDeleteData
===
2
&&
t
(
"settings.deleteImagesDesc"
)
}
{
selectedDeleteData
===
3
&&
t
(
"settings.deleteMediaDesc"
)
}
</
p
>
<
div
className=
"modal__box__actions"
>
<
CButton
title=
{
t
(
"button.cancel"
)
}
onClick=
{
toggleIsOpenDeleteDataModal
}
/>
<
CButton
title=
{
t
(
"button.delete"
)
}
variant=
"danger"
onClick=
{
handleDeleteData
}
isLoading=
{
deletingData
}
/>
</
div
>
</
div
>
}
/>
</
div
>
);
};
...
...
src/stores/slices/accountSlice.ts
View file @
7ad3afd9
...
...
@@ -7,6 +7,7 @@ interface IAccountState {
session
:
ISession
;
loading
:
boolean
;
isCheckPasswordLoading
:
boolean
;
deletingData
:
boolean
;
errorCheckPassword
:
string
|
null
;
}
...
...
@@ -20,6 +21,7 @@ const initialState: IAccountState = {
},
loading
:
false
,
isCheckPasswordLoading
:
false
,
deletingData
:
false
,
errorCheckPassword
:
null
,
};
...
...
@@ -99,6 +101,54 @@ export const setTimezone = createAsyncThunk(
}
);
export
const
deleteAudio
=
createAsyncThunk
(
"account/deleteAudio"
,
async
(
_
,
{
rejectWithValue
})
=>
{
try
{
const
response
=
await
sendRpcRequest
(
"account.deleteAudio"
);
return
response
;
}
catch
(
error
)
{
if
(
typeof
error
===
"object"
&&
error
!==
null
&&
"message"
in
error
)
{
return
rejectWithValue
((
error
as
{
message
:
string
}).
message
);
}
return
rejectWithValue
(
"Unknown error occurred"
);
}
}
);
export
const
deleteImage
=
createAsyncThunk
(
"account/deleteImage"
,
async
(
_
,
{
rejectWithValue
})
=>
{
try
{
const
response
=
await
sendRpcRequest
(
"account.deleteImage"
);
return
response
;
}
catch
(
error
)
{
if
(
typeof
error
===
"object"
&&
error
!==
null
&&
"message"
in
error
)
{
return
rejectWithValue
((
error
as
{
message
:
string
}).
message
);
}
return
rejectWithValue
(
"Unknown error occurred"
);
}
}
);
export
const
deleteMedia
=
createAsyncThunk
(
"account/deleteMedia"
,
async
(
_
,
{
rejectWithValue
})
=>
{
try
{
const
response
=
await
sendRpcRequest
(
"account.deleteMedia"
);
return
response
;
}
catch
(
error
)
{
if
(
typeof
error
===
"object"
&&
error
!==
null
&&
"message"
in
error
)
{
return
rejectWithValue
((
error
as
{
message
:
string
}).
message
);
}
return
rejectWithValue
(
"Unknown error occurred"
);
}
}
);
const
accountSlice
=
createSlice
({
name
:
"account"
,
initialState
,
...
...
@@ -136,6 +186,26 @@ const accountSlice = createSlice({
})
.
addCase
(
setTimezone
.
rejected
,
(
state
)
=>
{
state
.
loading
=
false
;
})
.
addCase
(
deleteAudio
.
pending
,
(
state
)
=>
{
state
.
deletingData
=
true
;
})
.
addCase
(
deleteAudio
.
fulfilled
,
(
state
)
=>
{
state
.
deletingData
=
false
;
})
.
addCase
(
deleteAudio
.
rejected
,
(
state
)
=>
{
state
.
deletingData
=
false
;
})
.
addCase
(
deleteImage
.
pending
,
(
state
)
=>
{
state
.
deletingData
=
true
;
})
.
addCase
(
deleteImage
.
fulfilled
,
(
state
)
=>
{
state
.
deletingData
=
false
;
})
.
addCase
(
deleteImage
.
rejected
,
(
state
)
=>
{
state
.
deletingData
=
false
;
});
},
});
...
...
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