Commit b4eebb44 by asranov0003

feat: make delete edit and refresh device

parent 7ad3afd9
......@@ -20,7 +20,10 @@
"pageInDevelopment": "Page in Development",
"pageInDevelopmentDesc": "This page is currently under development. Use the application to view recordings.",
"hours": "Hours",
"minutes": "Minutes"
"minutes": "Minutes",
"rename": "Rename",
"deviceName": "Device name",
"deletion": "Deletion"
},
"auth": {
"entrance": "Sign In",
......
......@@ -20,7 +20,10 @@
"pageInDevelopment": "Страница в разработке",
"pageInDevelopmentDesc": "Эта страница в настоящее время разрабатывается. Используйте приложение для просмотра записей.",
"hours": "Часы",
"minutes": "Минуты"
"minutes": "Минуты",
"rename": "Переименовать",
"deviceName": "Имя устройства",
"deletion": "Удаление"
},
"auth": {
"entrance": "Вход",
......
......@@ -20,7 +20,10 @@
"pageInDevelopment": "Sahifa ishlab chiqilmoqda",
"pageInDevelopmentDesc": "Ushbu sahifa hozirda ishlab chiqilmoqda. Yozuvlarni ko'rish uchun ilovadan foydalaning.",
"hours": "Soatlar",
"minutes": "Daqiqalar"
"minutes": "Daqiqalar",
"rename": "O'zgartirish",
"deviceName": "Qurilma nomi",
"deletion": "O'chirish"
},
"auth": {
"entrance": "Kirish",
......
......@@ -6,8 +6,8 @@ import en from "../../assets/images/flag-en.png";
import ru from "../../assets/images/flag-ru.png";
import uz from "../../assets/images/flag-uz.png";
import { FiUserMinus } from "react-icons/fi";
import { IoKeyOutline } from "react-icons/io5";
import { MdOutlineLogout } from "react-icons/md";
import { IoKeyOutline, IoPhonePortraitOutline } from "react-icons/io5";
import { MdOutlineEdit, MdOutlineLogout } from "react-icons/md";
import { useTranslation } from "react-i18next";
import {
useAppDispatch,
......@@ -31,6 +31,11 @@ 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";
import {
deleteDevice,
editDevice,
refreshDevices,
} from "../../stores/slices/deviceSlice";
const deleteDatas = [
{
......@@ -63,6 +68,13 @@ const Settings: React.FC = () => {
const [selectedDeleteData, setSelectedDeleteData] = useState<null | number>(
null
);
const [selectedDevice, setSelectedDevice] = useState<{
id: string;
name: string;
} | null>(null);
const [isOpenDevices, setIsOpenDevices] = useState(false);
const [isOpenEditDevice, setIsOpenEditDevice] = useState(false);
const [isOpenDeleteDevice, setIsOpenDeleteDevice] = useState(false);
const [isOpenDeleteDataModal, setIsOpenDeleteDataModal] = useState(false);
const { language, changeLanguage } = useLanguage();
const { t } = useTranslation();
......@@ -72,6 +84,9 @@ const Settings: React.FC = () => {
const { session, deletingData } = useAppSelector(
(state: RootState) => state.account
);
const { devices, isDeletingDevice, isEditingDevice } = useAppSelector(
(state: RootState) => state.device
);
const dispatch = useAppDispatch();
const toggleLogoutModal = () => {
......@@ -90,6 +105,48 @@ const Settings: React.FC = () => {
setIsOpenDeleteDataModal((prev) => !prev);
};
const toggleIsOpenDevices = () => {
setIsOpenDevices((prev) => !prev);
};
const toggleIsOpenEditDevice = () => {
setIsOpenEditDevice((prev) => !prev);
};
const toggleIsOpenDeleteDevice = () => {
setIsOpenDeleteDevice((prev) => !prev);
};
const handleEditDevice = async () => {
try {
if (selectedDevice) {
await dispatch(
editDevice({ deviceId: selectedDevice.id, name: selectedDevice.name })
);
await dispatch(refreshDevices());
}
} catch (error) {
console.error("Error editing device: ", error);
} finally {
setIsOpenEditDevice(false);
}
};
const handleDeleteDevice = async () => {
try {
if (selectedDevice) {
await dispatch(deleteDevice(selectedDevice.id));
}
await dispatch(refreshDevices());
} catch (error) {
console.error("Error deleting device: ", error);
} finally {
setIsOpenDeleteDevice(false);
}
};
const handleDeleteData = async () => {
try {
if (selectedDeleteData) {
......@@ -181,6 +238,51 @@ const Settings: React.FC = () => {
/>
<div>
<div onClick={toggleIsOpenDevices} className="settings__data__header">
<p>{t("settings.myDevices")}</p>
{isOpenDevices ? <FaChevronUp /> : <FaChevronDown />}
</div>
{isOpenDevices && (
<div className="settings__data__list">
{devices.length > 0 ? (
<>
{devices.map((device) => {
return (
<div key={device.id} className="settings__data__item">
<div className="settings__data__item__info">
<IoPhonePortraitOutline className="settings__data__item__info__icon" />
<p>{device.name}</p>
</div>
<div className="settings__data__item__actions">
<MdOutlineEdit
className="settings__data__item__actions__icon"
onClick={() => {
setSelectedDevice(device);
setIsOpenEditDevice(true);
}}
/>
<FaRegTrashCan
className="settings__data__item__actions__icon text-danger"
onClick={() => {
setSelectedDevice(device);
setIsOpenDeleteDevice(true);
}}
/>
</div>
</div>
);
})}
</>
) : (
<p className="settings__data__no">{t("settings.noDevices")}</p>
)}
</div>
)}
</div>
<div>
<div
onClick={toggleIsOpenDeleteData}
className="settings__data__header"
......@@ -259,6 +361,68 @@ const Settings: React.FC = () => {
/>
<CModal
isOpen={isOpenEditDevice}
onToggle={toggleIsOpenEditDevice}
content={
<div className="modal__box">
<h3 className="modal__box__title">{t("common.rename")}</h3>
<CInput
placeholder={t("common.deviceName")}
value={selectedDevice?.name || ""}
onChange={(e) => {
if (selectedDevice) {
setSelectedDevice({
...selectedDevice,
name: e.target.value,
});
}
}}
/>
<div className="modal__box__actions">
<CButton
title={t("button.cancel")}
onClick={toggleIsOpenEditDevice}
/>
<CButton
title={t("button.ok")}
onClick={handleEditDevice}
isLoading={isEditingDevice}
/>
</div>
</div>
}
/>
<CModal
isOpen={isOpenDeleteDevice}
onToggle={toggleIsOpenDeleteDevice}
content={
<div className="modal__box">
<h3 className="modal__box__title">
{t("device.deleteDevice")} <br />
{selectedDevice?.name}
</h3>
<p style={{ textAlign: "center" }}>
{t("device.deleteDeviceDesc")}
</p>
<div className="modal__box__actions">
<CButton
title={t("button.cancel")}
onClick={toggleIsOpenDeleteDevice}
/>
<CButton
title={t("button.delete")}
variant="danger"
onClick={handleDeleteDevice}
isLoading={isDeletingDevice}
/>
</div>
</div>
}
/>
<CModal
isOpen={isOpenDeleteAccountModal}
onToggle={toggleDeleteAccountModal}
content={
......
......@@ -14,6 +14,7 @@ interface IDeviceState {
isAudioListLoading: boolean;
loadingDevices: boolean;
errorDevices: string;
isEditingDevice?: boolean;
isDeletingDevice: boolean;
}
......@@ -25,6 +26,7 @@ const initialState: IDeviceState = {
isAudioListLoading: false,
loadingDevices: false,
errorDevices: "",
isEditingDevice: false,
isDeletingDevice: false,
};
......@@ -116,6 +118,48 @@ export const fetchAudioFiles = createAsyncThunk(
}
);
export const editDevice = createAsyncThunk(
"device/editDevice",
async (
{ deviceId, name }: { deviceId: string; name: string },
{ rejectWithValue }
) => {
try {
const response = await sendRpcRequest("devices.setDeviceName", {
deviceId,
name,
});
return response;
} catch (error: unknown) {
if (typeof error === "object" && error !== null && "message" in error) {
return rejectWithValue(error.message);
}
return rejectWithValue("Unknown error occurred");
}
}
);
// force refresh (no condition)
export const refreshDevices = createAsyncThunk(
"device/refreshDevices",
async (_, { rejectWithValue }) => {
try {
const response = await sendRpcRequest<{ list: IDevice[] }>(
"devices.getlist"
);
return response.list;
} catch (error: unknown) {
if (typeof error === "object" && error !== null && "message" in error) {
return rejectWithValue(error.message);
}
return rejectWithValue("Unknown error occurred");
}
}
);
export const deleteDevice = createAsyncThunk(
"device/deleteDevice",
async (deviceId: string, { rejectWithValue }) => {
......@@ -167,6 +211,17 @@ const deviceSlice = createSlice({
state.deviceData = action.payload;
})
.addCase(editDevice.pending, (state) => {
state.isEditingDevice = true;
})
.addCase(editDevice.fulfilled, (state) => {
state.isEditingDevice = false;
})
.addCase(editDevice.rejected, (state, action) => {
state.isEditingDevice = false;
console.error("Error editing device:", action.payload);
})
.addCase(deleteDevice.pending, (state) => {
state.isDeletingDevice = true;
})
......@@ -188,6 +243,11 @@ const deviceSlice = createSlice({
.addCase(fetchAudioFiles.rejected, (state, action) => {
state.isAudioListLoading = false;
console.error("Error fetching audio files:", action.payload);
})
.addCase(refreshDevices.fulfilled, (state, action) => {
state.devices = action.payload;
state.selectedDevice = action.payload[0] ?? null;
});
},
});
......
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