dahsboard connected to backend

This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-04-07 13:11:23 +05:00
parent df485b5797
commit b09e2ebc59
4 changed files with 53 additions and 28 deletions

View File

@@ -13,4 +13,5 @@ export const links = {
si_create: '/shared/ai_document/create/', si_create: '/shared/ai_document/create/',
document_types: '/shared/document_types/', document_types: '/shared/document_types/',
pay_history: '/shared/orders/all/', pay_history: '/shared/orders/all/',
statistics: '/shared/statistics/',
}; };

View File

@@ -1,6 +1,16 @@
import React from 'react'; import React from 'react';
import { TrendingUp, Calendar, Tag, Wallet } from 'lucide-react'; import { TrendingUp, Calendar, Wallet, Loader2 } from 'lucide-react';
import type { CabinetStats } from '../../lib/types'; import { useQuery } from '@tanstack/react-query';
import { apiRequest } from '@/shared/request/apiRequest';
import { links } from '@/shared/request/links';
// ─── Types ─────────────────────────────────────────────────────────────────────
type Stats = {
total_documents: number;
this_month_documents: number;
paid_price: number;
};
// ─── Single stat card ────────────────────────────────────────────────────────── // ─── Single stat card ──────────────────────────────────────────────────────────
@@ -33,46 +43,62 @@ const StatCard: React.FC<StatCardProps> = ({
</div> </div>
); );
const StatCardSkeleton = () => (
<div className="bg-white rounded-2xl border border-slate-100 p-5 shadow-sm animate-pulse">
<div className="w-10 h-10 rounded-xl bg-slate-100 mb-4" />
<div className="h-7 w-16 bg-slate-100 rounded mb-2" />
<div className="h-3 w-24 bg-slate-100 rounded" />
</div>
);
// ─── Grid ────────────────────────────────────────────────────────────────────── // ─── Grid ──────────────────────────────────────────────────────────────────────
interface StatsCardsProps { export const StatsCards = () => {
stats: CabinetStats; const { data, isLoading } = useQuery({
} queryKey: ['statistics'],
queryFn: (): Promise<Stats> =>
apiRequest('GET', links.statistics).then((res) => res.data as Stats),
});
export const StatsCards: React.FC<StatsCardsProps> = ({ stats }) => { if (isLoading) {
const discountPct = Math.round( return (
(stats.discountUsed / stats.discountTotal) * 100, <div className="grid grid-cols-2 lg:grid-cols-3 gap-4">
); <StatCardSkeleton />
<StatCardSkeleton />
<StatCardSkeleton />
</div>
);
}
if (!data) {
return (
<div className="flex items-center justify-center py-10 gap-2 text-slate-400">
<Loader2 size={18} className="animate-spin" />
<span className="text-sm">Ma&apos;lumot topilmadi</span>
</div>
);
}
return ( return (
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4"> <div className="grid grid-cols-2 lg:grid-cols-3 gap-4">
<StatCard <StatCard
icon={TrendingUp} icon={TrendingUp}
label="Jami tekshiruvlar" label="Jami tekshiruvlar"
value={String(stats.total)} value={String(data.total_documents)}
iconColor="text-blue-600" iconColor="text-blue-600"
iconBg="bg-blue-50" iconBg="bg-blue-50"
/> />
<StatCard <StatCard
icon={Calendar} icon={Calendar}
label="Bu oy" label="Bu oy"
value={String(stats.thisMonth)} value={String(data.this_month_documents)}
sub={`${stats.discountUsed}/${stats.discountTotal} ta hujjat`}
iconColor="text-emerald-600" iconColor="text-emerald-600"
iconBg="bg-emerald-50" iconBg="bg-emerald-50"
/> />
<StatCard
icon={Tag}
label="Chegirma holati"
value={`${discountPct}%`}
sub={`${stats.discountUsed}/${stats.discountTotal} ta ishlatilgan`}
iconColor="text-amber-600"
iconBg="bg-amber-50"
/>
<StatCard <StatCard
icon={Wallet} icon={Wallet}
label="Balans" label="To'langan summa"
value={`${stats.balance.toLocaleString()} ${stats.currency}`} value={`${data.paid_price.toLocaleString('uz-UZ')} UZS`}
iconColor="text-violet-600" iconColor="text-violet-600"
iconBg="bg-violet-50" iconBg="bg-violet-50"
/> />

View File

@@ -2,14 +2,12 @@ import React from 'react';
import { CtaCards } from './CtaCards'; import { CtaCards } from './CtaCards';
import { StatsCards } from './StatsCards'; import { StatsCards } from './StatsCards';
import { ModulesSection } from './ModulesSection'; import { ModulesSection } from './ModulesSection';
import type { CabinetStats } from '../../lib/types';
interface DashboardProps { interface DashboardProps {
stats: CabinetStats;
userName: string; userName: string;
} }
export const Dashboard: React.FC<DashboardProps> = ({ stats, userName }) => ( export const Dashboard: React.FC<DashboardProps> = ({ userName }) => (
<div className="space-y-6"> <div className="space-y-6">
<div> <div>
<h2 className="text-xl font-bold text-slate-900"> <h2 className="text-xl font-bold text-slate-900">
@@ -20,7 +18,7 @@ export const Dashboard: React.FC<DashboardProps> = ({ stats, userName }) => (
</p> </p>
</div> </div>
<StatsCards stats={stats} /> <StatsCards />
<div> <div>
<h3 className="text-xs font-semibold text-slate-400 uppercase tracking-widest mb-3"> <h3 className="text-xs font-semibold text-slate-400 uppercase tracking-widest mb-3">

View File

@@ -45,7 +45,7 @@ const ProfileSection = dynamic(
function SectionContent({ section }: { section: CabinetSection }) { function SectionContent({ section }: { section: CabinetSection }) {
switch (section) { switch (section) {
case 'dashboard': case 'dashboard':
return <Dashboard stats={MOCK_STATS} userName={MOCK_USER.name} />; return <Dashboard userName={MOCK_USER.name} />;
case 'plagiat': case 'plagiat':
return <PlagiatTable />; return <PlagiatTable />;
case 'si': case 'si':