Commit 1e49e9ab by asranov0003

feat: add account slice

parent 18157566
// export const API_URL = "https://cabinet.thecybernanny.com/nanny/backend/rpc"; // PROD
export const API_URL = "https://cabinet.dev.thecybernanny.com/nanny/backend/rpc"; // DEV
export const API_URL = "https://cabinet.thecybernanny.com/nanny/backend/rpc"; // PROD
// export const API_URL = "https://cabinet.dev.thecybernanny.com/nanny/backend/rpc"; // DEV
export const TG_USER_ID = window.Telegram.WebApp.initDataUnsafe?.user?.id || 0;
export const TOKEN = localStorage.getItem(`token-${TG_USER_ID}`) || "";
......@@ -28,7 +28,7 @@
}
.sidebar {
width: 70%;
width: 85%;
height: 100%;
display: flex;
justify-content: space-between;
......@@ -39,6 +39,19 @@
transition: 0.3s;
}
.sidebar__content__info {
padding: 1rem;
display: flex;
align-items: center;
gap: 1rem;
font-size: 0.85rem;
}
.sidebar__content__info__icon {
font-size: 2.5rem;
color: var(--primary-color);
}
.sidebar__content__navs {
display: flex;
flex-direction: column;
......
......@@ -13,6 +13,13 @@ import { MdLogout } from "react-icons/md";
import { RiHome3Line } from "react-icons/ri";
import { BsCreditCard } from "react-icons/bs";
import { useTranslation } from "react-i18next";
import {
useAppDispatch,
useAppSelector,
type RootState,
} from "../../stores/store";
import { accountSession } from "../../stores/slices/accountSlice";
import { FaUserAlt } from "react-icons/fa";
const devices = [
{
......@@ -37,6 +44,12 @@ const Header: React.FC = () => {
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const sidebarRef = useRef<HTMLDivElement>(null);
const { t } = useTranslation();
const dispatch = useAppDispatch();
const { session } = useAppSelector((state: RootState) => state.account);
useEffect(() => {
dispatch(accountSession());
}, [dispatch]);
const handleOutsideClick = (e: MouseEvent) => {
if (sidebarRef.current && !sidebarRef.current.contains(e.target as Node)) {
......@@ -85,6 +98,36 @@ const Header: React.FC = () => {
<div className="sidebar__overlay">
<div className="sidebar" ref={sidebarRef}>
<div className="sidebar__content">
<div className="sidebar__content__info">
<FaUserAlt className="sidebar__content__info__icon" />
<div className="text-bold">
<p>{session.login}</p>
<p>
{t("session.activeTill")}:{" "}
{session.subDateEnd ? (
<span className="text-success">{session.subDateEnd}</span>
) : (
<span className="text-danger">
{t("session.noSubscription")}
</span>
)}
</p>
<p>
{t("session.emailStatus")}:{" "}
{session.emailVerified ? (
<span className="text-success">
{t("session.verified")}
</span>
) : (
<span className="text-danger">
{t("session.unVerified")}
</span>
)}
</p>
</div>
</div>
<div className="sidebar__content__navs">
<NavLink
to={"/home"}
......
......@@ -26,6 +26,13 @@
"settings": "Settings",
"logout": "Logout"
},
"session": {
"activeTill": "Active till",
"noSubscription": "No subscription",
"emailStatus": "Email status",
"verified": "Verified",
"unVerified": "Unverified"
},
"pincode": {
"enterTitle": "Enter your PIN Code",
"createTitle": "Create your PIN Code",
......
......@@ -26,6 +26,13 @@
"settings": "Настройки",
"logout": "Выйти"
},
"session": {
"activeTill": "Активен до",
"noSubscription": "Нет подписки",
"emailStatus": "Статус почты",
"verified": "Подтверждено",
"unVerified": "Не подтверждено"
},
"pincode": {
"enterTitle": "Введите PIN-код",
"createTitle": "Создайте PIN-код",
......
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { sendRpcRequest } from "../../services/apiClient";
interface ISession {
login: string;
emailVerified: boolean;
subDateEnd: string;
}
interface IAccountState {
session: ISession;
loading: boolean;
}
const initialState: IAccountState = {
session: {
login: "",
emailVerified: false,
subDateEnd: "",
},
loading: false,
};
export const accountSession = createAsyncThunk(
"account/session",
async (_, { rejectWithValue }) => {
try {
const response = await sendRpcRequest<ISession>("account.session");
return response;
} catch (error: unknown) {
if (typeof error === "object" && error !== null && "message" in error) {
return rejectWithValue(error.message);
}
return rejectWithValue("Unknown error occurred");
}
}
);
const accountSlice = createSlice({
name: "account",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(accountSession.pending, (state) => {
state.loading = true;
})
.addCase(accountSession.fulfilled, (state, action) => {
state.loading = false;
state.session = action.payload;
})
.addCase(accountSession.rejected, (state) => {
state.loading = false;
});
},
});
export default accountSlice.reducer;
import { configureStore } from "@reduxjs/toolkit";
import authSlice from "./slices/authSlice";
import accountSlice from "./slices/accountSlice";
import {
useDispatch,
useSelector,
......@@ -9,6 +10,7 @@ import {
export const store = configureStore({
reducer: {
auth: authSlice,
account: accountSlice,
},
});
......
......@@ -28,6 +28,10 @@ body {
text-align: center;
}
.text-bold {
font-weight: bold;
}
:root {
--primary-color: #448AFF;
--primary-muted-color: #BBDEFB;
......
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