Commit 7ad3afd9 by asranov0003

feat: make delete data

parent aab2f9f5
......@@ -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",
......
......@@ -114,7 +114,16 @@
"recoverPassword": "Восстановить пароль",
"changePassword": "Сменить пароль",
"subscribeNow": "Оформить подписку",
"logout": "Выйти"
"logout": "Выйти",
"myDevices": "Мои устройства",
"noDevices": "Устройства не найдены",
"deleteData": "Удалить данные",
"deleteAudio": "Удалить аудио",
"deleteAudioDesc": "Вы действительно хотите удалить все аудио-файлы?",
"deleteImages": "Удалить изображения",
"deleteImagesDesc": "Вы действительно хотите удалить все изображения?",
"deleteMedia": "Удалить медиа",
"deleteMediaDesc": "Вы действительно хотите удалить все медиа-файлы?"
},
"permissions": {
"title": "Разрешения",
......
......@@ -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",
......
......@@ -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
......@@ -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>
);
};
......
......@@ -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;
});
},
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment