82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
'use client';
|
|
import React from 'react';
|
|
import dynamic from 'next/dynamic';
|
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
import { Dashboard } from './dashboard';
|
|
import { useCabinet } from '../lib/hooks/useCabinet';
|
|
import { MOCK_USER, MOCK_STATS } from '../lib/mock';
|
|
import type { CabinetSection } from '../lib/types';
|
|
|
|
// ─── Lazy sections (separate JS chunks) ───────────────────────────────────────
|
|
|
|
const Skeleton = () => (
|
|
<div className="space-y-3">
|
|
{Array.from({ length: 4 }).map((_, i) => (
|
|
<div key={i} className="h-12 bg-slate-100 rounded-xl animate-pulse" />
|
|
))}
|
|
</div>
|
|
);
|
|
|
|
const PlagiatTable = dynamic(
|
|
() =>
|
|
import('./tables/PlagiatTable').then((m) => ({ default: m.PlagiatTable })),
|
|
{ loading: Skeleton },
|
|
);
|
|
const SiTable = dynamic(
|
|
() => import('./tables/SiTable').then((m) => ({ default: m.SiTable })),
|
|
{ loading: Skeleton },
|
|
);
|
|
const PaymentsTable = dynamic(
|
|
() =>
|
|
import('./tables/PaymentsTable').then((m) => ({
|
|
default: m.PaymentsTable,
|
|
})),
|
|
{ loading: Skeleton },
|
|
);
|
|
const ProfileSection = dynamic(
|
|
() => import('./profile').then((m) => ({ default: m.ProfileSection })),
|
|
{ loading: Skeleton },
|
|
);
|
|
|
|
// ─── Section switcher ──────────────────────────────────────────────────────────
|
|
|
|
function SectionContent({ section }: { section: CabinetSection }) {
|
|
switch (section) {
|
|
case 'dashboard':
|
|
return <Dashboard userName={MOCK_USER.first_name} />;
|
|
case 'plagiat':
|
|
return <PlagiatTable />;
|
|
case 'si':
|
|
return <SiTable />;
|
|
case 'payments':
|
|
return <PaymentsTable />;
|
|
case 'profile':
|
|
return <ProfileSection stats={MOCK_STATS} />;
|
|
}
|
|
}
|
|
|
|
// ─── Animation ────────────────────────────────────────────────────────────────
|
|
|
|
const FADE = {
|
|
initial: { opacity: 0, y: 10 },
|
|
animate: { opacity: 1, y: 0 },
|
|
exit: { opacity: 0, y: -6 },
|
|
transition: { duration: 0.18, ease: 'easeOut' },
|
|
} as const;
|
|
|
|
// ─── CabinetLayout ────────────────────────────────────────────────────────────
|
|
|
|
export const CabinetLayout: React.FC = () => {
|
|
const { activeSection } = useCabinet();
|
|
|
|
return (
|
|
<main className="flex-1 p-4 md:p-6 lg:p-8 max-w-6xl mx-auto w-full pt-20">
|
|
<AnimatePresence mode="wait">
|
|
<motion.div key={activeSection} {...FADE}>
|
|
<SectionContent section={activeSection} />
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</main>
|
|
);
|
|
};
|