🚀 Final: Fix stats, staff list, settings profile, and logout redirect
This commit is contained in:
@@ -62,6 +62,16 @@ export class AuthController {
|
||||
return this.authService.logout(user.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* الملف الشخصي الحالي والبيانات الأساسية
|
||||
*/
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('me')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
async me(@CurrentUser() user: any) {
|
||||
return this.authService.getMe(user.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* الملف الشخصي
|
||||
*/
|
||||
|
||||
@@ -179,6 +179,29 @@ export class AuthService {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* الحصول على بيانات المستخدم والاشتراك الحالي
|
||||
*/
|
||||
async getMe(userId: string) {
|
||||
const user = await this.dataSource.getRepository(User).findOne({
|
||||
where: { id: userId },
|
||||
relations: ['tenant'],
|
||||
});
|
||||
|
||||
if (!user) throw new UnauthorizedException();
|
||||
|
||||
return {
|
||||
user: {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
tenantId: user.tenant_id,
|
||||
},
|
||||
tenant: user.tenant,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* تسجيل خروج
|
||||
*/
|
||||
|
||||
@@ -22,13 +22,6 @@ export class DashboardService {
|
||||
where: { tenant_id: tenantId, status: InvoiceStatus.APPROVED },
|
||||
});
|
||||
|
||||
const pendingInvoices = await this.invoiceRepository.count({
|
||||
where: {
|
||||
tenant_id: tenantId,
|
||||
status: Buffer.from('approved').toString() === InvoiceStatus.APPROVED ? InvoiceStatus.UPLOADED : InvoiceStatus.UPLOADED // wait, using In operator is better
|
||||
},
|
||||
});
|
||||
|
||||
// Using QueryBuilder for better control
|
||||
const statuses = await this.invoiceRepository
|
||||
.createQueryBuilder('invoice')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* ════════════════════════════════════════════════════════════
|
||||
*/
|
||||
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { NavLink, useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
LayoutDashboard,
|
||||
FileText,
|
||||
@@ -24,8 +24,14 @@ const menuItems = [
|
||||
];
|
||||
|
||||
export const Sidebar = () => {
|
||||
const navigate = useNavigate();
|
||||
const clearAuth = useAuthStore((state) => state.clearAuth);
|
||||
|
||||
const handleLogout = () => {
|
||||
clearAuth();
|
||||
navigate('/login');
|
||||
};
|
||||
|
||||
return (
|
||||
<aside className="w-64 h-screen glass border-l border-slate-200 sticky top-0 flex flex-col p-4">
|
||||
<div className="flex items-center gap-3 px-2 py-6">
|
||||
@@ -58,7 +64,7 @@ export const Sidebar = () => {
|
||||
|
||||
<div className="pt-4 border-t border-slate-100">
|
||||
<button
|
||||
onClick={clearAuth}
|
||||
onClick={handleLogout}
|
||||
className="flex items-center gap-3 px-4 py-3 w-full rounded-xl text-red-500 hover:bg-red-50 transition-all group"
|
||||
>
|
||||
<LogOut className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
|
||||
|
||||
@@ -40,7 +40,7 @@ export const StaffPage = () => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
await apiClient.post('/users', {
|
||||
full_name: fullName,
|
||||
name: fullName,
|
||||
email,
|
||||
password,
|
||||
role
|
||||
@@ -108,7 +108,7 @@ export const StaffPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 className="text-xl font-bold text-slate-900 mb-1">{member.full_name}</h3>
|
||||
<h3 className="text-xl font-bold text-slate-900 mb-1">{member.name}</h3>
|
||||
<div className="flex items-center gap-2 mb-6">
|
||||
<span className={`text-[10px] font-black uppercase tracking-widest px-2 py-0.5 rounded-md ${
|
||||
member.role === 'admin' ? 'bg-indigo-50 text-indigo-600' : 'bg-slate-50 text-slate-600'
|
||||
|
||||
Reference in New Issue
Block a user