ptechcore_ui 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.config.js +28 -0
- package/index.html +78 -0
- package/package.json +42 -0
- package/postcss.config.js +6 -0
- package/src/App.tsx +156 -0
- package/src/assets/imgs/login_illustration.png +0 -0
- package/src/components/common/Buttons.tsx +39 -0
- package/src/components/common/Cards.tsx +18 -0
- package/src/components/common/FDrawer.tsx +2448 -0
- package/src/components/common/FDrawer.types.ts +191 -0
- package/src/components/common/Inputs.tsx +409 -0
- package/src/components/common/Modals.tsx +41 -0
- package/src/components/common/Navigations.tsx +0 -0
- package/src/components/common/Toast.tsx +0 -0
- package/src/components/demo/ToastDemo.tsx +73 -0
- package/src/components/layout/Header.tsx +202 -0
- package/src/components/layout/ModernDoubleSidebarLayout.tsx +727 -0
- package/src/components/layout/PrivateLayout.tsx +52 -0
- package/src/components/layout/Sidebar.tsx +182 -0
- package/src/components/ui/Toast.tsx +93 -0
- package/src/contexts/SessionContext.tsx +77 -0
- package/src/contexts/ThemeContext.tsx +58 -0
- package/src/contexts/ToastContext.tsx +94 -0
- package/src/index.css +3 -0
- package/src/main.tsx +10 -0
- package/src/models/Organization.ts +47 -0
- package/src/models/Plan.ts +42 -0
- package/src/models/User.ts +23 -0
- package/src/pages/Analytics.tsx +101 -0
- package/src/pages/CreateOrganization.tsx +215 -0
- package/src/pages/Dashboard.tsx +15 -0
- package/src/pages/Home.tsx +12 -0
- package/src/pages/Profile.tsx +313 -0
- package/src/pages/Settings.tsx +382 -0
- package/src/pages/Team.tsx +180 -0
- package/src/pages/auth/Login.tsx +140 -0
- package/src/pages/auth/Register.tsx +302 -0
- package/src/pages/organizations/DetailEntity.tsx +1002 -0
- package/src/pages/organizations/DetailOrganizations.tsx +1629 -0
- package/src/pages/organizations/ListOrganizations.tsx +270 -0
- package/src/pages/pricings/CartPlan.tsx +486 -0
- package/src/pages/pricings/ListPricing.tsx +321 -0
- package/src/pages/users/CreateUser.tsx +450 -0
- package/src/pages/users/ListUsers.tsx +0 -0
- package/src/services/AuthServices.ts +94 -0
- package/src/services/OrganizationServices.ts +61 -0
- package/src/services/PlanSubscriptionServices.tsx +137 -0
- package/src/services/UserServices.ts +36 -0
- package/src/services/api.ts +64 -0
- package/src/styles/theme.ts +383 -0
- package/src/utils/utils.ts +48 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.js +158 -0
- package/tsconfig.app.json +24 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +22 -0
- package/vite.config.ts +10 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Menu, Search, Bell, User, ChevronDown, LogOut, Settings } from 'lucide-react';
|
|
3
|
+
import { useNavigate } from 'react-router-dom';
|
|
4
|
+
import { useToast } from '../../contexts/ToastContext';
|
|
5
|
+
|
|
6
|
+
interface HeaderProps {
|
|
7
|
+
onMenuClick: () => void;
|
|
8
|
+
sidebarOpen: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const Header: React.FC<HeaderProps> = ({ onMenuClick, sidebarOpen }) => {
|
|
12
|
+
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
13
|
+
const [notificationsOpen, setNotificationsOpen] = useState(false);
|
|
14
|
+
const navigate = useNavigate();
|
|
15
|
+
const { success } = useToast();
|
|
16
|
+
|
|
17
|
+
const handleLogout = () => {
|
|
18
|
+
localStorage.removeItem('token');
|
|
19
|
+
success('Déconnexion réussie');
|
|
20
|
+
navigate('/auth/login');
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Données utilisateur simulées (à remplacer par des vraies données)
|
|
24
|
+
const user = {
|
|
25
|
+
name: 'John Doe',
|
|
26
|
+
email: 'john@example.com',
|
|
27
|
+
avatar: null
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const notifications = [
|
|
31
|
+
{ id: 1, title: 'Nouvelle tâche assignée', time: '5 min', unread: true },
|
|
32
|
+
{ id: 2, title: 'Réunion dans 30 minutes', time: '25 min', unread: true },
|
|
33
|
+
{ id: 3, title: 'Rapport mensuel prêt', time: '1h', unread: false },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<header className="fixed top-0 left-0 right-0 z-30 bg-white border-b border-gray-200 h-16">
|
|
38
|
+
<div className="flex items-center justify-between h-full px-4">
|
|
39
|
+
{/* Left Section */}
|
|
40
|
+
<div className="flex items-center space-x-4">
|
|
41
|
+
{/* Menu Button */}
|
|
42
|
+
<button
|
|
43
|
+
onClick={onMenuClick}
|
|
44
|
+
className="p-2 rounded-lg hover:bg-gray-100 transition-colors"
|
|
45
|
+
>
|
|
46
|
+
<Menu className="w-5 h-5 text-gray-600" />
|
|
47
|
+
</button>
|
|
48
|
+
|
|
49
|
+
{/* Logo/Brand */}
|
|
50
|
+
<div className="flex items-center space-x-2">
|
|
51
|
+
<div className="w-8 h-8 bg-[#8290A9] rounded-full flex items-center justify-center">
|
|
52
|
+
<span className="text-white font-bold text-sm">R</span>
|
|
53
|
+
</div>
|
|
54
|
+
<span className="font-bold text-xl text-gray-800 hidden sm:block">
|
|
55
|
+
Rewise
|
|
56
|
+
</span>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
{/* Center Section - Search */}
|
|
61
|
+
<div className="hidden md:flex flex-1 max-w-lg mx-8">
|
|
62
|
+
<div className="relative w-full">
|
|
63
|
+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
|
|
64
|
+
<input
|
|
65
|
+
type="text"
|
|
66
|
+
placeholder="Rechercher..."
|
|
67
|
+
className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#8290A9] focus:border-transparent"
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
{/* Right Section */}
|
|
73
|
+
<div className="flex items-center space-x-4">
|
|
74
|
+
{/* Search Button (mobile) */}
|
|
75
|
+
<button className="p-2 rounded-lg hover:bg-gray-100 transition-colors md:hidden">
|
|
76
|
+
<Search className="w-5 h-5 text-gray-600" />
|
|
77
|
+
</button>
|
|
78
|
+
|
|
79
|
+
{/* Notifications */}
|
|
80
|
+
<div className="relative">
|
|
81
|
+
<button
|
|
82
|
+
onClick={() => setNotificationsOpen(!notificationsOpen)}
|
|
83
|
+
className="p-2 rounded-lg hover:bg-gray-100 transition-colors relative"
|
|
84
|
+
>
|
|
85
|
+
<Bell className="w-5 h-5 text-gray-600" />
|
|
86
|
+
{notifications.some(n => n.unread) && (
|
|
87
|
+
<span className="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full"></span>
|
|
88
|
+
)}
|
|
89
|
+
</button>
|
|
90
|
+
|
|
91
|
+
{/* Notifications Dropdown */}
|
|
92
|
+
{notificationsOpen && (
|
|
93
|
+
<div className="absolute right-0 mt-2 w-80 bg-white rounded-lg shadow-lg border border-gray-200 py-2 z-40">
|
|
94
|
+
<div className="px-4 py-2 border-b border-gray-100">
|
|
95
|
+
<h3 className="font-semibold text-gray-800">Notifications</h3>
|
|
96
|
+
</div>
|
|
97
|
+
<div className="max-h-64 overflow-y-auto">
|
|
98
|
+
{notifications.map((notification) => (
|
|
99
|
+
<div
|
|
100
|
+
key={notification.id}
|
|
101
|
+
className={`px-4 py-3 hover:bg-gray-50 cursor-pointer ${
|
|
102
|
+
notification.unread ? 'bg-blue-50' : ''
|
|
103
|
+
}`}
|
|
104
|
+
>
|
|
105
|
+
<div className="flex justify-between items-start">
|
|
106
|
+
<p className={`text-sm ${notification.unread ? 'font-medium' : ''}`}>
|
|
107
|
+
{notification.title}
|
|
108
|
+
</p>
|
|
109
|
+
<span className="text-xs text-gray-500">{notification.time}</span>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
))}
|
|
113
|
+
</div>
|
|
114
|
+
<div className="px-4 py-2 border-t border-gray-100">
|
|
115
|
+
<button className="text-sm text-[#8290A9] hover:text-[#6B7C92]">
|
|
116
|
+
Voir toutes les notifications
|
|
117
|
+
</button>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
{/* User Menu */}
|
|
124
|
+
<div className="relative">
|
|
125
|
+
<button
|
|
126
|
+
onClick={() => setDropdownOpen(!dropdownOpen)}
|
|
127
|
+
className="flex items-center space-x-2 p-2 rounded-lg hover:bg-gray-100 transition-colors"
|
|
128
|
+
>
|
|
129
|
+
<div className="w-8 h-8 bg-[#8290A9] rounded-full flex items-center justify-center">
|
|
130
|
+
{user.avatar ? (
|
|
131
|
+
<img src={user.avatar} alt={user.name} className="w-8 h-8 rounded-full" />
|
|
132
|
+
) : (
|
|
133
|
+
<User className="w-4 h-4 text-white" />
|
|
134
|
+
)}
|
|
135
|
+
</div>
|
|
136
|
+
<div className="hidden sm:block text-left">
|
|
137
|
+
<p className="text-sm font-medium text-gray-700">{user.name}</p>
|
|
138
|
+
</div>
|
|
139
|
+
<ChevronDown className="w-4 h-4 text-gray-500" />
|
|
140
|
+
</button>
|
|
141
|
+
|
|
142
|
+
{/* User Dropdown */}
|
|
143
|
+
{dropdownOpen && (
|
|
144
|
+
<div className="absolute right-0 mt-2 w-56 bg-white rounded-lg shadow-lg border border-gray-200 py-2 z-40">
|
|
145
|
+
<div className="px-4 py-3 border-b border-gray-100">
|
|
146
|
+
<p className="font-medium text-gray-800">{user.name}</p>
|
|
147
|
+
<p className="text-sm text-gray-500">{user.email}</p>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div className="py-2">
|
|
151
|
+
<button
|
|
152
|
+
onClick={() => {
|
|
153
|
+
navigate('/profile');
|
|
154
|
+
setDropdownOpen(false);
|
|
155
|
+
}}
|
|
156
|
+
className="w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-50 flex items-center space-x-2"
|
|
157
|
+
>
|
|
158
|
+
<User className="w-4 h-4" />
|
|
159
|
+
<span>Mon profil</span>
|
|
160
|
+
</button>
|
|
161
|
+
<button
|
|
162
|
+
onClick={() => {
|
|
163
|
+
navigate('/settings');
|
|
164
|
+
setDropdownOpen(false);
|
|
165
|
+
}}
|
|
166
|
+
className="w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-50 flex items-center space-x-2"
|
|
167
|
+
>
|
|
168
|
+
<Settings className="w-4 h-4" />
|
|
169
|
+
<span>Paramètres</span>
|
|
170
|
+
</button>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<div className="border-t border-gray-100 py-2">
|
|
174
|
+
<button
|
|
175
|
+
onClick={handleLogout}
|
|
176
|
+
className="w-full px-4 py-2 text-left text-sm text-red-600 hover:bg-red-50 flex items-center space-x-2"
|
|
177
|
+
>
|
|
178
|
+
<LogOut className="w-4 h-4" />
|
|
179
|
+
<span>Se déconnecter</span>
|
|
180
|
+
</button>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
{/* Click outside to close dropdowns */}
|
|
189
|
+
{(dropdownOpen || notificationsOpen) && (
|
|
190
|
+
<div
|
|
191
|
+
className="fixed inset-0 z-10"
|
|
192
|
+
onClick={() => {
|
|
193
|
+
setDropdownOpen(false);
|
|
194
|
+
setNotificationsOpen(false);
|
|
195
|
+
}}
|
|
196
|
+
/>
|
|
197
|
+
)}
|
|
198
|
+
</header>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export default Header;
|