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.
Files changed (57) hide show
  1. package/eslint.config.js +28 -0
  2. package/index.html +78 -0
  3. package/package.json +42 -0
  4. package/postcss.config.js +6 -0
  5. package/src/App.tsx +156 -0
  6. package/src/assets/imgs/login_illustration.png +0 -0
  7. package/src/components/common/Buttons.tsx +39 -0
  8. package/src/components/common/Cards.tsx +18 -0
  9. package/src/components/common/FDrawer.tsx +2448 -0
  10. package/src/components/common/FDrawer.types.ts +191 -0
  11. package/src/components/common/Inputs.tsx +409 -0
  12. package/src/components/common/Modals.tsx +41 -0
  13. package/src/components/common/Navigations.tsx +0 -0
  14. package/src/components/common/Toast.tsx +0 -0
  15. package/src/components/demo/ToastDemo.tsx +73 -0
  16. package/src/components/layout/Header.tsx +202 -0
  17. package/src/components/layout/ModernDoubleSidebarLayout.tsx +727 -0
  18. package/src/components/layout/PrivateLayout.tsx +52 -0
  19. package/src/components/layout/Sidebar.tsx +182 -0
  20. package/src/components/ui/Toast.tsx +93 -0
  21. package/src/contexts/SessionContext.tsx +77 -0
  22. package/src/contexts/ThemeContext.tsx +58 -0
  23. package/src/contexts/ToastContext.tsx +94 -0
  24. package/src/index.css +3 -0
  25. package/src/main.tsx +10 -0
  26. package/src/models/Organization.ts +47 -0
  27. package/src/models/Plan.ts +42 -0
  28. package/src/models/User.ts +23 -0
  29. package/src/pages/Analytics.tsx +101 -0
  30. package/src/pages/CreateOrganization.tsx +215 -0
  31. package/src/pages/Dashboard.tsx +15 -0
  32. package/src/pages/Home.tsx +12 -0
  33. package/src/pages/Profile.tsx +313 -0
  34. package/src/pages/Settings.tsx +382 -0
  35. package/src/pages/Team.tsx +180 -0
  36. package/src/pages/auth/Login.tsx +140 -0
  37. package/src/pages/auth/Register.tsx +302 -0
  38. package/src/pages/organizations/DetailEntity.tsx +1002 -0
  39. package/src/pages/organizations/DetailOrganizations.tsx +1629 -0
  40. package/src/pages/organizations/ListOrganizations.tsx +270 -0
  41. package/src/pages/pricings/CartPlan.tsx +486 -0
  42. package/src/pages/pricings/ListPricing.tsx +321 -0
  43. package/src/pages/users/CreateUser.tsx +450 -0
  44. package/src/pages/users/ListUsers.tsx +0 -0
  45. package/src/services/AuthServices.ts +94 -0
  46. package/src/services/OrganizationServices.ts +61 -0
  47. package/src/services/PlanSubscriptionServices.tsx +137 -0
  48. package/src/services/UserServices.ts +36 -0
  49. package/src/services/api.ts +64 -0
  50. package/src/styles/theme.ts +383 -0
  51. package/src/utils/utils.ts +48 -0
  52. package/src/vite-env.d.ts +1 -0
  53. package/tailwind.config.js +158 -0
  54. package/tsconfig.app.json +24 -0
  55. package/tsconfig.json +7 -0
  56. package/tsconfig.node.json +22 -0
  57. package/vite.config.ts +10 -0
@@ -0,0 +1,382 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ Bell,
4
+ Shield,
5
+ Palette,
6
+ Globe,
7
+ Monitor,
8
+ Moon,
9
+ Sun,
10
+ Eye,
11
+ Lock,
12
+ Smartphone,
13
+ Key,
14
+ Trash2,
15
+ Save,
16
+ AlertTriangle
17
+ } from 'lucide-react';
18
+ import { useToast } from '../contexts/ToastContext';
19
+
20
+ const Settings: React.FC = () => {
21
+ const [activeTab, setActiveTab] = useState('general');
22
+ const [loading, setLoading] = useState(false);
23
+ const { success, error: showError, warning } = useToast();
24
+
25
+ const [settings, setSettings] = useState({
26
+ // General Settings
27
+ language: 'fr',
28
+ timezone: 'Europe/Paris',
29
+ theme: 'light',
30
+
31
+ // Notifications
32
+ emailNotifications: true,
33
+ pushNotifications: true,
34
+ weeklyReport: true,
35
+ taskReminders: true,
36
+ teamUpdates: false,
37
+
38
+ // Privacy & Security
39
+ twoFactorAuth: false,
40
+ profileVisibility: 'team',
41
+ activityStatus: true,
42
+ dataSharing: false,
43
+
44
+ // Appearance
45
+ sidebarCollapsed: false,
46
+ compactMode: false,
47
+ animations: true
48
+ });
49
+
50
+ const handleSettingChange = (key: string, value: any) => {
51
+ setSettings(prev => ({ ...prev, [key]: value }));
52
+ };
53
+
54
+ const handleSave = async () => {
55
+ setLoading(true);
56
+ try {
57
+ // Simuler un appel API
58
+ await new Promise(resolve => setTimeout(resolve, 1000));
59
+ success('Paramètres sauvegardés avec succès !');
60
+ } catch (error) {
61
+ showError('Erreur lors de la sauvegarde des paramètres');
62
+ } finally {
63
+ setLoading(false);
64
+ }
65
+ };
66
+
67
+ const handleResetPassword = () => {
68
+ warning('Un email de réinitialisation sera envoyé');
69
+ };
70
+
71
+ const handleDeleteAccount = () => {
72
+ showError('Fonctionnalité de suppression de compte non disponible');
73
+ };
74
+
75
+ const tabs = [
76
+ { id: 'general', label: 'Général', icon: Monitor },
77
+ { id: 'notifications', label: 'Notifications', icon: Bell },
78
+ { id: 'security', label: 'Sécurité', icon: Shield },
79
+ { id: 'appearance', label: 'Apparence', icon: Palette },
80
+ { id: 'privacy', label: 'Confidentialité', icon: Eye }
81
+ ];
82
+
83
+ const ToggleSwitch = ({ enabled, onChange, label, description }: {
84
+ enabled: boolean;
85
+ onChange: (value: boolean) => void;
86
+ label: string;
87
+ description?: string;
88
+ }) => (
89
+ <div className="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
90
+ <div>
91
+ <h4 className="font-medium text-gray-900">{label}</h4>
92
+ {description && <p className="text-sm text-gray-600">{description}</p>}
93
+ </div>
94
+ <button
95
+ onClick={() => onChange(!enabled)}
96
+ className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
97
+ enabled ? 'bg-[#8290A9]' : 'bg-gray-300'
98
+ }`}
99
+ >
100
+ <span
101
+ className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
102
+ enabled ? 'translate-x-6' : 'translate-x-1'
103
+ }`}
104
+ />
105
+ </button>
106
+ </div>
107
+ );
108
+
109
+ const SelectField = ({ value, onChange, options, label }: {
110
+ value: string;
111
+ onChange: (value: string) => void;
112
+ options: { value: string; label: string }[];
113
+ label: string;
114
+ }) => (
115
+ <div>
116
+ <label className="block text-sm font-medium text-gray-700 mb-2">{label}</label>
117
+ <select
118
+ value={value}
119
+ onChange={(e) => onChange(e.target.value)}
120
+ className="w-full px-3 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#8290A9] focus:border-transparent"
121
+ >
122
+ {options.map((option) => (
123
+ <option key={option.value} value={option.value}>
124
+ {option.label}
125
+ </option>
126
+ ))}
127
+ </select>
128
+ </div>
129
+ );
130
+
131
+ const renderTabContent = () => {
132
+ switch (activeTab) {
133
+ case 'general':
134
+ return (
135
+ <div className="space-y-6">
136
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
137
+ <SelectField
138
+ label="Langue"
139
+ value={settings.language}
140
+ onChange={(value) => handleSettingChange('language', value)}
141
+ options={[
142
+ { value: 'fr', label: 'Français' },
143
+ { value: 'en', label: 'English' },
144
+ { value: 'es', label: 'Español' }
145
+ ]}
146
+ />
147
+ <SelectField
148
+ label="Fuseau horaire"
149
+ value={settings.timezone}
150
+ onChange={(value) => handleSettingChange('timezone', value)}
151
+ options={[
152
+ { value: 'Europe/Paris', label: 'Paris (UTC+1)' },
153
+ { value: 'Europe/London', label: 'Londres (UTC+0)' },
154
+ { value: 'America/New_York', label: 'New York (UTC-5)' }
155
+ ]}
156
+ />
157
+ </div>
158
+ </div>
159
+ );
160
+
161
+ case 'notifications':
162
+ return (
163
+ <div className="space-y-4">
164
+ <ToggleSwitch
165
+ enabled={settings.emailNotifications}
166
+ onChange={(value) => handleSettingChange('emailNotifications', value)}
167
+ label="Notifications par email"
168
+ description="Recevoir des notifications importantes par email"
169
+ />
170
+ <ToggleSwitch
171
+ enabled={settings.pushNotifications}
172
+ onChange={(value) => handleSettingChange('pushNotifications', value)}
173
+ label="Notifications push"
174
+ description="Recevoir des notifications en temps réel"
175
+ />
176
+ <ToggleSwitch
177
+ enabled={settings.weeklyReport}
178
+ onChange={(value) => handleSettingChange('weeklyReport', value)}
179
+ label="Rapport hebdomadaire"
180
+ description="Recevoir un résumé de votre activité chaque semaine"
181
+ />
182
+ <ToggleSwitch
183
+ enabled={settings.taskReminders}
184
+ onChange={(value) => handleSettingChange('taskReminders', value)}
185
+ label="Rappels de tâches"
186
+ description="Recevoir des rappels pour les tâches en retard"
187
+ />
188
+ <ToggleSwitch
189
+ enabled={settings.teamUpdates}
190
+ onChange={(value) => handleSettingChange('teamUpdates', value)}
191
+ label="Mises à jour d'équipe"
192
+ description="Recevoir des notifications sur l'activité de l'équipe"
193
+ />
194
+ </div>
195
+ );
196
+
197
+ case 'security':
198
+ return (
199
+ <div className="space-y-6">
200
+ <ToggleSwitch
201
+ enabled={settings.twoFactorAuth}
202
+ onChange={(value) => handleSettingChange('twoFactorAuth', value)}
203
+ label="Authentification à deux facteurs"
204
+ description="Ajouter une couche de sécurité supplémentaire"
205
+ />
206
+
207
+ <div className="bg-gray-50 rounded-lg p-4 space-y-4">
208
+ <h4 className="font-medium text-gray-900 flex items-center space-x-2">
209
+ <Key className="w-4 h-4" />
210
+ <span>Gestion du mot de passe</span>
211
+ </h4>
212
+ <button
213
+ onClick={handleResetPassword}
214
+ className="bg-[#8290A9] text-white px-4 py-2 rounded-lg hover:bg-[#6B7C92] transition-colors"
215
+ >
216
+ Réinitialiser le mot de passe
217
+ </button>
218
+ </div>
219
+
220
+ <div className="bg-red-50 border border-red-200 rounded-lg p-4">
221
+ <h4 className="font-medium text-red-900 flex items-center space-x-2 mb-2">
222
+ <AlertTriangle className="w-4 h-4" />
223
+ <span>Zone de danger</span>
224
+ </h4>
225
+ <p className="text-sm text-red-700 mb-4">
226
+ Cette action est irréversible et supprimera définitivement votre compte.
227
+ </p>
228
+ <button
229
+ onClick={handleDeleteAccount}
230
+ className="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors flex items-center space-x-2"
231
+ >
232
+ <Trash2 className="w-4 h-4" />
233
+ <span>Supprimer le compte</span>
234
+ </button>
235
+ </div>
236
+ </div>
237
+ );
238
+
239
+ case 'appearance':
240
+ return (
241
+ <div className="space-y-6">
242
+ <div>
243
+ <label className="block text-sm font-medium text-gray-700 mb-3">Thème</label>
244
+ <div className="grid grid-cols-3 gap-4">
245
+ {[
246
+ { value: 'light', label: 'Clair', icon: Sun },
247
+ { value: 'dark', label: 'Sombre', icon: Moon },
248
+ { value: 'auto', label: 'Auto', icon: Monitor }
249
+ ].map((theme) => {
250
+ const Icon = theme.icon;
251
+ return (
252
+ <button
253
+ key={theme.value}
254
+ onClick={() => handleSettingChange('theme', theme.value)}
255
+ className={`p-4 border-2 rounded-lg transition-colors ${
256
+ settings.theme === theme.value
257
+ ? 'border-[#8290A9] bg-blue-50'
258
+ : 'border-gray-200 hover:border-gray-300'
259
+ }`}
260
+ >
261
+ <Icon className="w-6 h-6 mx-auto mb-2 text-gray-600" />
262
+ <span className="text-sm font-medium">{theme.label}</span>
263
+ </button>
264
+ );
265
+ })}
266
+ </div>
267
+ </div>
268
+
269
+ <ToggleSwitch
270
+ enabled={settings.sidebarCollapsed}
271
+ onChange={(value) => handleSettingChange('sidebarCollapsed', value)}
272
+ label="Sidebar réduite par défaut"
273
+ description="Commencer avec la sidebar réduite"
274
+ />
275
+
276
+ <ToggleSwitch
277
+ enabled={settings.compactMode}
278
+ onChange={(value) => handleSettingChange('compactMode', value)}
279
+ label="Mode compact"
280
+ description="Affichage plus dense pour économiser l'espace"
281
+ />
282
+
283
+ <ToggleSwitch
284
+ enabled={settings.animations}
285
+ onChange={(value) => handleSettingChange('animations', value)}
286
+ label="Animations"
287
+ description="Activer les animations et transitions"
288
+ />
289
+ </div>
290
+ );
291
+
292
+ case 'privacy':
293
+ return (
294
+ <div className="space-y-6">
295
+ <SelectField
296
+ label="Visibilité du profil"
297
+ value={settings.profileVisibility}
298
+ onChange={(value) => handleSettingChange('profileVisibility', value)}
299
+ options={[
300
+ { value: 'public', label: 'Public' },
301
+ { value: 'team', label: 'Équipe uniquement' },
302
+ { value: 'private', label: 'Privé' }
303
+ ]}
304
+ />
305
+
306
+ <ToggleSwitch
307
+ enabled={settings.activityStatus}
308
+ onChange={(value) => handleSettingChange('activityStatus', value)}
309
+ label="Statut d'activité"
310
+ description="Permettre aux autres de voir quand vous êtes en ligne"
311
+ />
312
+
313
+ <ToggleSwitch
314
+ enabled={settings.dataSharing}
315
+ onChange={(value) => handleSettingChange('dataSharing', value)}
316
+ label="Partage de données analytiques"
317
+ description="Partager des données anonymisées pour améliorer le service"
318
+ />
319
+ </div>
320
+ );
321
+
322
+ default:
323
+ return null;
324
+ }
325
+ };
326
+
327
+ return (
328
+ <div className="space-y-6">
329
+ {/* Header */}
330
+ <div className="flex items-center justify-between">
331
+ <div>
332
+ <h1 className="text-3xl font-bold text-gray-900">Paramètres</h1>
333
+ <p className="text-gray-600 mt-2">
334
+ Gérez vos préférences et la configuration de votre compte
335
+ </p>
336
+ </div>
337
+ <button
338
+ onClick={handleSave}
339
+ disabled={loading}
340
+ className="bg-[#8290A9] text-white px-4 py-2 rounded-lg hover:bg-[#6B7C92] transition-colors flex items-center space-x-2 disabled:opacity-50"
341
+ >
342
+ <Save className="w-4 h-4" />
343
+ <span>{loading ? 'Sauvegarde...' : 'Sauvegarder'}</span>
344
+ </button>
345
+ </div>
346
+
347
+ <div className="flex flex-col lg:flex-row gap-6">
348
+ {/* Sidebar */}
349
+ <div className="lg:w-64">
350
+ <nav className="space-y-2">
351
+ {tabs.map((tab) => {
352
+ const Icon = tab.icon;
353
+ return (
354
+ <button
355
+ key={tab.id}
356
+ onClick={() => setActiveTab(tab.id)}
357
+ className={`w-full flex items-center space-x-3 px-4 py-3 rounded-lg transition-colors ${
358
+ activeTab === tab.id
359
+ ? 'bg-[#8290A9] text-white'
360
+ : 'text-gray-600 hover:bg-gray-100'
361
+ }`}
362
+ >
363
+ <Icon className="w-5 h-5" />
364
+ <span className="font-medium">{tab.label}</span>
365
+ </button>
366
+ );
367
+ })}
368
+ </nav>
369
+ </div>
370
+
371
+ {/* Content */}
372
+ <div className="flex-1">
373
+ <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
374
+ {renderTabContent()}
375
+ </div>
376
+ </div>
377
+ </div>
378
+ </div>
379
+ );
380
+ };
381
+
382
+ export default Settings;
@@ -0,0 +1,180 @@
1
+ import React, { useState } from 'react';
2
+ import { Plus, Search, Filter, MoreVertical, Mail, Phone, MapPin } from 'lucide-react';
3
+
4
+ const Team: React.FC = () => {
5
+ const [searchTerm, setSearchTerm] = useState('');
6
+
7
+ const teamMembers = [
8
+ {
9
+ id: 1,
10
+ name: 'Alice Martin',
11
+ role: 'Lead Developer',
12
+ email: 'alice.martin@rewise.com',
13
+ phone: '+33 6 12 34 56 78',
14
+ location: 'Paris, France',
15
+ avatar: null,
16
+ status: 'online',
17
+ projects: 3
18
+ },
19
+ {
20
+ id: 2,
21
+ name: 'Thomas Dubois',
22
+ role: 'UI/UX Designer',
23
+ email: 'thomas.dubois@rewise.com',
24
+ phone: '+33 6 87 65 43 21',
25
+ location: 'Lyon, France',
26
+ avatar: null,
27
+ status: 'away',
28
+ projects: 2
29
+ },
30
+ {
31
+ id: 3,
32
+ name: 'Sophie Laurent',
33
+ role: 'Project Manager',
34
+ email: 'sophie.laurent@rewise.com',
35
+ phone: '+33 6 11 22 33 44',
36
+ location: 'Marseille, France',
37
+ avatar: null,
38
+ status: 'online',
39
+ projects: 5
40
+ },
41
+ {
42
+ id: 4,
43
+ name: 'Pierre Moreau',
44
+ role: 'Backend Developer',
45
+ email: 'pierre.moreau@rewise.com',
46
+ phone: '+33 6 55 66 77 88',
47
+ location: 'Toulouse, France',
48
+ avatar: null,
49
+ status: 'offline',
50
+ projects: 2
51
+ }
52
+ ];
53
+
54
+ const filteredMembers = teamMembers.filter(member =>
55
+ member.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
56
+ member.role.toLowerCase().includes(searchTerm.toLowerCase())
57
+ );
58
+
59
+ const getStatusColor = (status: string) => {
60
+ switch (status) {
61
+ case 'online': return 'bg-green-500';
62
+ case 'away': return 'bg-yellow-500';
63
+ case 'offline': return 'bg-gray-400';
64
+ default: return 'bg-gray-400';
65
+ }
66
+ };
67
+
68
+ const getInitials = (name: string) => {
69
+ return name.split(' ').map(n => n[0]).join('').toUpperCase();
70
+ };
71
+
72
+ return (
73
+ <div className="space-y-6">
74
+ {/* Header */}
75
+ <div className="flex items-center justify-between">
76
+ <div>
77
+ <h1 className="text-3xl font-bold text-gray-900">Équipe</h1>
78
+ <p className="text-gray-600 mt-2">
79
+ Gérez votre équipe et suivez les performances de chaque membre
80
+ </p>
81
+ </div>
82
+ <button className="bg-[#8290A9] text-white px-4 py-2 rounded-lg hover:bg-[#6B7C92] transition-colors flex items-center space-x-2">
83
+ <Plus className="w-4 h-4" />
84
+ <span>Ajouter un membre</span>
85
+ </button>
86
+ </div>
87
+
88
+ {/* Filters */}
89
+ <div className="flex items-center space-x-4 bg-white p-4 rounded-lg shadow-sm border border-gray-200">
90
+ <div className="flex-1 relative">
91
+ <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
92
+ <input
93
+ type="text"
94
+ placeholder="Rechercher un membre..."
95
+ value={searchTerm}
96
+ onChange={(e) => setSearchTerm(e.target.value)}
97
+ 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"
98
+ />
99
+ </div>
100
+ <button className="flex items-center space-x-2 px-4 py-2 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors">
101
+ <Filter className="w-4 h-4" />
102
+ <span>Filtres</span>
103
+ </button>
104
+ </div>
105
+
106
+ {/* Team Stats */}
107
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
108
+ <div className="bg-white rounded-lg p-6 shadow-sm border border-gray-200">
109
+ <h3 className="text-lg font-semibold text-gray-900">Total membres</h3>
110
+ <p className="text-3xl font-bold text-[#8290A9] mt-2">{teamMembers.length}</p>
111
+ </div>
112
+ <div className="bg-white rounded-lg p-6 shadow-sm border border-gray-200">
113
+ <h3 className="text-lg font-semibold text-gray-900">En ligne</h3>
114
+ <p className="text-3xl font-bold text-green-600 mt-2">
115
+ {teamMembers.filter(m => m.status === 'online').length}
116
+ </p>
117
+ </div>
118
+ <div className="bg-white rounded-lg p-6 shadow-sm border border-gray-200">
119
+ <h3 className="text-lg font-semibold text-gray-900">Projets actifs</h3>
120
+ <p className="text-3xl font-bold text-blue-600 mt-2">
121
+ {teamMembers.reduce((sum, m) => sum + m.projects, 0)}
122
+ </p>
123
+ </div>
124
+ </div>
125
+
126
+ {/* Team Members Grid */}
127
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
128
+ {filteredMembers.map((member) => (
129
+ <div key={member.id} className="bg-white rounded-lg p-6 shadow-sm border border-gray-200">
130
+ <div className="flex items-center justify-between mb-4">
131
+ <div className="flex items-center space-x-3">
132
+ <div className="relative">
133
+ <div className="w-12 h-12 bg-[#8290A9] rounded-full flex items-center justify-center">
134
+ <span className="text-white font-semibold">
135
+ {getInitials(member.name)}
136
+ </span>
137
+ </div>
138
+ <div className={`absolute -bottom-1 -right-1 w-4 h-4 rounded-full border-2 border-white ${getStatusColor(member.status)}`}></div>
139
+ </div>
140
+ <div>
141
+ <h3 className="font-semibold text-gray-900">{member.name}</h3>
142
+ <p className="text-sm text-gray-600">{member.role}</p>
143
+ </div>
144
+ </div>
145
+ <button className="p-2 hover:bg-gray-100 rounded-lg transition-colors">
146
+ <MoreVertical className="w-4 h-4 text-gray-400" />
147
+ </button>
148
+ </div>
149
+
150
+ <div className="space-y-3">
151
+ <div className="flex items-center space-x-2 text-sm text-gray-600">
152
+ <Mail className="w-4 h-4" />
153
+ <span>{member.email}</span>
154
+ </div>
155
+ <div className="flex items-center space-x-2 text-sm text-gray-600">
156
+ <Phone className="w-4 h-4" />
157
+ <span>{member.phone}</span>
158
+ </div>
159
+ <div className="flex items-center space-x-2 text-sm text-gray-600">
160
+ <MapPin className="w-4 h-4" />
161
+ <span>{member.location}</span>
162
+ </div>
163
+ </div>
164
+
165
+ <div className="mt-4 pt-4 border-t border-gray-100">
166
+ <div className="flex items-center justify-between">
167
+ <span className="text-sm text-gray-600">Projets actifs</span>
168
+ <span className="bg-[#8290A9] text-white px-2 py-1 rounded-full text-xs">
169
+ {member.projects}
170
+ </span>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ ))}
175
+ </div>
176
+ </div>
177
+ );
178
+ };
179
+
180
+ export default Team;