@lastbrain/module-auth 0.1.22 → 1.0.1

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 (49) hide show
  1. package/dist/api/admin/signup-stats.d.ts +21 -0
  2. package/dist/api/admin/signup-stats.d.ts.map +1 -0
  3. package/dist/api/admin/signup-stats.js +75 -0
  4. package/dist/api/admin/users-by-source.d.ts +22 -0
  5. package/dist/api/admin/users-by-source.d.ts.map +1 -0
  6. package/dist/api/admin/users-by-source.js +56 -0
  7. package/dist/api/public/signup.d.ts +10 -0
  8. package/dist/api/public/signup.d.ts.map +1 -0
  9. package/dist/api/public/signup.js +71 -0
  10. package/dist/auth.build.config.d.ts.map +1 -1
  11. package/dist/auth.build.config.js +26 -0
  12. package/dist/components/AccountButton.d.ts.map +1 -1
  13. package/dist/index.d.ts +17 -16
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +17 -16
  16. package/dist/server.d.ts +1 -0
  17. package/dist/server.d.ts.map +1 -1
  18. package/dist/server.js +1 -0
  19. package/dist/web/admin/signup-stats.d.ts +2 -0
  20. package/dist/web/admin/signup-stats.d.ts.map +1 -0
  21. package/dist/web/admin/signup-stats.js +50 -0
  22. package/dist/web/admin/user-detail.d.ts.map +1 -1
  23. package/dist/web/admin/user-detail.js +5 -1
  24. package/dist/web/admin/users/[id].js +1 -1
  25. package/dist/web/admin/users-by-signup-source.d.ts +2 -0
  26. package/dist/web/admin/users-by-signup-source.d.ts.map +1 -0
  27. package/dist/web/admin/users-by-signup-source.js +79 -0
  28. package/dist/web/auth/profile.js +18 -18
  29. package/dist/web/public/SignUpPage.d.ts.map +1 -1
  30. package/dist/web/public/SignUpPage.js +15 -23
  31. package/package.json +4 -4
  32. package/src/api/admin/signup-stats.ts +109 -0
  33. package/src/api/admin/users-by-source.ts +87 -0
  34. package/src/api/public/signup.ts +106 -0
  35. package/src/auth.build.config.ts +27 -0
  36. package/src/components/AccountButton.tsx +0 -1
  37. package/src/index.ts +17 -16
  38. package/src/server.ts +1 -0
  39. package/src/web/admin/signup-stats.tsx +304 -0
  40. package/src/web/admin/user-detail.tsx +17 -2
  41. package/src/web/admin/users/[id].tsx +1 -1
  42. package/src/web/admin/users-by-signup-source.tsx +262 -0
  43. package/src/web/admin/users.tsx +1 -1
  44. package/src/web/auth/profile.tsx +6 -6
  45. package/src/web/public/SignUpPage.tsx +16 -25
  46. package/supabase/migrations/20251112000000_user_init.sql +18 -1
  47. package/supabase/migrations/20251112000001_auto_profile_and_admin_view.sql +10 -2
  48. package/supabase/migrations/20251124000001_add_get_admin_user_details.sql +2 -1
  49. package/supabase/migrations-down/20251204000000_add_signup_source.sql +12 -0
@@ -0,0 +1,21 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ interface SignupStats {
3
+ total: number;
4
+ bySource: {
5
+ lastbrain: number;
6
+ recipe: number;
7
+ };
8
+ byDate: Array<{
9
+ date: string;
10
+ lastbrain: number;
11
+ recipe: number;
12
+ total: number;
13
+ }>;
14
+ }
15
+ export declare function GET(_request: NextRequest): Promise<NextResponse<{
16
+ error: string;
17
+ }> | NextResponse<{
18
+ data: SignupStats;
19
+ }>>;
20
+ export {};
21
+ //# sourceMappingURL=signup-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signup-stats.d.ts","sourceRoot":"","sources":["../../../src/api/admin/signup-stats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,wBAAsB,GAAG,CAAC,QAAQ,EAAE,WAAW;;;;IAuC9C"}
@@ -0,0 +1,75 @@
1
+ import { getSupabaseServiceClient } from "@lastbrain/core/server";
2
+ import { NextResponse } from "next/server";
3
+ export async function GET(_request) {
4
+ try {
5
+ const supabase = await getSupabaseServiceClient();
6
+ // Get total signups by source
7
+ const { data: signupData, error: signupError } = await supabase
8
+ .from("user_profil")
9
+ .select("signup_source", { count: "exact" })
10
+ .order("created_at", { ascending: false });
11
+ if (signupError) {
12
+ return NextResponse.json({ error: signupError.message }, { status: 400 });
13
+ }
14
+ // Get signups by date and source (last 30 days)
15
+ const thirtyDaysAgo = new Date();
16
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
17
+ const { data: dateData, error: dateError } = await supabase
18
+ .from("user_profil")
19
+ .select("created_at, signup_source")
20
+ .gte("created_at", thirtyDaysAgo.toISOString())
21
+ .order("created_at", { ascending: false });
22
+ if (dateError) {
23
+ return NextResponse.json({ error: dateError.message }, { status: 400 });
24
+ }
25
+ // Process stats
26
+ const stats = processSignupStats(signupData, dateData);
27
+ return NextResponse.json({ data: stats }, { status: 200 });
28
+ }
29
+ catch (error) {
30
+ console.error("Error fetching signup stats:", error);
31
+ return NextResponse.json({ error: "Erreur interne du serveur" }, { status: 500 });
32
+ }
33
+ }
34
+ function processSignupStats(allData, dateData) {
35
+ // Count by source
36
+ const bySource = {
37
+ lastbrain: 0,
38
+ recipe: 0,
39
+ };
40
+ for (const record of allData) {
41
+ const source = (record.signup_source || "lastbrain").toLowerCase();
42
+ if (source === "lastbrain")
43
+ bySource.lastbrain++;
44
+ else if (source === "recipe")
45
+ bySource.recipe++;
46
+ }
47
+ // Count by date
48
+ const byDate = {};
49
+ for (const record of dateData) {
50
+ const date = new Date(record.created_at).toISOString().split("T")[0];
51
+ if (!byDate[date]) {
52
+ byDate[date] = { lastbrain: 0, recipe: 0, total: 0 };
53
+ }
54
+ const source = (record.signup_source || "lastbrain").toLowerCase();
55
+ if (source === "lastbrain") {
56
+ byDate[date].lastbrain++;
57
+ }
58
+ else if (source === "recipe") {
59
+ byDate[date].recipe++;
60
+ }
61
+ byDate[date].total++;
62
+ }
63
+ // Sort dates
64
+ const sortedByDate = Object.entries(byDate)
65
+ .sort(([dateA], [dateB]) => dateB.localeCompare(dateA))
66
+ .map(([date, stats]) => ({
67
+ date,
68
+ ...stats,
69
+ }));
70
+ return {
71
+ total: allData.length,
72
+ bySource,
73
+ byDate: sortedByDate,
74
+ };
75
+ }
@@ -0,0 +1,22 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ interface UserSignupData {
3
+ id: string;
4
+ email: string;
5
+ created_at: string;
6
+ signup_source: string | null;
7
+ first_name: string | null;
8
+ last_name: string | null;
9
+ }
10
+ export declare function GET(request: NextRequest): Promise<NextResponse<{
11
+ error: string;
12
+ }> | NextResponse<{
13
+ data: UserSignupData[];
14
+ pagination: {
15
+ page: number;
16
+ limit: number;
17
+ total: number;
18
+ totalPages: number;
19
+ };
20
+ }>>;
21
+ export {};
22
+ //# sourceMappingURL=users-by-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"users-by-source.d.ts","sourceRoot":"","sources":["../../../src/api/admin/users-by-source.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;IA0E7C"}
@@ -0,0 +1,56 @@
1
+ import { getSupabaseServiceClient } from "@lastbrain/core/server";
2
+ import { NextResponse } from "next/server";
3
+ export async function GET(request) {
4
+ try {
5
+ const supabase = await getSupabaseServiceClient();
6
+ // Get query params for filtering
7
+ const url = new URL(request.url);
8
+ const source = url.searchParams.get("source"); // 'lastbrain' or 'recipe'
9
+ const page = parseInt(url.searchParams.get("page") || "1");
10
+ const limit = parseInt(url.searchParams.get("limit") || "50");
11
+ const offset = (page - 1) * limit;
12
+ let query = supabase.from("user_profil").select(`
13
+ id,
14
+ owner_id,
15
+ first_name,
16
+ last_name,
17
+ signup_source,
18
+ created_at
19
+ `, { count: "exact" });
20
+ // Filter by source if specified
21
+ if (source) {
22
+ query = query.eq("signup_source", source);
23
+ }
24
+ const { data, count, error } = await query
25
+ .order("created_at", { ascending: false })
26
+ .range(offset, offset + limit - 1);
27
+ if (error) {
28
+ return NextResponse.json({ error: error.message }, { status: 400 });
29
+ }
30
+ // Fetch email from auth.users for each profile
31
+ const usersWithEmails = await Promise.all((data || []).map(async (profile) => {
32
+ const { data: authUser } = await supabase.auth.admin.getUserById(profile.owner_id);
33
+ return {
34
+ id: profile.id,
35
+ email: authUser?.user?.email || "Unknown",
36
+ created_at: profile.created_at,
37
+ signup_source: profile.signup_source || "lastbrain",
38
+ first_name: profile.first_name,
39
+ last_name: profile.last_name,
40
+ };
41
+ }));
42
+ return NextResponse.json({
43
+ data: usersWithEmails,
44
+ pagination: {
45
+ page,
46
+ limit,
47
+ total: count || 0,
48
+ totalPages: Math.ceil((count || 0) / limit),
49
+ },
50
+ }, { status: 200 });
51
+ }
52
+ catch (error) {
53
+ console.error("Error fetching users by signup source:", error);
54
+ return NextResponse.json({ error: "Erreur interne du serveur" }, { status: 500 });
55
+ }
56
+ }
@@ -0,0 +1,10 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ export declare function POST(request: NextRequest): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ data: {
6
+ user: import("@supabase/supabase-js").AuthUser;
7
+ message: string;
8
+ };
9
+ }>>;
10
+ //# sourceMappingURL=signup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signup.d.ts","sourceRoot":"","sources":["../../../src/api/public/signup.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;;IA4F9C"}
@@ -0,0 +1,71 @@
1
+ import { getSupabaseServerClient, getSupabaseServiceClient, } from "@lastbrain/core/server";
2
+ import { NextResponse } from "next/server";
3
+ export async function POST(request) {
4
+ try {
5
+ const body = await request.json();
6
+ const defaultSource = process.env.APP_NAME || "undefined";
7
+ console.log("🚀 ~ POST ~ defaultSource:", defaultSource);
8
+ const { email, password, fullName, signupSource = defaultSource } = body;
9
+ // Validate required fields
10
+ if (!email || !password) {
11
+ return NextResponse.json({ error: "Email et mot de passe requis." }, { status: 400 });
12
+ }
13
+ // Get Supabase client for authentication
14
+ const supabase = await getSupabaseServerClient();
15
+ // Sign up the user
16
+ const { data: authData, error: signUpError } = await supabase.auth.signUp({
17
+ email,
18
+ password,
19
+ options: {
20
+ emailRedirectTo: `${request.nextUrl.origin}/api/auth/callback`,
21
+ data: {
22
+ full_name: fullName,
23
+ signup_source: signupSource,
24
+ },
25
+ },
26
+ });
27
+ if (signUpError) {
28
+ return NextResponse.json({ error: signUpError.message }, { status: 400 });
29
+ }
30
+ if (!authData.user) {
31
+ return NextResponse.json({ error: "Erreur lors de la création du compte" }, { status: 500 });
32
+ }
33
+ // Create user profile with signup_source
34
+ const serviceClient = await getSupabaseServiceClient();
35
+ // Check if profile already exists
36
+ const { data: existingProfile } = await serviceClient
37
+ .from("user_profil")
38
+ .select("owner_id")
39
+ .eq("owner_id", authData.user.id)
40
+ .single();
41
+ // Only create profile if it doesn't exist
42
+ if (!existingProfile) {
43
+ const { error: profileError } = await serviceClient
44
+ .from("user_profil")
45
+ .insert({
46
+ owner_id: authData.user.id,
47
+ first_name: fullName?.split(" ")[0] || "",
48
+ last_name: fullName?.split(" ").slice(1).join(" ") || "",
49
+ signup_source: signupSource,
50
+ preferences: {},
51
+ });
52
+ if (profileError) {
53
+ console.error("Error creating user profile:", profileError);
54
+ return NextResponse.json({
55
+ error: "Compte créé mais profil non configuré",
56
+ message: profileError.message,
57
+ }, { status: 500 });
58
+ }
59
+ }
60
+ return NextResponse.json({
61
+ data: {
62
+ user: authData.user,
63
+ message: "Compte créé avec succès",
64
+ },
65
+ }, { status: 201 });
66
+ }
67
+ catch (error) {
68
+ console.error("Signup error:", error);
69
+ return NextResponse.json({ error: "Erreur interne du serveur" }, { status: 500 });
70
+ }
71
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.build.config.d.ts","sourceRoot":"","sources":["../src/auth.build.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,QAAA,MAAM,eAAe,EAAE,iBAqUtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"auth.build.config.d.ts","sourceRoot":"","sources":["../src/auth.build.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,QAAA,MAAM,eAAe,EAAE,iBAgWtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -46,6 +46,11 @@ const authBuildConfig = {
46
46
  path: "/users/[id]",
47
47
  componentExport: "UserPage",
48
48
  },
49
+ {
50
+ section: "admin",
51
+ path: "/signup-stats",
52
+ componentExport: "SignupStatsPage",
53
+ },
49
54
  ],
50
55
  apis: [
51
56
  {
@@ -55,6 +60,13 @@ const authBuildConfig = {
55
60
  entryPoint: "api/public/signin",
56
61
  authRequired: false,
57
62
  },
63
+ {
64
+ method: "POST",
65
+ path: "/api/auth/signup",
66
+ handlerExport: "POST",
67
+ entryPoint: "api/public/signup",
68
+ authRequired: false,
69
+ },
58
70
  {
59
71
  method: "GET",
60
72
  path: "/api/auth/profile",
@@ -104,6 +116,13 @@ const authBuildConfig = {
104
116
  entryPoint: "api/admin/users/[id]/notifications",
105
117
  authRequired: true,
106
118
  },
119
+ {
120
+ method: "GET",
121
+ path: "/api/admin/signup-stats",
122
+ handlerExport: "GET",
123
+ entryPoint: "api/admin/signup-stats",
124
+ authRequired: true,
125
+ },
107
126
  ],
108
127
  migrations: {
109
128
  enabled: true,
@@ -160,6 +179,13 @@ const authBuildConfig = {
160
179
  shortcut: "cmd+shift+u",
161
180
  shortcutDisplay: "⌘⇧U",
162
181
  },
182
+ {
183
+ title: "Statistiques d'inscriptions",
184
+ description: "Suivez les inscriptions par source",
185
+ icon: "UserStar",
186
+ path: "/admin/auth/signup-stats",
187
+ order: 2,
188
+ },
163
189
  {
164
190
  title: "Notifications",
165
191
  description: "Vos notifications",
@@ -1 +1 @@
1
- {"version":3,"file":"AccountButton.d.ts","sourceRoot":"","sources":["../../src/components/AccountButton.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAGlD,UAAU,kBAAkB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AASD,eAAO,MAAM,aAAa,GAAI,kCAI3B,kBAAkB,4CA8HpB,CAAC"}
1
+ {"version":3,"file":"AccountButton.d.ts","sourceRoot":"","sources":["../../src/components/AccountButton.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,UAAU,kBAAkB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AASD,eAAO,MAAM,aAAa,GAAI,kCAI3B,kBAAkB,4CA8HpB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,17 +1,18 @@
1
- export { SignInPage } from "./web/public/SignInPage.js";
2
- export { SignUpPage } from "./web/public/SignUpPage.js";
3
- export { ResetPassword } from "./web/public/ResetPassword.js";
4
- export { DashboardPage } from "./web/auth/dashboard.js";
5
- export { FolderPage } from "./web/auth/folder.js";
6
- export { ProfilePage } from "./web/auth/profile.js";
7
- export { ReglagePage } from "./web/auth/reglage.js";
8
- export { AdminUsersPage } from "./web/admin/users.js";
9
- export { default as UserPage } from "./web/admin/users/[id].js";
10
- export { UserDetailPage } from "./web/admin/user-detail.js";
11
- export { AccountButton } from "./components/AccountButton.js";
12
- export { NotificationButton } from "./components/NotificationButton.js";
13
- export { ThemeSwitcherButton } from "./components/ThemeSwitcherButton.js";
14
- export { Doc } from "./components/Doc.js";
15
- export { Doc as AuthModuleDoc } from "./components/Doc.js";
16
- export { default as authBuildConfig } from "./auth.build.config.js";
1
+ export { SignInPage } from "./web/public/SignInPage";
2
+ export { SignUpPage } from "./web/public/SignUpPage";
3
+ export { ResetPassword } from "./web/public/ResetPassword";
4
+ export { DashboardPage } from "./web/auth/dashboard";
5
+ export { FolderPage } from "./web/auth/folder";
6
+ export { ProfilePage } from "./web/auth/profile";
7
+ export { ReglagePage } from "./web/auth/reglage";
8
+ export { AdminUsersPage } from "./web/admin/users";
9
+ export { default as UserPage } from "./web/admin/users/[id]";
10
+ export { UserDetailPage } from "./web/admin/user-detail";
11
+ export { SignupStatsPage } from "./web/admin/signup-stats";
12
+ export { AccountButton } from "./components/AccountButton";
13
+ export { NotificationButton } from "./components/NotificationButton";
14
+ export { ThemeSwitcherButton } from "./components/ThemeSwitcherButton";
15
+ export { Doc } from "./components/Doc";
16
+ export { Doc as AuthModuleDoc } from "./components/Doc";
17
+ export { default as authBuildConfig } from "./auth.build.config";
17
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAG1E,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAGvE,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -1,20 +1,21 @@
1
1
  // Client Components uniquement
2
- export { SignInPage } from "./web/public/SignInPage.js";
3
- export { SignUpPage } from "./web/public/SignUpPage.js";
4
- export { ResetPassword } from "./web/public/ResetPassword.js";
5
- export { DashboardPage } from "./web/auth/dashboard.js";
6
- export { FolderPage } from "./web/auth/folder.js";
7
- export { ProfilePage } from "./web/auth/profile.js";
8
- export { ReglagePage } from "./web/auth/reglage.js";
9
- export { AdminUsersPage } from "./web/admin/users.js";
10
- export { default as UserPage } from "./web/admin/users/[id].js";
11
- export { UserDetailPage } from "./web/admin/user-detail.js";
2
+ export { SignInPage } from "./web/public/SignInPage";
3
+ export { SignUpPage } from "./web/public/SignUpPage";
4
+ export { ResetPassword } from "./web/public/ResetPassword";
5
+ export { DashboardPage } from "./web/auth/dashboard";
6
+ export { FolderPage } from "./web/auth/folder";
7
+ export { ProfilePage } from "./web/auth/profile";
8
+ export { ReglagePage } from "./web/auth/reglage";
9
+ export { AdminUsersPage } from "./web/admin/users";
10
+ export { default as UserPage } from "./web/admin/users/[id]";
11
+ export { UserDetailPage } from "./web/admin/user-detail";
12
+ export { SignupStatsPage } from "./web/admin/signup-stats";
12
13
  // Header Components
13
- export { AccountButton } from "./components/AccountButton.js";
14
- export { NotificationButton } from "./components/NotificationButton.js";
15
- export { ThemeSwitcherButton } from "./components/ThemeSwitcherButton.js";
14
+ export { AccountButton } from "./components/AccountButton";
15
+ export { NotificationButton } from "./components/NotificationButton";
16
+ export { ThemeSwitcherButton } from "./components/ThemeSwitcherButton";
16
17
  // Documentation
17
- export { Doc } from "./components/Doc.js";
18
- export { Doc as AuthModuleDoc } from "./components/Doc.js";
18
+ export { Doc } from "./components/Doc";
19
+ export { Doc as AuthModuleDoc } from "./components/Doc";
19
20
  // Configuration de build (utilisée par les scripts)
20
- export { default as authBuildConfig } from "./auth.build.config.js";
21
+ export { default as authBuildConfig } from "./auth.build.config";
package/dist/server.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { POST as signInApi } from "./api/public/signin.js";
2
+ export { POST as signUpApi } from "./api/public/signup.js";
2
3
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/server.js CHANGED
@@ -1,2 +1,3 @@
1
1
  // Server-only exports (Route Handlers, Server Actions, etc.)
2
2
  export { POST as signInApi } from "./api/public/signin.js";
3
+ export { POST as signUpApi } from "./api/public/signup.js";
@@ -0,0 +1,2 @@
1
+ export declare function SignupStatsPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=signup-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signup-stats.d.ts","sourceRoot":"","sources":["../../../src/web/admin/signup-stats.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,eAAe,4CA6Q9B"}
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { Card, CardBody, CardHeader, Chip, Spinner, Tab, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow, Tabs, } from "@lastbrain/ui";
5
+ import { BarChart3, TrendingUp } from "lucide-react";
6
+ export function SignupStatsPage() {
7
+ const [stats, setStats] = useState(null);
8
+ const [loading, setLoading] = useState(true);
9
+ const [error, setError] = useState(null);
10
+ useEffect(() => {
11
+ fetchStats();
12
+ }, []);
13
+ const fetchStats = async () => {
14
+ try {
15
+ setLoading(true);
16
+ const response = await fetch("/api/admin/signup-stats");
17
+ if (!response.ok) {
18
+ throw new Error("Erreur lors du chargement des statistiques");
19
+ }
20
+ const result = await response.json();
21
+ setStats(result.data);
22
+ }
23
+ catch (err) {
24
+ setError(err instanceof Error ? err.message : "Erreur lors du chargement");
25
+ }
26
+ finally {
27
+ setLoading(false);
28
+ }
29
+ };
30
+ if (loading) {
31
+ return (_jsx("div", { className: "flex justify-center items-center min-h-screen", children: _jsx(Spinner, { size: "lg", label: "Chargement des statistiques..." }) }));
32
+ }
33
+ if (error || !stats) {
34
+ return (_jsx("div", { className: "p-6", children: _jsx(Card, { className: "border border-danger-200 bg-danger-50/50", children: _jsx(CardBody, { children: _jsx("p", { className: "text-danger-600", children: error || "Erreur de chargement" }) }) }) }));
35
+ }
36
+ const lastbrainPercentage = ((stats.bySource.lastbrain / stats.total) *
37
+ 100).toFixed(1);
38
+ const recipePercentage = ((stats.bySource.recipe / stats.total) *
39
+ 100).toFixed(1);
40
+ return (_jsxs("div", { className: "space-y-6 px-2 md:p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(BarChart3, { size: 28, className: "text-primary-600" }), _jsx("h1", { className: "text-3xl font-bold", children: "Statistiques d'inscriptions" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-12", children: [_jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium text-primary-600 dark:text-primary-400", children: "Total d'inscriptions" }), _jsx(TrendingUp, { size: 20, className: "text-primary-600" })] }), _jsx("p", { className: "text-4xl font-bold text-primary-700 dark:text-primary-300", children: stats.total })] }) }), _jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: "text-sm font-medium text-secondary-600 dark:text-secondary-400", children: "Inscriptions LastBrain" }) }), _jsxs("div", { className: "flex items-end justify-between gap-2", children: [_jsx("p", { className: "text-4xl font-bold text-secondary-700 dark:text-secondary-300", children: stats.bySource.lastbrain }), _jsxs(Chip, { size: "sm", color: "secondary", variant: "flat", children: [lastbrainPercentage, "%"] })] })] }) }), _jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: "text-sm font-medium text-success-600 dark:text-success-400", children: "Inscriptions Recipe" }) }), _jsxs("div", { className: "flex items-end justify-between gap-2", children: [_jsx("p", { className: "text-4xl font-bold text-success-700 dark:text-success-300", children: stats.bySource.recipe }), _jsxs(Chip, { size: "sm", color: "success", variant: "flat", children: [recipePercentage, "%"] })] })] }) })] }), _jsxs(Tabs, { "aria-label": "Vues des statistiques", color: "primary", variant: "bordered", children: [_jsx(Tab, { title: "Par Source", children: _jsxs(Card, { className: "mt-6", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "R\u00E9sum\u00E9 par source" }) }), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "p-4 rounded-lg border border-secondary-800 dark:border-secondary-800", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "font-medium text-secondary-700 dark:text-secondary-300", children: "LastBrain" }), _jsxs(Chip, { size: "sm", color: "secondary", variant: "flat", children: [stats.bySource.lastbrain, " inscriptions"] })] }), _jsx("div", { className: "w-full bg-default-200 rounded-full h-2 dark:bg-default-700", children: _jsx("div", { className: "bg-secondary-500 h-2 rounded-full", style: {
41
+ width: `${(stats.bySource.lastbrain / stats.total) * 100}%`,
42
+ } }) }), _jsxs("p", { className: "text-xs text-default-500 mt-2", children: [lastbrainPercentage, "% du total"] })] }), _jsxs("div", { className: "p-4 rounded-lg border border-success-200 dark:border-success-800", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "font-medium text-success-700 dark:text-success-300", children: "Recipe" }), _jsxs(Chip, { size: "sm", color: "success", variant: "flat", children: [stats.bySource.recipe, " inscriptions"] })] }), _jsx("div", { className: "w-full bg-default-200 rounded-full h-2 dark:bg-default-700", children: _jsx("div", { className: "bg-success-500 h-2 rounded-full", style: {
43
+ width: `${(stats.bySource.recipe / stats.total) * 100}%`,
44
+ } }) }), _jsxs("p", { className: "text-xs text-default-500 mt-2", children: [recipePercentage, "% du total"] })] })] }) })] }) }, "by-source"), _jsx(Tab, { title: "Par Date (30 derniers jours)", children: _jsxs(Card, { className: "mt-6", children: [_jsxs(CardHeader, { children: [_jsx("h3", { className: "text-lg font-semibold", children: "Inscriptions par date" }), _jsx("p", { className: "text-sm text-default-500", children: "Derniers 30 jours avec r\u00E9partition par source" })] }), _jsxs(CardBody, { children: [_jsxs(Table, { "aria-label": "Tableau des inscriptions par date", className: "rounded-lg", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "Date" }), _jsx(TableColumn, { className: "text-right", children: "LastBrain" }), _jsx(TableColumn, { className: "text-right", children: "Recipe" }), _jsx(TableColumn, { className: "text-right", children: "Total" })] }), _jsx(TableBody, { children: stats.byDate.map((row) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx("span", { className: "font-medium", children: new Date(row.date).toLocaleDateString("fr-FR", {
45
+ weekday: "short",
46
+ year: "2-digit",
47
+ month: "2-digit",
48
+ day: "2-digit",
49
+ }) }) }), _jsx(TableCell, { className: "text-right", children: _jsx(Chip, { size: "sm", color: row.lastbrain > 0 ? "secondary" : "default", variant: "flat", children: row.lastbrain }) }), _jsx(TableCell, { className: "text-right", children: _jsx(Chip, { size: "sm", color: row.recipe > 0 ? "success" : "default", variant: "flat", children: row.recipe }) }), _jsx(TableCell, { className: "text-right", children: _jsx("span", { className: "font-semibold text-primary-600 dark:text-primary-400", children: row.total }) })] }, row.date))) })] }), stats.byDate.length === 0 && (_jsx("div", { className: "text-center py-8 text-default-500", children: _jsx("p", { children: "Aucune donn\u00E9e disponible pour les 30 derniers jours" }) }))] })] }) }, "by-date")] }), _jsx(Card, { className: "border-l-4 border-l-primary-500 bg-primary-50/30 dark:bg-primary-950/20", children: _jsx(CardBody, { className: "py-3", children: _jsxs("p", { className: "text-sm text-primary-700 dark:text-primary-300", children: [_jsx("strong", { children: "\uD83D\uDCA1 Info:" }), " Ces statistiques vous permettent de suivre les inscriptions en fonction de la source (LastBrain ou Recipe) pour mieux comprendre d'o\u00F9 proviennent vos utilisateurs."] }) }) })] }));
50
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"user-detail.d.ts","sourceRoot":"","sources":["../../../src/web/admin/user-detail.tsx"],"names":[],"mappings":"AAyBA,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAiCD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,cAAmB,GACpB,EAAE,mBAAmB,2CA0frB"}
1
+ {"version":3,"file":"user-detail.d.ts","sourceRoot":"","sources":["../../../src/web/admin/user-detail.tsx"],"names":[],"mappings":"AAwBA,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAkCD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,cAAmB,GACpB,EAAE,mBAAmB,2CAygBrB"}
@@ -103,7 +103,11 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
103
103
  ? new Date(userProfile.last_sign_in_at).toLocaleDateString()
104
104
  : "N/A", " ", "\u00E0", " ", userProfile.last_sign_in_at
105
105
  ? new Date(userProfile.last_sign_in_at).toLocaleTimeString()
106
- : "N/A"] })] }), _jsx("p", { className: "text-gray-500", children: userProfile.email }), _jsxs("div", { className: "flex flex-col md:flex-row md:items-center gap-2", children: [_jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "primary", size: "sm", children: isAdmin ? "Administrateur" : "Utilisateur" }), _jsx(Snippet, { color: "default", size: "sm", symbol: "#", children: userId })] })] })] }) }), _jsx(Card, { children: _jsx(CardBody, { children: _jsxs(Tabs, { "aria-label": "Options utilisateur", color: "primary", variant: "underlined", children: [_jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(User, { size: 16 }), _jsx("span", { children: "Profil" })] }), children: _jsxs("div", { className: "space-y-6 mt-4", children: [_jsx(Card, { children: _jsxs(CardBody, { children: [_jsxs("h3", { className: "font-semibold text-lg mb-4 flex items-center gap-2", children: [_jsx(User, { size: 18 }), "Identit\u00E9"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom complet" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.full_name || "Non renseigné" })] }), userProfile.profile?.first_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Pr\u00E9nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.first_name })] })), userProfile.profile?.last_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.last_name })] })), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Email" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.email })] }), userProfile.profile?.phone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "T\u00E9l\u00E9phone" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.phone })] }))] }), userProfile.profile?.bio && (_jsxs("div", { className: "mt-4", children: [_jsx("span", { className: "text-default-500 text-sm", children: "Bio" }), _jsx("p", { className: "font-medium mt-1 text-sm", children: userProfile.profile.bio })] }))] }) }), (userProfile.profile?.company ||
106
+ : "N/A"] })] }), _jsx("p", { className: "text-gray-500", children: userProfile.email }), _jsxs("div", { className: "flex flex-col md:flex-row md:items-center gap-2", children: [_jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "primary", size: "sm", children: isAdmin ? "Administrateur" : "Utilisateur" }), userProfile.profile?.signup_source && (_jsx(Chip, { variant: "flat", color: userProfile.profile.signup_source.toLowerCase() === "recipe"
107
+ ? "success"
108
+ : "secondary", size: "sm", children: userProfile.profile.signup_source.toLowerCase() === "recipe"
109
+ ? "Recipe"
110
+ : "LastBrain" })), _jsx(Snippet, { color: "default", size: "sm", symbol: "#", children: userId })] })] })] }) }), _jsx(Card, { children: _jsx(CardBody, { children: _jsxs(Tabs, { "aria-label": "Options utilisateur", color: "primary", variant: "underlined", children: [_jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(User, { size: 16 }), _jsx("span", { children: "Profil" })] }), children: _jsxs("div", { className: "space-y-6 mt-4", children: [_jsx(Card, { children: _jsxs(CardBody, { children: [_jsxs("h3", { className: "font-semibold text-lg mb-4 flex items-center gap-2", children: [_jsx(User, { size: 18 }), "Identit\u00E9"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom complet" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.full_name || "Non renseigné" })] }), userProfile.profile?.first_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Pr\u00E9nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.first_name })] })), userProfile.profile?.last_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.last_name })] })), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Email" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.email })] }), userProfile.profile?.phone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "T\u00E9l\u00E9phone" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.phone })] }))] }), userProfile.profile?.bio && (_jsxs("div", { className: "mt-4", children: [_jsx("span", { className: "text-default-500 text-sm", children: "Bio" }), _jsx("p", { className: "font-medium mt-1 text-sm", children: userProfile.profile.bio })] }))] }) }), (userProfile.profile?.company ||
107
111
  userProfile.profile?.website ||
108
112
  userProfile.profile?.location) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Informations professionnelles" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.company && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Entreprise" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.company })] })), userProfile.profile?.website && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Site web" }), _jsx("p", { className: "font-medium mt-1", children: _jsx("a", { href: userProfile.profile.website, target: "_blank", rel: "noopener noreferrer", className: "text-primary hover:underline", children: userProfile.profile.website }) })] })), userProfile.profile?.location && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Localisation" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.location })] }))] })] }) })), (userProfile.profile?.language ||
109
113
  userProfile.profile?.timezone) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Pr\u00E9f\u00E9rences" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.language && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Langue" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.language.toUpperCase() })] })), userProfile.profile?.timezone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Fuseau horaire" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.timezone })] }))] })] }) })), _jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Informations du compte" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "R\u00F4le" }), _jsx("div", { className: "mt-2", children: _jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "default", size: "sm", children: isAdmin
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { UserDetailPage } from "../user-detail.js";
2
+ import { UserDetailPage } from "../user-detail";
3
3
  import { moduleUserTabs } from "@lastbrain/core";
4
4
  export default async function UserPage({ params }) {
5
5
  const { id } = await params;
@@ -0,0 +1,2 @@
1
+ export declare function UsersBySignupSourcePage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=users-by-signup-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"users-by-signup-source.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users-by-signup-source.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,uBAAuB,4CA+NtC"}