Добавлен новый компонент TabsNav для управления навигацией по вкладкам в страницах аккаунта и статистики. Обновлены соответствующие страницы для использования нового компонента, что улучшает структуру кода и упрощает управление вкладками. Также внесены изменения в стили для улучшения визуального восприятия.
This commit is contained in:
parent
14921074a5
commit
5614894e49
@ -23,6 +23,7 @@ import AccountProfile from "../../components/AccountProfile";
|
|||||||
import AccountSecurity from "../../components/AccountSecurity";
|
import AccountSecurity from "../../components/AccountSecurity";
|
||||||
import AccountNotifications from "../../components/AccountNotifications";
|
import AccountNotifications from "../../components/AccountNotifications";
|
||||||
import AccountAgentTransactionSection from "../../components/AccountAgentTransactionSection";
|
import AccountAgentTransactionSection from "../../components/AccountAgentTransactionSection";
|
||||||
|
import TabsNav from "../../components/TabsNav";
|
||||||
|
|
||||||
const initialNotifications = {
|
const initialNotifications = {
|
||||||
emailNotifications: true,
|
emailNotifications: true,
|
||||||
@ -54,22 +55,7 @@ export default function AccountPage() {
|
|||||||
<div className={styles.dashboard}>
|
<div className={styles.dashboard}>
|
||||||
<h1 className={styles.title}>Аккаунт</h1>
|
<h1 className={styles.title}>Аккаунт</h1>
|
||||||
<div className={accountStyles.accountTabsNav}>
|
<div className={accountStyles.accountTabsNav}>
|
||||||
<nav className={accountStyles.accountTabsNav}>
|
<TabsNav activeTab={activeTab} setActiveTab={setActiveTab} tabs={tabs} />
|
||||||
{tabs.map(tab => (
|
|
||||||
<button
|
|
||||||
key={tab.id}
|
|
||||||
onClick={() => setActiveTab(tab.id)}
|
|
||||||
className={
|
|
||||||
activeTab === tab.id
|
|
||||||
? `${accountStyles.accountTabsButton} ${accountStyles.accountTabsButtonActive}`
|
|
||||||
: accountStyles.accountTabsButton
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{tab.icon}
|
|
||||||
{tab.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
{activeTab === "profile" && (
|
{activeTab === "profile" && (
|
||||||
<AccountProfile />
|
<AccountProfile />
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import styles from "../../styles/stat.module.css";
|
|||||||
import DateInput from "../../components/DateInput";
|
import DateInput from "../../components/DateInput";
|
||||||
import DateFilters from "../../components/DateFilters";
|
import DateFilters from "../../components/DateFilters";
|
||||||
import AuthGuard from "../../components/AuthGuard";
|
import AuthGuard from "../../components/AuthGuard";
|
||||||
|
import TabsNav from "../../components/TabsNav";
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ id: "agents", label: "Агенты" },
|
{ id: "agents", label: "Агенты" },
|
||||||
@ -40,17 +41,7 @@ export default function StatPage() {
|
|||||||
<h1 className={styles.title}>Статистика и аналитика</h1>
|
<h1 className={styles.title}>Статистика и аналитика</h1>
|
||||||
{/* <button className={styles.exportBtn}>Экспорт</button> */}
|
{/* <button className={styles.exportBtn}>Экспорт</button> */}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.tabs}>
|
<TabsNav activeTab={activeTab} setActiveTab={setActiveTab} tabs={tabs} />
|
||||||
{tabs.map((tab) => (
|
|
||||||
<button
|
|
||||||
key={tab.id}
|
|
||||||
className={activeTab === tab.id ? styles.activeTab : styles.tab}
|
|
||||||
onClick={() => setActiveTab(tab.id)}
|
|
||||||
>
|
|
||||||
{tab.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<DateFilters
|
<DateFilters
|
||||||
dateStart={filters.dateStart}
|
dateStart={filters.dateStart}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { CalendarToday } from "@mui/icons-material";
|
||||||
|
import styles from "../styles/dateinput.module.css";
|
||||||
|
|
||||||
interface DateInputProps {
|
interface DateInputProps {
|
||||||
label: string;
|
label: string;
|
||||||
@ -11,13 +13,28 @@ interface DateInputProps {
|
|||||||
const DateInput: React.FC<DateInputProps> = ({ label, value, onChange, min, max }) => (
|
const DateInput: React.FC<DateInputProps> = ({ label, value, onChange, min, max }) => (
|
||||||
<div>
|
<div>
|
||||||
<label>{label}</label>
|
<label>{label}</label>
|
||||||
<input
|
<div style={{ position: "relative" }}>
|
||||||
type="date"
|
<input
|
||||||
value={value}
|
type="date"
|
||||||
onChange={onChange}
|
value={value}
|
||||||
min={min}
|
onChange={onChange}
|
||||||
max={max}
|
min={min}
|
||||||
/>
|
max={max}
|
||||||
|
className={`${styles.dateInputHiddenIcon} ${styles.dateInputBase}`}
|
||||||
|
/>
|
||||||
|
<CalendarToday
|
||||||
|
className={styles.dateIcon}
|
||||||
|
fontSize="small"
|
||||||
|
onClick={(e) => {
|
||||||
|
const inputElement = e.currentTarget.previousElementSibling as HTMLInputElement;
|
||||||
|
if (inputElement && typeof inputElement.showPicker === 'function') {
|
||||||
|
inputElement.showPicker();
|
||||||
|
} else {
|
||||||
|
inputElement.focus();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import styles from "../styles/navigation.module.css";
|
|||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useUser } from "./UserContext";
|
import { useUser } from "./UserContext";
|
||||||
|
import TabsNav from "./TabsNav";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
interface NavItem {
|
interface NavItem {
|
||||||
id: string;
|
id: string;
|
||||||
@ -22,6 +24,7 @@ const Navigation: React.FC = () => {
|
|||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const [login, setLogin] = useState<string>("");
|
const [login, setLogin] = useState<string>("");
|
||||||
const { firstName, surname } = useUser();
|
const { firstName, surname } = useUser();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof document !== "undefined") {
|
if (typeof document !== "undefined") {
|
||||||
@ -30,25 +33,21 @@ const Navigation: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleNavigationChange = (tabId: string) => {
|
||||||
|
if (tabId === "home") {
|
||||||
|
router.push("/");
|
||||||
|
} else if (tabId === "stat") {
|
||||||
|
router.push("/stat");
|
||||||
|
} else if (tabId === "billing") {
|
||||||
|
router.push("/billing");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (pathname === "/auth") return null;
|
if (pathname === "/auth") return null;
|
||||||
return (
|
return (
|
||||||
<nav className={styles.nav}>
|
<nav className={styles.nav}>
|
||||||
<div className={styles.logo}>RE:Premium Partner</div>
|
<div className={styles.logo}>RE:Premium Partner</div>
|
||||||
<div className={styles.links}>
|
<TabsNav activeTab={pathname} setActiveTab={handleNavigationChange} tabs={navItems} />
|
||||||
{navItems.map((item) => (
|
|
||||||
<Link
|
|
||||||
key={item.id}
|
|
||||||
href={item.href}
|
|
||||||
className={
|
|
||||||
pathname === item.href
|
|
||||||
? styles.active
|
|
||||||
: styles.link
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className={styles.profile}>
|
<div className={styles.profile}>
|
||||||
<Link href="/account" style={{ display: 'flex', alignItems: 'center', gap: 12, textDecoration: 'none' }}>
|
<Link href="/account" style={{ display: 'flex', alignItems: 'center', gap: 12, textDecoration: 'none' }}>
|
||||||
<div className={styles.avatar}>
|
<div className={styles.avatar}>
|
||||||
|
|||||||
71
src/components/TabsNav.tsx
Normal file
71
src/components/TabsNav.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import defaultTabsStyles from "../styles/tabs.module.css";
|
||||||
|
|
||||||
|
interface TabItem {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
href?: string;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TabsNavProps {
|
||||||
|
activeTab: string;
|
||||||
|
setActiveTab: (tabId: string) => void;
|
||||||
|
tabs: TabItem[];
|
||||||
|
tabStyles?: {
|
||||||
|
nav: string;
|
||||||
|
button: string;
|
||||||
|
buttonActive: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const TabsNav: React.FC<TabsNavProps> = ({
|
||||||
|
activeTab,
|
||||||
|
setActiveTab,
|
||||||
|
tabs,
|
||||||
|
tabStyles,
|
||||||
|
}) => {
|
||||||
|
const currentTabStyles = tabStyles || {
|
||||||
|
nav: defaultTabsStyles.tabsNav,
|
||||||
|
button: defaultTabsStyles.tabButton,
|
||||||
|
buttonActive: defaultTabsStyles.tabButtonActive,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className={currentTabStyles.nav}>
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
tab.href ? (
|
||||||
|
<Link
|
||||||
|
key={tab.id}
|
||||||
|
href={tab.href}
|
||||||
|
onClick={() => setActiveTab(tab.id)}
|
||||||
|
className={
|
||||||
|
activeTab === tab.href
|
||||||
|
? `${currentTabStyles.button} ${currentTabStyles.buttonActive}`
|
||||||
|
: currentTabStyles.button
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tab.icon}
|
||||||
|
{tab.label}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
key={tab.id}
|
||||||
|
onClick={() => setActiveTab(tab.id)}
|
||||||
|
className={
|
||||||
|
activeTab === tab.id
|
||||||
|
? `${currentTabStyles.button} ${currentTabStyles.buttonActive}`
|
||||||
|
: currentTabStyles.button
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tab.icon}
|
||||||
|
{tab.label}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TabsNav;
|
||||||
@ -258,6 +258,7 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
@ -273,6 +274,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
color: #6b7280;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Стили для вкладки уведомлений --- */
|
/* --- Стили для вкладки уведомлений --- */
|
||||||
@ -362,9 +364,11 @@
|
|||||||
left: 22px;
|
left: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Стили для табов и навигации из page.tsx --- */
|
|
||||||
|
|
||||||
.accountTabsNav {
|
|
||||||
|
/* Стили для табов и навигации из page.tsx */
|
||||||
|
|
||||||
|
/* .accountTabsNav {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 32px;
|
gap: 32px;
|
||||||
border-bottom: 1px solid #e5e7eb;
|
border-bottom: 1px solid #e5e7eb;
|
||||||
@ -389,51 +393,18 @@
|
|||||||
border-bottom: 2px solid #2563eb;
|
border-bottom: 2px solid #2563eb;
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
} */
|
||||||
|
|
||||||
/* Стили для кнопок подтверждения */
|
/* Стили для кнопок подтверждения */
|
||||||
.primaryButton {
|
.primaryButton {
|
||||||
background-color: #2563eb; /* Синий */
|
background: #2563eb;
|
||||||
color: #ffffff;
|
color: #fff;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 8px 16px;
|
padding: 8px 20px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s ease;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.primaryButton:hover {
|
|
||||||
background-color: #1d4ed8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondaryButton {
|
|
||||||
background-color: #f3f4f6; /* Серый */
|
|
||||||
color: #374151;
|
|
||||||
border: 1px solid #d1d5db;
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondaryButton:hover {
|
|
||||||
background-color: #e5e7eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tertiaryButton {
|
|
||||||
background: none;
|
|
||||||
color: #6b7280; /* Темно-серый */
|
|
||||||
border: none;
|
|
||||||
padding: 8px 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tertiaryButton:hover {
|
|
||||||
color: #4b5563;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ... можно добавить другие стили по необходимости ... */
|
|
||||||
37
src/styles/dateinput.module.css
Normal file
37
src/styles/dateinput.module.css
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
.dateInputHiddenIcon {
|
||||||
|
-webkit-appearance: none; /* Safari и Chrome */
|
||||||
|
-moz-appearance: none; /* Firefox */
|
||||||
|
appearance: none; /* Стандартное свойство */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateInputHiddenIcon::-webkit-calendar-picker-indicator {
|
||||||
|
display: none; /* Скрыть для WebKit-браузеров */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateInputHiddenIcon::-moz-calendar-picker-indicator {
|
||||||
|
display: none; /* Скрыть для Mozilla-браузеров */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateInputHiddenIcon::-ms-calendar-picker-indicator {
|
||||||
|
display: none; /* Скрыть для Internet Explorer/Edge */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateInputBase {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-top: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-right: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateIcon {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
cursor: pointer;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
}
|
}
|
||||||
.links {
|
/* .links {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 32px;
|
gap: 32px;
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@
|
|||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
border-bottom: 2px solid #2563eb;
|
border-bottom: 2px solid #2563eb;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
} */
|
||||||
.profile {
|
.profile {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -27,11 +27,14 @@
|
|||||||
.exportBtn:hover {
|
.exportBtn:hover {
|
||||||
background: #1d4ed8;
|
background: #1d4ed8;
|
||||||
}
|
}
|
||||||
.tabs {
|
/* Tabs */
|
||||||
|
/* .tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 32px;
|
gap: 32px;
|
||||||
border-bottom: 1.5px solid #e5e7eb;
|
border-bottom: 1.5px solid #e5e7eb;
|
||||||
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
@ -43,17 +46,19 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 0.2s, border 0.2s;
|
transition: color 0.2s, border 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab:hover {
|
.tab:hover {
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
border-bottom: 2px solid #dbeafe;
|
border-bottom: 2px solid #dbeafe;
|
||||||
}
|
}
|
||||||
|
|
||||||
.activeTab {
|
.activeTab {
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 2px solid #2563eb;
|
border-bottom: 2px solid #2563eb;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: none;
|
background: none;
|
||||||
}
|
} */
|
||||||
.filters {
|
.filters {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(1, 1fr);
|
grid-template-columns: repeat(1, 1fr);
|
||||||
|
|||||||
31
src/styles/tabs.module.css
Normal file
31
src/styles/tabs.module.css
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.tabsNav {
|
||||||
|
display: flex;
|
||||||
|
gap: 32px;
|
||||||
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabButton {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
color: #6b7280;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 8px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabButton:hover {
|
||||||
|
color: #2563eb;
|
||||||
|
border-bottom: 2px solid #dbeafe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabButtonActive {
|
||||||
|
border-bottom: 2px solid #2563eb;
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user