@lastbrain/module-auth 2.0.13 → 2.0.19
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/dist/auth.build.config.d.ts.map +1 -1
- package/dist/auth.build.config.js +33 -47
- package/dist/components/AccountButton.d.ts.map +1 -1
- package/dist/components/AccountButton.js +9 -5
- package/dist/web/admin/signup-stats.d.ts.map +1 -1
- package/dist/web/admin/signup-stats.js +4 -2
- package/dist/web/admin/user-detail.d.ts.map +1 -1
- package/dist/web/admin/user-detail.js +42 -17
- package/dist/web/admin/users-by-signup-source.d.ts.map +1 -1
- package/dist/web/admin/users-by-signup-source.js +18 -7
- package/dist/web/admin/users.d.ts.map +1 -1
- package/dist/web/admin/users.js +11 -6
- package/dist/web/auth/dashboard.d.ts.map +1 -1
- package/dist/web/auth/dashboard.js +7 -3
- package/dist/web/auth/folder.d.ts.map +1 -1
- package/dist/web/auth/folder.js +5 -3
- package/dist/web/auth/profile.d.ts.map +1 -1
- package/dist/web/auth/profile.js +13 -6
- package/dist/web/auth/reglage.d.ts.map +1 -1
- package/dist/web/auth/reglage.js +11 -6
- package/dist/web/public/SignInPage.d.ts.map +1 -1
- package/dist/web/public/SignInPage.js +14 -56
- package/dist/web/public/SignUpPage.d.ts.map +1 -1
- package/dist/web/public/SignUpPage.js +18 -11
- package/package.json +4 -3
- package/src/auth.build.config.ts +34 -48
- package/src/components/AccountButton.tsx +17 -10
- package/src/i18n/en.json +263 -0
- package/src/i18n/fr.json +261 -0
- package/src/web/admin/signup-stats.tsx +10 -3
- package/src/web/admin/user-detail.tsx +135 -56
- package/src/web/admin/users-by-signup-source.tsx +60 -21
- package/src/web/admin/users.tsx +41 -18
- package/src/web/auth/dashboard.tsx +25 -9
- package/src/web/auth/folder.tsx +11 -3
- package/src/web/auth/profile.tsx +63 -29
- package/src/web/auth/reglage.tsx +43 -19
- package/src/web/public/SignInPage.tsx +32 -70
- package/src/web/public/SignUpPage.tsx +48 -26
- package/supabase/migrations/20251112000000_user_init.sql +35 -19
- package/supabase/migrations/20251112000001_auto_profile_and_admin_view.sql +8 -3
- package/supabase/migrations/20251112000002_sync_avatars.sql +7 -1
- package/supabase/migrations/20251124000001_add_get_admin_user_details.sql +2 -1
package/dist/web/admin/users.js
CHANGED
|
@@ -3,9 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useCallback, useEffect, useState, useId } from "react";
|
|
4
4
|
import { Card, CardBody, CardHeader, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Spinner, Chip, Input, Button, Pagination, Avatar, } from "@lastbrain/ui";
|
|
5
5
|
import { Search, RefreshCw, Eye, Users2 } from "lucide-react";
|
|
6
|
-
import {
|
|
6
|
+
import { useModuleTranslation } from "@lastbrain/core";
|
|
7
|
+
import { useLocalizedRouter } from "@lastbrain/core";
|
|
7
8
|
export function AdminUsersPage() {
|
|
8
|
-
const router =
|
|
9
|
+
const router = useLocalizedRouter();
|
|
10
|
+
const t = useModuleTranslation("auth");
|
|
9
11
|
const searchInputId = useId();
|
|
10
12
|
const [users, setUsers] = useState([]);
|
|
11
13
|
const [isLoading, setIsLoading] = useState(true);
|
|
@@ -76,16 +78,19 @@ export function AdminUsersPage() {
|
|
|
76
78
|
if (error && users.length === 0) {
|
|
77
79
|
return (_jsx("div", { className: "pt-12 pb-12 max-w-7xl mx-auto px-4", children: _jsx(Card, { children: _jsx(CardBody, { children: _jsx("p", { className: "text-danger", children: error }) }) }) }));
|
|
78
80
|
}
|
|
79
|
-
return (_jsxs("div", { className: "pt-12 pb-12 max-w-7xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Users2, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "User Management" })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex flex-col md:flex-row gap-4 w-full", children: [_jsxs("div", { className: "flex gap-2 flex-1", children: [_jsx(Input, { id: searchInputId, placeholder: "Search by email or name...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyPress: (e) => {
|
|
81
|
+
return (_jsxs("div", { className: "pt-12 pb-12 max-w-7xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Users2, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: t("users.title") || "User Management" })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex flex-col md:flex-row gap-4 w-full", children: [_jsxs("div", { className: "flex gap-2 flex-1", children: [_jsx(Input, { id: searchInputId, placeholder: t("users.search_placeholder") || "Search by email or name...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyPress: (e) => {
|
|
80
82
|
if (e.key === "Enter") {
|
|
81
83
|
handleSearch();
|
|
82
84
|
}
|
|
83
|
-
}, startContent: _jsx(Search, { className: "w-4 h-4 text-default-400" }), className: "flex-1" }), _jsx(Button, { color: "primary", onPress: handleSearch, isDisabled: isLoading, children: "Search" })] }), _jsx(Button, { variant: "flat", onPress: fetchUsers, isDisabled: isLoading, startContent: _jsx(RefreshCw, { className: "w-4 h-4" }), children: "Refresh" })] }) }), _jsx(CardBody, { children: isLoading ? (_jsx("div", { className: "flex justify-center items-center py-12", children: _jsx(Spinner, { size: "lg", label: "Loading users..." }) })) : users.length === 0 ? (_jsx("div", { className: "text-center py-12 text-default-500", children: "No users found" })) : (_jsxs(_Fragment, { children: [_jsxs(Table, { isStriped: true, "aria-label": "Users table", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "USER" }), _jsx(TableColumn, { children: "EMAIL" }), _jsx(TableColumn, { children: "ROLE" }), _jsx(TableColumn, { children: "LAST SIGN IN" }), _jsx(TableColumn, { children: "CREATED" }), _jsx(TableColumn, { children: "ACTIONS" })] }), _jsx(TableBody, { children: users.map((user) => {
|
|
85
|
+
}, startContent: _jsx(Search, { className: "w-4 h-4 text-default-400" }), className: "flex-1" }), _jsx(Button, { color: "primary", onPress: handleSearch, isDisabled: isLoading, children: t("users.search_button") || "Search" })] }), _jsx(Button, { variant: "flat", onPress: fetchUsers, isDisabled: isLoading, startContent: _jsx(RefreshCw, { className: "w-4 h-4" }), children: t("users.refresh_button") || "Refresh" })] }) }), _jsx(CardBody, { children: isLoading ? (_jsx("div", { className: "flex justify-center items-center py-12", children: _jsx(Spinner, { size: "lg", label: t("users.loading_users") || "Loading users..." }) })) : users.length === 0 ? (_jsx("div", { className: "text-center py-12 text-default-500", children: t("users.no_users_found") || "No users found" })) : (_jsxs(_Fragment, { children: [_jsxs(Table, { isStriped: true, "aria-label": t("users.table_aria_label") || "Users table", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: t("users.column_user") || "USER" }), _jsx(TableColumn, { children: t("users.column_email") || "EMAIL" }), _jsx(TableColumn, { children: t("users.column_role") || "ROLE" }), _jsx(TableColumn, { children: t("users.column_last_sign_in") || "LAST SIGN IN" }), _jsx(TableColumn, { children: t("users.column_created") || "CREATED" }), _jsx(TableColumn, { children: t("users.column_actions") || "ACTIONS" })] }), _jsx(TableBody, { children: users.map((user) => {
|
|
84
86
|
const displayName = user.full_name || user.email;
|
|
85
87
|
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Avatar, { isBordered: true, src: user.avatar_url
|
|
86
88
|
? `/api/storage/${user.avatar_url}`
|
|
87
89
|
: undefined, name: displayName, size: "sm" }), _jsx("span", { className: "text-small font-medium", children: displayName })] }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: user.email }) }), _jsx(TableCell, { children: _jsx(Chip, { size: "sm", variant: "flat", color: user.role === "admin" ? "danger" : "default", children: user.role || "user" }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: user.last_sign_in_at
|
|
88
90
|
? formatDate(user.last_sign_in_at)
|
|
89
|
-
: "Jamais" }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: formatDate(user.created_at) }) }), _jsx(TableCell, { children: _jsx(Button, { size: "sm", variant: "flat", color: "primary", onPress: () => handleViewUser(user.id), startContent: _jsx(Eye, { size: 14 }), children: "Voir" }) })] }, user.id));
|
|
90
|
-
}) })] }), pagination.total_pages > 1 && (_jsx("div", { className: "flex justify-center mt-4", children: _jsx(Pagination, { total: pagination.total_pages, page: pagination.page, onChange: handlePageChange, showControls: true }) })),
|
|
91
|
+
: t("users.never") || "Jamais" }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: formatDate(user.created_at) }) }), _jsx(TableCell, { children: _jsx(Button, { size: "sm", variant: "flat", color: "primary", onPress: () => handleViewUser(user.id), startContent: _jsx(Eye, { size: 14 }), children: t("users.view_button") || "Voir" }) })] }, user.id));
|
|
92
|
+
}) })] }), pagination.total_pages > 1 && (_jsx("div", { className: "flex justify-center mt-4", children: _jsx(Pagination, { total: pagination.total_pages, page: pagination.page, onChange: handlePageChange, showControls: true }) })), _jsx("div", { className: "mt-4 text-small text-default-500 text-center", children: t("users.showing_results")
|
|
93
|
+
?.replace("{{count}}", users.length.toString())
|
|
94
|
+
.replace("{{total}}", pagination.total.toString()) ||
|
|
95
|
+
`Showing ${users.length} of ${pagination.total} users` })] })) })] })] }));
|
|
91
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/web/auth/dashboard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/web/auth/dashboard.tsx"],"names":[],"mappings":"AA8BA,wBAAgB,aAAa,mDAmM5B"}
|
|
@@ -3,7 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { Card, CardBody, CardHeader, Spinner, Chip, Divider, Avatar, } from "@lastbrain/ui";
|
|
5
5
|
import { User, Mail, Calendar, Shield } from "lucide-react";
|
|
6
|
+
import { useModuleTranslation } from "@lastbrain/core";
|
|
6
7
|
export function DashboardPage() {
|
|
8
|
+
const t = useModuleTranslation("auth");
|
|
7
9
|
const [userData, setUserData] = useState(null);
|
|
8
10
|
const [isLoading, setIsLoading] = useState(true);
|
|
9
11
|
const [error, setError] = useState(null);
|
|
@@ -28,10 +30,10 @@ export function DashboardPage() {
|
|
|
28
30
|
}
|
|
29
31
|
};
|
|
30
32
|
if (isLoading) {
|
|
31
|
-
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: "Loading dashboard..." })] }) }));
|
|
33
|
+
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: t("dashboard.loading") || "Loading dashboard..." })] }) }));
|
|
32
34
|
}
|
|
33
35
|
if (error) {
|
|
34
|
-
return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: ["Error: ", error] }) }) }) }));
|
|
36
|
+
return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: [t("dashboard.error") || "Error", ": ", error] }) }) }) }));
|
|
35
37
|
}
|
|
36
38
|
if (!userData) {
|
|
37
39
|
return null;
|
|
@@ -39,6 +41,8 @@ export function DashboardPage() {
|
|
|
39
41
|
const fullName = userData.profile?.first_name && userData.profile?.last_name
|
|
40
42
|
? `${userData.profile.first_name} ${userData.profile.last_name}`
|
|
41
43
|
: "User";
|
|
42
|
-
return (_jsxs("div", { className: "pt-12 pb-12 max-w-6xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: "Dashboard" }), _jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [_jsxs(Card, { className: "col-span-full md:col-span-1", children: [_jsxs(CardHeader, { className: "flex gap-3", children: [_jsx(Avatar, { src: userData.profile?.avatar_url, icon: _jsx(User, {}), size: "lg", className: "shrink-0" }), _jsxs("div", { className: "flex flex-col", children: [_jsx("p", { className: "text-xl font-semibold", children: fullName }), _jsx("p", { className: "text-small text-default-500", children: userData.email })] })] }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.email })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "w-4 h-4 text-default-400" }), _jsxs("span", { className: "text-small", children: ["Member since", " ", new Date(userData.created_at).toLocaleDateString()] })] }), userData.profile?.company && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Shield, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.profile.company })] }))] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Account Status" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: "Status" }), _jsx(Chip, { color: "success", size: "sm", variant: "flat", children: "Active" })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: "Profile" }), _jsx(Chip, { color: userData.profile ? "success" : "warning", size: "sm", variant: "flat", children: userData.profile
|
|
44
|
+
return (_jsxs("div", { className: "pt-12 pb-12 max-w-6xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: t("dashboard.title") || "Dashboard" }), _jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [_jsxs(Card, { className: "col-span-full md:col-span-1", children: [_jsxs(CardHeader, { className: "flex gap-3", children: [_jsx(Avatar, { src: userData.profile?.avatar_url, icon: _jsx(User, {}), size: "lg", className: "shrink-0" }), _jsxs("div", { className: "flex flex-col", children: [_jsx("p", { className: "text-xl font-semibold", children: fullName }), _jsx("p", { className: "text-small text-default-500", children: userData.email })] })] }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.email })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "w-4 h-4 text-default-400" }), _jsxs("span", { className: "text-small", children: [t("dashboard.member_since") || "Member since", " ", new Date(userData.created_at).toLocaleDateString()] })] }), userData.profile?.company && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Shield, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.profile.company })] }))] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("dashboard.account_status") || "Account Status" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: t("dashboard.status") || "Status" }), _jsx(Chip, { color: "success", size: "sm", variant: "flat", children: t("dashboard.active") || "Active" })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: t("dashboard.profile") || "Profile" }), _jsx(Chip, { color: userData.profile ? "success" : "warning", size: "sm", variant: "flat", children: userData.profile
|
|
45
|
+
? t("dashboard.complete") || "Complete"
|
|
46
|
+
: t("dashboard.incomplete") || "Incomplete" })] })] }) })] }), userData.profile?.bio && (_jsxs(Card, { className: "col-span-full", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Bio" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsx("p", { className: "text-small text-default-600", children: userData.profile.bio }) })] })), _jsxs(Card, { className: "col-span-full", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Quick Stats" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [_jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-primary", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Projects" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-success", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Tasks" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-warning", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Notifications" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-secondary", children: Math.floor((Date.now() - new Date(userData.created_at).getTime()) /
|
|
43
47
|
(1000 * 60 * 60 * 24)) }), _jsx("p", { className: "text-small text-default-500", children: "Days active" })] })] }) })] })] })] }));
|
|
44
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/web/auth/folder.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/web/auth/folder.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,UAAU,mDA2EzB"}
|
package/dist/web/auth/folder.js
CHANGED
|
@@ -3,7 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { Card, CardBody, Spinner } from "@lastbrain/ui";
|
|
5
5
|
import { FileManager } from "@lastbrain/ui";
|
|
6
|
+
import { useModuleTranslation } from "@lastbrain/core";
|
|
6
7
|
export function FolderPage() {
|
|
8
|
+
const t = useModuleTranslation("auth");
|
|
7
9
|
const [userData, setUserData] = useState(null);
|
|
8
10
|
const [isLoading, setIsLoading] = useState(true);
|
|
9
11
|
const [error, setError] = useState(null);
|
|
@@ -28,13 +30,13 @@ export function FolderPage() {
|
|
|
28
30
|
}
|
|
29
31
|
};
|
|
30
32
|
if (isLoading) {
|
|
31
|
-
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: "Loading folder..." })] }) }));
|
|
33
|
+
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: t("folder.loading") || "Loading folder..." })] }) }));
|
|
32
34
|
}
|
|
33
35
|
if (error) {
|
|
34
|
-
return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: ["Error: ", error] }) }) }) }));
|
|
36
|
+
return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: [t("folder.error") || "Error", ": ", error] }) }) }) }));
|
|
35
37
|
}
|
|
36
38
|
if (!userData) {
|
|
37
39
|
return null;
|
|
38
40
|
}
|
|
39
|
-
return (_jsxs("div", { className: "pt-4 pb-12 max-w-8xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: "Dossier" }), _jsx(FileManager, { bucket: "app", basePath: userData.id, allowUpload: true, allowCreateFolder: true, allowAIImageGeneration: false, className: "min-h-[80vh]" })] }));
|
|
41
|
+
return (_jsxs("div", { className: "pt-4 pb-12 max-w-8xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: t("folder.title") || "Dossier" }), _jsx(FileManager, { bucket: "app", basePath: userData.id, allowUpload: true, allowCreateFolder: true, allowAIImageGeneration: false, className: "min-h-[80vh]" })] }));
|
|
40
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/web/auth/profile.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/web/auth/profile.tsx"],"names":[],"mappings":"AA0CA,wBAAgB,WAAW,4CA8Z1B"}
|
package/dist/web/auth/profile.js
CHANGED
|
@@ -3,9 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { Card, CardBody, CardHeader, Input, Textarea, Button, Spinner, Divider, addToast, AvatarUploader, } from "@lastbrain/ui";
|
|
5
5
|
import { Save, User } from "lucide-react";
|
|
6
|
+
import { useModuleTranslation } from "@lastbrain/core";
|
|
6
7
|
import { uploadFile, deleteFilesWithPrefix } from "../../api/storage";
|
|
7
8
|
import { supabaseBrowserClient } from "@lastbrain/core";
|
|
8
9
|
export function ProfilePage() {
|
|
10
|
+
const t = useModuleTranslation("auth");
|
|
9
11
|
const [profile, setProfile] = useState({});
|
|
10
12
|
const [isLoading, setIsLoading] = useState(true);
|
|
11
13
|
const [isSaving, setIsSaving] = useState(false);
|
|
@@ -64,8 +66,8 @@ export function ProfilePage() {
|
|
|
64
66
|
throw new Error("Failed to update profile");
|
|
65
67
|
}
|
|
66
68
|
addToast({
|
|
67
|
-
title: "Success",
|
|
68
|
-
description: "Profile updated successfully",
|
|
69
|
+
title: t("profile.success") || "Success",
|
|
70
|
+
description: t("profile.updated") || "Profile updated successfully",
|
|
69
71
|
color: "success",
|
|
70
72
|
});
|
|
71
73
|
}
|
|
@@ -73,8 +75,8 @@ export function ProfilePage() {
|
|
|
73
75
|
console.error("Error updating profile:", err);
|
|
74
76
|
setError(err instanceof Error ? err.message : "An error occurred");
|
|
75
77
|
addToast({
|
|
76
|
-
title: "Error",
|
|
77
|
-
description: "Failed to update profile",
|
|
78
|
+
title: t("profile.error") || "Error",
|
|
79
|
+
description: t("profile.update_failed") || "Failed to update profile",
|
|
78
80
|
color: "danger",
|
|
79
81
|
});
|
|
80
82
|
}
|
|
@@ -172,7 +174,7 @@ export function ProfilePage() {
|
|
|
172
174
|
setProfile((prev) => ({ ...prev, avatar_url: "" }));
|
|
173
175
|
};
|
|
174
176
|
if (isLoading) {
|
|
175
|
-
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: "Loading profile..." }) }));
|
|
177
|
+
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: t("profile.loading") || "Loading profile..." }) }));
|
|
176
178
|
}
|
|
177
179
|
return (_jsx("div", { className: "pt-12 pb-12 max-w-4xl mx-auto px-4", children: _jsx("form", { onSubmit: handleSubmit, children: _jsxs("div", { className: "space-y-6", children: [_jsx("div", { className: "flex justify-center", children: _jsx(AvatarUploader, { userId: currentUser?.id, bucket: "avatar", shape: "circle", onUpload: handleAvatarUpload, onDelete: handleAvatarDelete, initialAvatarPath: currentUser?.user_metadata?.avatar ||
|
|
178
180
|
profile.avatar_url ||
|
|
@@ -190,5 +192,10 @@ export function ProfilePage() {
|
|
|
190
192
|
setProfile((prev) => ({ ...prev, avatar_url: urls.large }));
|
|
191
193
|
}, onDeleted: () => {
|
|
192
194
|
setProfile((prev) => ({ ...prev, avatar_url: "" }));
|
|
193
|
-
} }) }), _jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(User, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children:
|
|
195
|
+
} }) }), _jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(User, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: t("profile.edit") || "Edit Profile" })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("profile.personal_info") || "Personal Information" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: t("profile.first_name") || "First Name", placeholder: t("profile.first_name_placeholder") ||
|
|
196
|
+
"Enter your first name", value: profile.first_name || "", onChange: (e) => handleChange("first_name", e.target.value) }), _jsx(Input, { label: t("profile.last_name") || "Last Name", placeholder: t("profile.last_name_placeholder") || "Enter your last name", value: profile.last_name || "", onChange: (e) => handleChange("last_name", e.target.value) }), _jsx(Input, { label: t("profile.phone") || "Phone", placeholder: t("profile.phone_placeholder") || "Enter your phone number", type: "tel", value: profile.phone || "", onChange: (e) => handleChange("phone", e.target.value), className: "md:col-span-2" }), _jsx(Textarea, { label: t("profile.bio") || "Bio", placeholder: t("profile.bio_placeholder") || "Tell us about yourself", value: profile.bio || "", onChange: (e) => handleChange("bio", e.target.value), minRows: 3, className: "md:col-span-2" })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("profile.professional_info") || "Professional Information" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: t("profile.company") || "Company", placeholder: t("profile.company_placeholder") ||
|
|
197
|
+
"Enter your company name", value: profile.company || "", onChange: (e) => handleChange("company", e.target.value) }), _jsx(Input, { label: t("profile.website") || "Website", placeholder: t("profile.website_placeholder") || "https://example.com", type: "url", value: profile.website || "", onChange: (e) => handleChange("website", e.target.value) }), _jsx(Input, { label: t("profile.location") || "Location", placeholder: t("profile.location_placeholder") || "City, Country", value: profile.location || "", onChange: (e) => handleChange("location", e.target.value), className: "md:col-span-2" })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("profile.preferences") || "Preferences" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: t("profile.language") || "Language", placeholder: t("profile.language_placeholder") || "en, fr, es...", value: profile.language || "", onChange: (e) => handleChange("language", e.target.value) }), _jsx(Input, { label: t("profile.timezone") || "Timezone", placeholder: t("profile.timezone_placeholder") ||
|
|
198
|
+
"Europe/Paris, America/New_York...", value: profile.timezone || "", onChange: (e) => handleChange("timezone", e.target.value) })] }) })] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "flat", onPress: () => fetchProfile(), isDisabled: isSaving, children: t("profile.cancel_button") || "Cancel" }), _jsx(Button, { type: "submit", color: "primary", isLoading: isSaving, startContent: !isSaving && _jsx(Save, { className: "w-4 h-4" }), children: isSaving
|
|
199
|
+
? t("profile.saving") || "Saving..."
|
|
200
|
+
: t("profile.save_button") || "Save Changes" })] })] }) }) }));
|
|
194
201
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reglage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/reglage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reglage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/reglage.tsx"],"names":[],"mappings":"AAiCA,wBAAgB,WAAW,4CAoR1B"}
|
package/dist/web/auth/reglage.js
CHANGED
|
@@ -3,7 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { Card, CardBody, CardHeader, Switch, Button, Spinner, Divider, Select, SelectItem, addToast, } from "@lastbrain/ui";
|
|
5
5
|
import { Settings, Save } from "lucide-react";
|
|
6
|
+
import { useModuleTranslation } from "@lastbrain/core";
|
|
6
7
|
export function ReglagePage() {
|
|
8
|
+
const t = useModuleTranslation("auth");
|
|
7
9
|
const [preferences, setPreferences] = useState({
|
|
8
10
|
email_notifications: true,
|
|
9
11
|
push_notifications: false,
|
|
@@ -70,16 +72,16 @@ export function ReglagePage() {
|
|
|
70
72
|
throw new Error("Failed to update settings");
|
|
71
73
|
}
|
|
72
74
|
addToast({
|
|
73
|
-
title: "Success",
|
|
74
|
-
description: "Settings updated successfully",
|
|
75
|
+
title: t("settings.success") || "Success",
|
|
76
|
+
description: t("settings.updated") || "Settings updated successfully",
|
|
75
77
|
color: "success",
|
|
76
78
|
});
|
|
77
79
|
}
|
|
78
80
|
catch (err) {
|
|
79
81
|
console.error("Error updating settings:", err);
|
|
80
82
|
addToast({
|
|
81
|
-
title: "Error",
|
|
82
|
-
description: "Failed to update settings",
|
|
83
|
+
title: t("settings.error") || "Error",
|
|
84
|
+
description: t("settings.update_failed") || "Failed to update settings",
|
|
83
85
|
color: "danger",
|
|
84
86
|
});
|
|
85
87
|
}
|
|
@@ -94,7 +96,10 @@ export function ReglagePage() {
|
|
|
94
96
|
setPreferences((prev) => ({ ...prev, [key]: value }));
|
|
95
97
|
};
|
|
96
98
|
if (isLoading) {
|
|
97
|
-
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: "Loading settings..." }) }));
|
|
99
|
+
return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: t("settings.loading") || "Loading settings..." }) }));
|
|
98
100
|
}
|
|
99
|
-
return (_jsxs("div", { className: "pt-12 pb-12 max-w-4xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Settings, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "Account Settings" })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Notifications" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children:
|
|
101
|
+
return (_jsxs("div", { className: "pt-12 pb-12 max-w-4xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Settings, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: t("settings.account") || "Account Settings" })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("settings.notifications") || "Notifications" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: t("settings.email_notifications") || "Email Notifications" }), _jsx("p", { className: "text-small text-default-500", children: t("settings.email_notifications_desc") ||
|
|
102
|
+
"Receive email notifications for important updates" })] }), _jsx(Switch, { isSelected: preferences.email_notifications, onValueChange: (value) => handleToggle("email_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: t("settings.push_notifications") || "Push Notifications" }), _jsx("p", { className: "text-small text-default-500", children: t("settings.push_notifications_desc") ||
|
|
103
|
+
"Receive push notifications in your browser" })] }), _jsx(Switch, { isSelected: preferences.push_notifications, onValueChange: (value) => handleToggle("push_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: t("settings.marketing_emails") || "Marketing Emails" }), _jsx("p", { className: "text-small text-default-500", children: t("settings.marketing_emails_desc") ||
|
|
104
|
+
"Receive emails about new features and updates" })] }), _jsx(Switch, { isSelected: preferences.marketing_emails, onValueChange: (value) => handleToggle("marketing_emails", value) })] })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("settings.appearance") || "Appearance" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs(Select, { label: t("settings.theme") || "Theme", placeholder: t("settings.select_theme") || "Select a theme", selectedKeys: preferences.theme ? [preferences.theme] : [], onChange: (e) => handleSelect("theme", e.target.value), children: [_jsx(SelectItem, { children: t("settings.light") || "Light" }, "light"), _jsx(SelectItem, { children: t("settings.dark") || "Dark" }, "dark"), _jsx(SelectItem, { children: t("settings.system") || "System" }, "system")] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Language & Region" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs(Select, { label: "Language", placeholder: "Select a language", selectedKeys: preferences.language ? [preferences.language] : [], onChange: (e) => handleSelect("language", e.target.value), children: [_jsx(SelectItem, { children: "English" }, "en"), _jsx(SelectItem, { children: "Fran\u00E7ais" }, "fr"), _jsx(SelectItem, { children: "Espa\u00F1ol" }, "es"), _jsx(SelectItem, { children: "Deutsch" }, "de")] }), _jsxs(Select, { label: "Timezone", placeholder: "Select a timezone", selectedKeys: preferences.timezone ? [preferences.timezone] : [], onChange: (e) => handleSelect("timezone", e.target.value), children: [_jsx(SelectItem, { children: "UTC" }, "UTC"), _jsx(SelectItem, { children: "Europe/Paris" }, "Europe/Paris"), _jsx(SelectItem, { children: "America/New_York" }, "America/New_York"), _jsx(SelectItem, { children: "America/Los_Angeles" }, "America/Los_Angeles"), _jsx(SelectItem, { children: "Asia/Tokyo" }, "Asia/Tokyo")] })] }) })] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "flat", onPress: () => fetchSettings(), isDisabled: isSaving, children: "Reset" }), _jsx(Button, { type: "button", color: "primary", isLoading: isSaving, onPress: handleSave, startContent: !isSaving && _jsx(Save, { className: "w-4 h-4" }), children: isSaving ? "Saving..." : "Save Settings" })] })] })] }));
|
|
100
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SignInPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignInPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SignInPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignInPage.tsx"],"names":[],"mappings":"AAiNA,wBAAgB,UAAU,4CAMzB"}
|
|
@@ -4,15 +4,18 @@ import { Suspense, useState } from "react";
|
|
|
4
4
|
import { supabaseBrowserClient } from "@lastbrain/core";
|
|
5
5
|
import { addToast, Button, Card, CardBody, Chip, Input, Link, } from "@lastbrain/ui";
|
|
6
6
|
import { ArrowRight, Lock, Mail, Sparkles } from "lucide-react";
|
|
7
|
-
import {
|
|
7
|
+
import { useSearchParams } from "next/navigation";
|
|
8
|
+
import { useModuleTranslation } from "@lastbrain/core";
|
|
9
|
+
import { useLocalizedRouter } from "@lastbrain/core";
|
|
8
10
|
function SignInForm() {
|
|
9
11
|
const searchParams = useSearchParams();
|
|
12
|
+
const t = useModuleTranslation("auth");
|
|
13
|
+
const router = useLocalizedRouter();
|
|
10
14
|
const [email, setEmail] = useState("");
|
|
11
15
|
const [password, setPassword] = useState("");
|
|
12
16
|
const [isLoading, setIsLoading] = useState(false);
|
|
13
17
|
const [error, _setError] = useState(null);
|
|
14
18
|
const redirectUrl = searchParams.get("redirect");
|
|
15
|
-
const router = useRouter();
|
|
16
19
|
const handleSubmit = async (event) => {
|
|
17
20
|
event.preventDefault();
|
|
18
21
|
setIsLoading(true);
|
|
@@ -24,18 +27,17 @@ function SignInForm() {
|
|
|
24
27
|
if (error) {
|
|
25
28
|
addToast({
|
|
26
29
|
color: "danger",
|
|
27
|
-
title: "Erreur de connexion",
|
|
30
|
+
title: t("signin.error_title") || "Erreur de connexion",
|
|
28
31
|
description: error.message,
|
|
29
32
|
});
|
|
30
33
|
setIsLoading(false);
|
|
31
34
|
return;
|
|
32
35
|
}
|
|
33
36
|
setIsLoading(false);
|
|
34
|
-
console.log("Signed in user:", data.user);
|
|
35
37
|
addToast({
|
|
36
38
|
color: "success",
|
|
37
|
-
title: "Connecté avec succès !",
|
|
38
|
-
description:
|
|
39
|
+
title: t("signin.success_title") || "Connecté avec succès !",
|
|
40
|
+
description: `${t("signin.success_welcome") || "Bienvenue"} ${data.user?.email}`,
|
|
39
41
|
});
|
|
40
42
|
router.push(redirectUrl || "/auth/dashboard");
|
|
41
43
|
}
|
|
@@ -43,65 +45,21 @@ function SignInForm() {
|
|
|
43
45
|
setIsLoading(false);
|
|
44
46
|
addToast({
|
|
45
47
|
color: "danger",
|
|
46
|
-
title: "Erreur de connexion",
|
|
48
|
+
title: t("signin.error_title") || "Erreur de connexion",
|
|
47
49
|
description: `${err instanceof Error ? err.message : String(err)}`,
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// <Card className="w-full max-w-md">
|
|
54
|
-
// <CardHeader className="flex flex-col">
|
|
55
|
-
// <h1 className="text-2xl font-semibold text-slate-900 dark:text-white">
|
|
56
|
-
// Connexion
|
|
57
|
-
// </h1>
|
|
58
|
-
// <p className="mt-1 text-sm text-slate-500">
|
|
59
|
-
// Utilisez votre adresse email pour vous connecter.
|
|
60
|
-
// </p>
|
|
61
|
-
// </CardHeader>
|
|
62
|
-
// <CardBody>
|
|
63
|
-
// <form onSubmit={handleSubmit}>
|
|
64
|
-
// <div className="space-y-6">
|
|
65
|
-
// <Input
|
|
66
|
-
// label="Email"
|
|
67
|
-
// type="email"
|
|
68
|
-
// className="mb-6"
|
|
69
|
-
// required
|
|
70
|
-
// value={email}
|
|
71
|
-
// onChange={(event) => setEmail(event.target.value)}
|
|
72
|
-
// />
|
|
73
|
-
// <Input
|
|
74
|
-
// label="Mot de passe"
|
|
75
|
-
// type="password"
|
|
76
|
-
// required
|
|
77
|
-
// placeholder="Password"
|
|
78
|
-
// className="mb-6"
|
|
79
|
-
// value={password}
|
|
80
|
-
// onChange={(event) => setPassword(event.target.value)}
|
|
81
|
-
// />
|
|
82
|
-
// <Button
|
|
83
|
-
// size="lg"
|
|
84
|
-
// type="submit"
|
|
85
|
-
// className="w-full"
|
|
86
|
-
// isLoading={isLoading}
|
|
87
|
-
// >
|
|
88
|
-
// Se connecter
|
|
89
|
-
// </Button>
|
|
90
|
-
// </div>
|
|
91
|
-
// </form>
|
|
92
|
-
// </CardBody>
|
|
93
|
-
// </Card>
|
|
94
|
-
// </div>
|
|
95
|
-
// );
|
|
96
|
-
return (_jsxs("div", { className: "relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-primary-50/30 to-secondary-50/30 dark:from-primary-950/50 dark:to-secondary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-[60vh] items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "primary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: "Espace membre" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-primary-600 to-secondary-600 bg-clip-text text-transparent", children: "Bon retour" }) }), _jsx("p", { className: "text-default-600 dark:text-default-400", children: "Connectez-vous pour acc\u00E9der \u00E0 votre espace" })] }), _jsx(Card, { className: "border border-default-200/60 bg-background/60 backdrop-blur-md backdrop-saturate-150 shadow-xl", children: _jsxs(CardBody, { className: "gap-6 p-8", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-6", children: [_jsx(Input, { label: "Email", type: "email", placeholder: "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
53
|
+
return (_jsxs("div", { className: "relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-primary-50/30 to-secondary-50/30 dark:from-primary-950/50 dark:to-secondary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-[60vh] items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "primary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: t("signin.chip_label") || "Espace membre" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-primary-600 to-secondary-600 bg-clip-text text-transparent", children: t("signin.title") || "Bon retour" }) }), _jsx("p", { className: "text-default-600 dark:text-default-700", children: t("signin.subtitle") ||
|
|
54
|
+
"Connectez-vous pour accéder à votre espace" })] }), _jsx(Card, { className: "border border-default-200/60 bg-background/60 backdrop-blur-md backdrop-saturate-150 shadow-xl", children: _jsxs(CardBody, { className: "gap-6 p-8", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-6", children: [_jsx(Input, { label: t("email") || "Email", type: "email", placeholder: t("signin.email_placeholder") || "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
97
55
|
input: "text-base",
|
|
98
56
|
inputWrapper: "border border-default-200/60 hover:border-primary-400 focus-within:border-primary-500",
|
|
99
|
-
} }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input, { label: "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
57
|
+
} }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input, { label: t("password") || "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
100
58
|
input: "text-base",
|
|
101
59
|
inputWrapper: "border border-default-200/60 hover:border-primary-400 focus-within:border-primary-500",
|
|
102
|
-
} }), _jsx(Link, { href: "/forgot-password", className: "text-xs text-default-500 hover:text-primary-500 self-end", children: "Mot de passe
|
|
60
|
+
} }), _jsx(Link, { href: "/forgot-password", className: "text-xs text-default-500 hover:text-primary-500 self-end", children: t("signin.forgot_password") || "Mot de passe oublié ?" })] }), error && (_jsx("div", { className: "rounded-lg border border-danger-200 bg-danger-50/50 px-4 py-3 dark:border-danger-800 dark:bg-danger-950/50", children: _jsx("p", { className: "text-sm text-danger-600 dark:text-danger-400", children: error }) })), _jsx(Button, { type: "submit", color: "primary", size: "lg", className: "w-full font-semibold", endContent: isLoading ? null : _jsx(ArrowRight, { className: "h-5 w-5" }), isLoading: isLoading, children: t("signin.submit") || "Se connecter" })] }), _jsxs("div", { className: "relative flex items-center gap-4 py-2", children: [_jsx("div", { className: "h-px flex-1 bg-default-200" }), _jsx("span", { className: "text-xs text-default-400", children: t("or") || "OU" }), _jsx("div", { className: "h-px flex-1 bg-default-200" })] }), _jsx("div", { className: "text-center", children: _jsxs("p", { className: "text-sm text-default-600", children: [t("signin.no_account") || "Pas encore de compte ?", " ", _jsx(Link, { href: redirectUrl
|
|
103
61
|
? `/signup?redirect=${encodeURIComponent(redirectUrl)}`
|
|
104
|
-
: "/signup", className: "font-semibold text-primary-600 hover:text-primary-700", children: "
|
|
62
|
+
: "/signup", className: "font-semibold text-primary-600 hover:text-primary-700", children: t("signin.sign_up") || "Créer un compte" })] }) })] }) }), _jsxs("p", { className: "mt-8 text-center text-sm text-default-700", children: [t("signin.accept_terms"), " ", _jsx(Link, { href: "/legal/terms", className: "underline hover:text-primary-500", children: t("signin.term") })] })] }) })] }));
|
|
105
63
|
}
|
|
106
64
|
export function SignInPage() {
|
|
107
65
|
return (_jsx(Suspense, { fallback: _jsx("div", { children: "Chargement..." }), children: _jsx(SignInForm, {}) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SignUpPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignUpPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SignUpPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignUpPage.tsx"],"names":[],"mappings":"AA2SA,wBAAgB,UAAU,4CAMzB"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Button, Card, CardBody, Input, Link, Chip, addToast, } from "@lastbrain/ui";
|
|
4
|
-
import {
|
|
4
|
+
import { useSearchParams } from "next/navigation";
|
|
5
5
|
import { Suspense, useState } from "react";
|
|
6
6
|
import { Mail, Lock, User, ArrowRight, Sparkles, CheckCircle2, } from "lucide-react";
|
|
7
|
+
import { useModuleTranslation } from "@lastbrain/core";
|
|
8
|
+
import { useLocalizedRouter } from "@lastbrain/core";
|
|
7
9
|
function SignUpForm() {
|
|
8
|
-
const router =
|
|
10
|
+
const router = useLocalizedRouter();
|
|
9
11
|
const searchParams = useSearchParams();
|
|
12
|
+
const t = useModuleTranslation("auth");
|
|
10
13
|
const [fullName, setFullName] = useState("");
|
|
11
14
|
const [email, setEmail] = useState("");
|
|
12
15
|
const [password, setPassword] = useState("");
|
|
@@ -21,11 +24,13 @@ function SignUpForm() {
|
|
|
21
24
|
setError(null);
|
|
22
25
|
setSuccess(null);
|
|
23
26
|
if (password !== confirmPassword) {
|
|
24
|
-
setError("
|
|
27
|
+
setError(t("signup.password_mismatch") ||
|
|
28
|
+
"Les mots de passe ne correspondent pas.");
|
|
25
29
|
return;
|
|
26
30
|
}
|
|
27
31
|
if (password.length < 6) {
|
|
28
|
-
setError("
|
|
32
|
+
setError(t("signup.password_too_short") ||
|
|
33
|
+
"Le mot de passe doit contenir au moins 6 caractères.");
|
|
29
34
|
return;
|
|
30
35
|
}
|
|
31
36
|
setLoading(true);
|
|
@@ -58,7 +63,7 @@ function SignUpForm() {
|
|
|
58
63
|
router.push(`/signin?redirect=${encodeURIComponent(redirectUrl)}`);
|
|
59
64
|
}
|
|
60
65
|
else {
|
|
61
|
-
router.push(
|
|
66
|
+
router.push(`/signin`);
|
|
62
67
|
}
|
|
63
68
|
}, 2000);
|
|
64
69
|
}
|
|
@@ -73,21 +78,23 @@ function SignUpForm() {
|
|
|
73
78
|
setLoading(false);
|
|
74
79
|
}
|
|
75
80
|
};
|
|
76
|
-
return (_jsxs("div", { className: " relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-secondary-50/30 to-primary-50/30 dark:from-secondary-950/50 dark:to-primary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-screen items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "secondary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: "Rejoignez-nous" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-secondary-600 to-primary-600 bg-clip-text text-transparent", children: "Commencer gratuitement" }) }), _jsx("p", { className: "text-default-600 dark:text-default-
|
|
81
|
+
return (_jsxs("div", { className: " relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-secondary-50/30 to-primary-50/30 dark:from-secondary-950/50 dark:to-primary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-screen items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "secondary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: t("signup.chip_label") || "Rejoignez-nous" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-secondary-600 to-primary-600 bg-clip-text text-transparent", children: t("signup.title") || "Commencer gratuitement" }) }), _jsx("p", { className: "text-default-600 dark:text-default-700", children: t("signup.subtitle") ||
|
|
82
|
+
"Créez votre compte en quelques secondes" })] }), _jsx(Card, { className: "border border-default-200/60 bg-background/60 backdrop-blur-md backdrop-saturate-150 shadow-xl", children: _jsxs(CardBody, { className: "gap-6 p-8", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-6", children: [_jsx(Input, { label: t("signup.full_name") || "Nom complet", type: "text", placeholder: t("signup.full_name_placeholder") || "Jean Dupont", value: fullName, onChange: (e) => setFullName(e.target.value), startContent: _jsx(User, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
77
83
|
input: "text-base",
|
|
78
84
|
inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
|
|
79
|
-
} }), _jsx(Input, { label: "Email", type: "email", placeholder: "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
85
|
+
} }), _jsx(Input, { label: t("email") || "Email", type: "email", placeholder: t("signin.email_placeholder") || "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
80
86
|
input: "text-base",
|
|
81
87
|
inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
|
|
82
|
-
} }), _jsx(Input, { label: "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
88
|
+
} }), _jsx(Input, { label: t("password") || "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
83
89
|
input: "text-base",
|
|
84
90
|
inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
|
|
85
|
-
}, description: "Minimum 6
|
|
91
|
+
}, description: t("signup.password_hint") || "Minimum 6 caractères" }), _jsx(Input, { label: t("signup.confirm_password") || "Confirmer le mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
|
|
86
92
|
input: "text-base",
|
|
87
93
|
inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
|
|
88
|
-
} }), error && (_jsx("div", { className: "rounded-lg border border-danger-200 bg-danger-50/50 px-4 py-3 dark:border-danger-800 dark:bg-danger-950/50", children: _jsx("p", { className: "text-sm text-danger-600 dark:text-danger-400", children: error }) })), success && (_jsx("div", { className: "rounded-lg border border-success-200 bg-success-50/50 px-4 py-3 dark:border-success-800 dark:bg-success-950/50", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-success-600 dark:text-success-400" }), _jsx("p", { className: "text-sm text-success-600 dark:text-success-400", children: success })] }) })), _jsx(Button, { type: "submit", color: "secondary", size: "lg", className: "w-full font-semibold", endContent: loading ? null : _jsx(ArrowRight, { className: "h-5 w-5" }), isLoading: loading, children: "
|
|
94
|
+
} }), error && (_jsx("div", { className: "rounded-lg border border-danger-200 bg-danger-50/50 px-4 py-3 dark:border-danger-800 dark:bg-danger-950/50", children: _jsx("p", { className: "text-sm text-danger-600 dark:text-danger-400", children: error }) })), success && (_jsx("div", { className: "rounded-lg border border-success-200 bg-success-50/50 px-4 py-3 dark:border-success-800 dark:bg-success-950/50", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-success-600 dark:text-success-400" }), _jsx("p", { className: "text-sm text-success-600 dark:text-success-400", children: success })] }) })), _jsx(Button, { type: "submit", color: "secondary", size: "lg", className: "w-full font-semibold", endContent: loading ? null : _jsx(ArrowRight, { className: "h-5 w-5" }), isLoading: loading, children: t("signup.submit") || "Créer mon compte" })] }), _jsxs("div", { className: "relative flex items-center gap-4 py-2", children: [_jsx("div", { className: "h-px flex-1 bg-default-200" }), _jsx("span", { className: "text-xs text-default-400", children: t("signup.or") || "OU" }), _jsx("div", { className: "h-px flex-1 bg-default-200" })] }), _jsx("div", { className: "text-center", children: _jsxs("p", { className: "text-sm text-default-600", children: [t("signup.have_account") || "Déjà inscrit ?", " ", _jsx(Link, { href: redirectUrl
|
|
89
95
|
? `/signin?redirect=${encodeURIComponent(redirectUrl)}`
|
|
90
|
-
: "/signin", className: "font-semibold text-secondary-600 hover:text-secondary-700", children: "Se connecter" })] }) })] }) }), _jsxs("p", { className: "mt-8 text-center text-
|
|
96
|
+
: "/signin", className: "font-semibold text-secondary-600 hover:text-secondary-700", children: t("signin.submit") || "Se connecter" })] }) })] }) }), _jsxs("p", { className: "mt-8 text-center text-sm text-default-700", children: [t("signup.legal_prefix") ||
|
|
97
|
+
"En créant un compte, vous acceptez nos", " ", _jsx(Link, { href: "/legal/terms", className: "underline hover:text-secondary-500", children: t("signup.terms") || "conditions d'utilisation" }), " ", t("signup.legal_and") || "et notre", " ", _jsx(Link, { href: "/legal/privacy", className: "underline hover:text-secondary-500", children: t("signup.privacy") || "politique de confidentialité" })] })] }) })] }));
|
|
91
98
|
}
|
|
92
99
|
export function SignUpPage() {
|
|
93
100
|
return (_jsx(Suspense, { fallback: _jsx("div", { children: "Chargement..." }), children: _jsx(SignUpForm, {}) }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lastbrain/module-auth",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.19",
|
|
4
4
|
"description": "Module d'authentification complet pour LastBrain avec Supabase",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"supabase"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@lastbrain/
|
|
36
|
-
"@lastbrain/
|
|
35
|
+
"@lastbrain/app": "^2.0.21",
|
|
36
|
+
"@lastbrain/core": "^2.0.19",
|
|
37
|
+
"@lastbrain/ui": "^2.0.19",
|
|
37
38
|
"@supabase/supabase-js": "^2.86.0",
|
|
38
39
|
"lucide-react": "^0.554.0",
|
|
39
40
|
"react": "^19.2.1",
|