This commit is contained in:
smanylov
2025-12-27 11:54:54 +07:00
parent ab6e385984
commit aaa95091d2
10 changed files with 134 additions and 187 deletions
+2 -3
View File
@@ -1,5 +1,4 @@
import NavLinks from '@/app/ui/nav-links'
import styles from '@/app/styles/page.module.scss'
import HeaderPanel from '@/app/ui/header/headerPanel';
import { getQueryClient } from '@/app/providers/getQueryClient';
import { HydrationBoundary, dehydrate } from '@tanstack/react-query';
@@ -14,9 +13,9 @@ export default async function Layout({ children }: { children: React.ReactNode }
<div className="flex">
<HydrationBoundary state={dehydrate(queryClient)}>
<NavLinks />
<div className={`${styles['main-containter-wrapper']}`}>
<div className="main-containter-wrapper">
<HeaderPanel />
<main className={`${styles['main-containter']}`}>
<main className="main-containter">
{children}
</main>
</div>
+1 -26
View File
@@ -1,31 +1,6 @@
'use server'
import { getSessionData } from '@/app/actions/session';
import { localDevelopmentUrl, testUserData, API_BASE_URL } from '@/app/actions/definitions';
const FRUITS_URL = 'https://www.fruityvice.com/api/fruit/';
const ALL = 'all';
export async function fetchFruits() {
try {
const response = await fetch(FRUITS_URL + ALL, { 'method': 'GET' });
let parsed = await response.json();
return parsed;
} catch (error) {
console.error('Error:', error);
throw new Error('Failed to fetch fruits data.');
}
}
export async function fetchFruit(id: number) {
try {
const response = await fetch(FRUITS_URL + id, { 'method': 'GET' });
let parsed = await response.json();
return parsed;
} catch (error) {
console.error('Error:', error);
throw new Error('Failed to fetch fruits data.');
}
}
import { testUserData, API_BASE_URL } from '@/app/actions/definitions';
export async function getUserData() {
const userEmail = await getSessionData('email');
+119
View File
@@ -6,6 +6,19 @@
@use './privacy-and-terms-pages.scss';
@use './VKLogin.scss';
.main-containter-wrapper {
margin-left: 280px;
flex: 1;
padding: 30px;
background: #f8f9ff;
min-height: 100vh;
}
.main-containter {
max-width: 1920px;
margin: 0 auto;
}
.btn {
padding: 12px 24px;
border-radius: 10px;
@@ -161,4 +174,110 @@
:where(.divide-gray-200 > tr:last-child) {
border-bottom: 1px solid var(--color-gray-200);
}
}
.sidebar {
width: 280px;
background: linear-gradient(180deg, #6366f1 0%, #8b5cf6 100%);
padding: 30px 0;
position: fixed;
height: 100vh;
overflow-y: auto;
z-index: 100;
}
.nav-link {
display: flex;
align-items: center;
padding: 15px 30px;
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
transition: all 0.3s;
border-radius: 0 25px 25px 0;
margin-right: 20px;
margin-bottom: 8px;
font-weight: 500;
text-transform: uppercase;
&:hover {
background: rgba(255, 255, 255, 0.15);
color: white;
}
svg {
margin-right: 15px;
width: 20px;
height: 20px;
}
}
.sub-link {
padding: 12px 50px;
font-size: 14px;
border-radius: 0;
margin-right: 0;
&:last-child {
margin-bottom: 0;
}
}
.nav-dropdown {
.dropdown-arrow {
margin-left: auto;
transition: transform 0.3s;
}
&.expanded {
.dropdown-arrow {
transform: rotate(180deg);
}
}
}
.sub-menu.expanded {
max-height: 400px;
}
.sub-menu {
list-style: none;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
background: rgba(255, 255, 255, 0.1);
margin-right: 20px;
border-radius: 0 15px 15px 0;
}
.logo {
display: flex;
align-items: center;
padding: 0 30px 40px;
color: white;
font-size: 24px;
font-weight: 600;
text-transform: uppercase;
svg {
width: 32px;
height: 32px;
margin-right: 15px;
}
}
.logo-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 60px;
height: 60px;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
border-radius: 15px;
margin-bottom: 15px;
svg {
width: 30px;
height: 30px;
fill: white;
}
}
-12
View File
@@ -1,12 +0,0 @@
.main-containter-wrapper {
margin-left: 280px;
flex: 1;
padding: 30px;
background: #f8f9ff;
min-height: 100vh;
}
.main-containter {
max-width: 1920px;
margin: 0 auto;
}
-105
View File
@@ -1,105 +0,0 @@
.sidebar {
width: 280px;
background: linear-gradient(180deg, #6366f1 0%, #8b5cf6 100%);
padding: 30px 0;
position: fixed;
height: 100vh;
overflow-y: auto;
z-index: 100;
}
.nav-link {
display: flex;
align-items: center;
padding: 15px 30px;
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
transition: all 0.3s;
border-radius: 0 25px 25px 0;
margin-right: 20px;
margin-bottom: 8px;
font-weight: 500;
text-transform: uppercase;
&:hover {
background: rgba(255, 255, 255, 0.15);
color: white;
}
svg {
margin-right: 15px;
width: 20px;
height: 20px;
}
}
.sub-link {
padding: 12px 50px;
font-size: 14px;
border-radius: 0;
margin-right: 0;
&:last-child {
margin-bottom: 0;
}
}
.nav-dropdown {
.dropdown-arrow {
margin-left: auto;
transition: transform 0.3s;
}
&.expanded {
.dropdown-arrow {
transform: rotate(180deg);
}
}
}
.sub-menu.expanded {
max-height: 400px;
}
.sub-menu {
list-style: none;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
background: rgba(255, 255, 255, 0.1);
margin-right: 20px;
border-radius: 0 15px 15px 0;
}
.logo {
display: flex;
align-items: center;
padding: 0 30px 40px;
color: white;
font-size: 24px;
font-weight: 600;
text-transform: uppercase;
svg {
width: 32px;
height: 32px;
margin-right: 15px;
}
}
.logo-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 60px;
height: 60px;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
border-radius: 15px;
margin-bottom: 15px;
svg {
width: 30px;
height: 30px;
fill: white;
}
}
+1 -18
View File
@@ -1,7 +1,6 @@
"use client"
import { useState, useRef } from 'react';
import { fetchFruits } from '@/app/actions/action';
import { useClickOutside } from '@/app/hooks/useClickOutside';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
@@ -10,7 +9,6 @@ import {IconNotification} from '@/app/ui/icons/icons';
export default function NotificationsButton() {
const [isOpen, setIsOpen] = useState(false);
const [data, setData] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const menuRef = useRef<HTMLDivElement | null>(null);
const t = useTranslations('Global');
@@ -19,24 +17,9 @@ export default function NotificationsButton() {
setIsOpen(false);
});
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const result = await fetchFruits();
setData("result");
setIsOpen(true);
} catch (err) {
setError('error message');
} finally {
setLoading(false);
}
};
const handleButtonClick = () => {
if (!isOpen) {
fetchData();
setIsOpen(true);
} else {
setIsOpen(false);
}
+1 -3
View File
@@ -1,8 +1,6 @@
import style from "@/app/styles/ui.module.scss"
export default function LogoIcon() {
return (
<div className={`${style['logo-icon']}`}>
<div className="logo-icon">
<svg viewBox="0 0 24 24">
<path d="M12 2L2 7v10c0 5.55 3.84 9.74 9 11 5.16-1.26 9-5.45 9-11V7l-10-5z"></path>
</svg>
+1 -3
View File
@@ -1,8 +1,6 @@
import styles from '@/app/styles/ui.module.scss';
export default function Logo() {
return (
<div className={`${styles.logo}`}>
<div className="logo">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2L2 7v10c0 5.55 3.84 9.74 9 11 5.16-1.26 9-5.45 9-11V7l-10-5z"></path>
</svg>
+5 -12
View File
@@ -1,4 +1,3 @@
import styles from '@/app/styles/ui.module.scss';
import { useState, useRef } from 'react';
import Link from 'next/link';
import clsx from 'clsx';
@@ -32,35 +31,29 @@ export default function DropDownList() {
return (
<>
<div
className={`
${styles['nav-dropdown']}
${dropDownExpanded ? styles['expanded'] : ''}
`}
className={`nav-dropdown ${dropDownExpanded ? 'expanded' : ''}`}
onClick={dropDownHandler}
>
<div className={`flex ${styles['nav-link']} cursor-pointer select-none`}>
<div className="flex nav-link cursor-pointer select-none">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2l-5.37.84z"></path>
</svg>
<p>
{t('marking')}
</p>
<svg className={`${styles['dropdown-arrow']}`} viewBox="0 0 24 24" fill="currentColor">
<svg className="dropdown-arrow" viewBox="0 0 24 24" fill="currentColor">
<path d="M7 10l5 5 5-5z"></path>
</svg>
</div>
</div>
<ul className={`
${styles['sub-menu']}
${dropDownExpanded ? styles['expanded'] : ''}
`}>
<ul className={`sub-menu ${dropDownExpanded ? 'expanded' : ''}`}>
{links.map((link) => {
return (
<Link
key={link.name}
href={link.href}
className={clsx(
`flex ${styles['nav-link']} ${styles['sub-link']}`,
`flex nav-link sub-link`,
{
'bg-[#5659f1]': pathname === link.href,
},
+4 -5
View File
@@ -3,7 +3,6 @@
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import clsx from 'clsx';
import styles from '@/app/styles/ui.module.scss'
import Logo from '@/app/ui/logo';
import DropDownList from '@/app/ui/nav-link-dropdown';
import { logout } from '@/app/actions/auth';
@@ -53,14 +52,14 @@ export default function NavLinks() {
return (
<div className=''>
<nav className={`${styles.sidebar}`}>
<nav className="sidebar">
<Logo />
<ul>
<Link
key={t('home')}
href='/pages/dashboard'
className={clsx(
`flex ${styles['nav-link']}`,
"flex nav-link",
{
'bg-[#5659f1]': pathname === '/pages/dashboard',
},
@@ -80,7 +79,7 @@ export default function NavLinks() {
key={link.name}
href={link.href}
className={clsx(
`flex ${styles['nav-link']}`,
`flex nav-link`,
{
'bg-[#5659f1]': pathname === link.href,
},
@@ -96,7 +95,7 @@ export default function NavLinks() {
<Link
key={t('exit')}
href='/login'
className={`flex ${styles['nav-link']}`}
className="flex nav-link"
onClick={(e) => {
e.preventDefault();
logout();