hazo_auth 0.1.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hazo_auth_config.example.ini +75 -0
- package/instrumentation.ts +1 -1
- package/next.config.mjs +1 -1
- package/package.json +4 -1
- package/src/app/api/{auth → hazo_auth/auth}/upload_profile_picture/route.ts +2 -2
- package/src/app/api/{auth → hazo_auth}/change_password/route.ts +23 -0
- package/src/app/api/hazo_auth/get_auth/route.ts +89 -0
- package/src/app/api/hazo_auth/invalidate_cache/route.ts +139 -0
- package/src/app/api/{auth → hazo_auth}/library_photos/route.ts +3 -0
- package/src/app/api/{auth → hazo_auth}/logout/route.ts +27 -0
- package/src/app/api/hazo_auth/upload_profile_picture/route.ts +268 -0
- package/src/app/api/hazo_auth/user_management/permissions/route.ts +367 -0
- package/src/app/api/hazo_auth/user_management/roles/route.ts +442 -0
- package/src/app/api/hazo_auth/user_management/users/roles/route.ts +367 -0
- package/src/app/api/hazo_auth/user_management/users/route.ts +239 -0
- package/src/app/api/{auth → hazo_auth}/validate_reset_token/route.ts +3 -0
- package/src/app/api/{auth → hazo_auth}/verify_email/route.ts +3 -0
- package/src/app/globals.css +1 -1
- package/src/app/hazo_auth/user_management/page.tsx +14 -0
- package/src/app/hazo_auth/user_management/user_management_page_client.tsx +16 -0
- package/src/app/hazo_connect/api/sqlite/data/route.ts +7 -1
- package/src/app/hazo_connect/api/sqlite/schema/route.ts +14 -4
- package/src/app/hazo_connect/api/sqlite/tables/route.ts +14 -4
- package/src/app/hazo_connect/sqlite_admin/sqlite-admin-client.tsx +40 -3
- package/src/app/layout.tsx +1 -1
- package/src/app/page.tsx +4 -4
- package/src/components/layouts/email_verification/hooks/use_email_verification.ts +4 -4
- package/src/components/layouts/email_verification/index.tsx +1 -1
- package/src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts +1 -1
- package/src/components/layouts/login/hooks/use_login_form.ts +2 -2
- package/src/components/layouts/my_settings/components/profile_picture_dialog.tsx +1 -1
- package/src/components/layouts/my_settings/components/profile_picture_library_tab.tsx +35 -6
- package/src/components/layouts/my_settings/hooks/use_my_settings.ts +5 -5
- package/src/components/layouts/my_settings/index.tsx +1 -1
- package/src/components/layouts/register/hooks/use_register_form.ts +1 -1
- package/src/components/layouts/reset_password/hooks/use_reset_password_form.ts +3 -3
- package/src/components/layouts/reset_password/index.tsx +2 -2
- package/src/components/layouts/shared/components/logout_button.tsx +1 -1
- package/src/components/layouts/shared/components/profile_pic_menu.tsx +321 -0
- package/src/components/layouts/shared/components/profile_pic_menu_wrapper.tsx +40 -0
- package/src/components/layouts/shared/components/sidebar_layout_wrapper.tsx +22 -72
- package/src/components/layouts/shared/components/unauthorized_guard.tsx +1 -1
- package/src/components/layouts/shared/hooks/use_auth_status.ts +1 -1
- package/src/components/layouts/shared/hooks/use_hazo_auth.ts +158 -0
- package/src/components/layouts/user_management/components/roles_matrix.tsx +607 -0
- package/src/components/layouts/user_management/index.tsx +1295 -0
- package/src/components/ui/alert-dialog.tsx +141 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/dropdown-menu.tsx +201 -0
- package/src/components/ui/table.tsx +120 -0
- package/src/lib/auth/auth_cache.ts +220 -0
- package/src/lib/auth/auth_rate_limiter.ts +121 -0
- package/src/lib/auth/auth_types.ts +65 -0
- package/src/lib/auth/hazo_get_auth.server.ts +333 -0
- package/src/lib/auth_utility_config.server.ts +136 -0
- package/src/lib/hazo_connect_setup.server.ts +2 -3
- package/src/lib/my_settings_config.server.ts +1 -1
- package/src/lib/profile_pic_menu_config.server.ts +138 -0
- package/src/lib/reset_password_config.server.ts +5 -5
- package/src/lib/services/email_service.ts +2 -2
- package/src/lib/services/profile_picture_remove_service.ts +1 -1
- package/src/lib/services/token_service.ts +2 -2
- package/src/lib/user_management_config.server.ts +40 -0
- package/src/lib/utils.ts +1 -1
- package/src/middleware.ts +15 -13
- package/src/server/types/express.d.ts +1 -0
- package/src/stories/project_overview.stories.tsx +1 -1
- package/tailwind.config.ts +1 -1
- /package/src/app/api/{auth → hazo_auth}/forgot_password/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/login/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/me/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/profile_picture/[filename]/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/register/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/remove_profile_picture/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/resend_verification/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/reset_password/route.ts +0 -0
- /package/src/app/api/{auth → hazo_auth}/update_user/route.ts +0 -0
- /package/src/app/{forgot_password → hazo_auth/forgot_password}/forgot_password_page_client.tsx +0 -0
- /package/src/app/{forgot_password → hazo_auth/forgot_password}/page.tsx +0 -0
- /package/src/app/{login → hazo_auth/login}/login_page_client.tsx +0 -0
- /package/src/app/{login → hazo_auth/login}/page.tsx +0 -0
- /package/src/app/{my_settings → hazo_auth/my_settings}/my_settings_page_client.tsx +0 -0
- /package/src/app/{my_settings → hazo_auth/my_settings}/page.tsx +0 -0
- /package/src/app/{register → hazo_auth/register}/page.tsx +0 -0
- /package/src/app/{register → hazo_auth/register}/register_page_client.tsx +0 -0
- /package/src/app/{reset_password → hazo_auth/reset_password}/page.tsx +0 -0
- /package/src/app/{reset_password → hazo_auth/reset_password}/reset_password_page_client.tsx +0 -0
- /package/src/app/{verify_email → hazo_auth/verify_email}/page.tsx +0 -0
- /package/src/app/{verify_email → hazo_auth/verify_email}/verify_email_page_client.tsx +0 -0
|
@@ -19,11 +19,21 @@ export async function GET(request: NextRequest) {
|
|
|
19
19
|
// Get singleton hazo_connect instance (initializes admin service if needed)
|
|
20
20
|
get_hazo_connect_instance();
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
let service;
|
|
23
|
+
try {
|
|
24
|
+
service = getSqliteAdminService();
|
|
25
|
+
} catch (serviceError) {
|
|
26
|
+
const errorMessage = serviceError instanceof Error ? serviceError.message : "Unknown error";
|
|
27
|
+
return NextResponse.json(
|
|
28
|
+
{ error: `SQLite Admin Service not available: ${errorMessage}. Make sure enable_admin_ui is set to true in hazo_auth_config.ini.` },
|
|
29
|
+
{ status: 500 }
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const schema = await service.getTableSchema(table);
|
|
34
|
+
return NextResponse.json({ data: schema });
|
|
25
35
|
} catch (error) {
|
|
26
|
-
return toErrorResponse(error, `Failed to fetch schema for table '${table}'`)
|
|
36
|
+
return toErrorResponse(error, `Failed to fetch schema for table '${table}'`);
|
|
27
37
|
}
|
|
28
38
|
}
|
|
29
39
|
|
|
@@ -10,11 +10,21 @@ export async function GET() {
|
|
|
10
10
|
// Get singleton hazo_connect instance (initializes admin service if needed)
|
|
11
11
|
get_hazo_connect_instance();
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
let service;
|
|
14
|
+
try {
|
|
15
|
+
service = getSqliteAdminService();
|
|
16
|
+
} catch (serviceError) {
|
|
17
|
+
const errorMessage = serviceError instanceof Error ? serviceError.message : "Unknown error";
|
|
18
|
+
return NextResponse.json(
|
|
19
|
+
{ error: `SQLite Admin Service not available: ${errorMessage}. Make sure enable_admin_ui is set to true in hazo_auth_config.ini.` },
|
|
20
|
+
{ status: 500 }
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const tables = await service.listTables();
|
|
25
|
+
return NextResponse.json({ data: tables });
|
|
16
26
|
} catch (error) {
|
|
17
|
-
return toErrorResponse(error, "Failed to list SQLite tables")
|
|
27
|
+
return toErrorResponse(error, "Failed to list SQLite tables");
|
|
18
28
|
}
|
|
19
29
|
}
|
|
20
30
|
|
|
@@ -91,7 +91,19 @@ export default function SqliteAdminClient({
|
|
|
91
91
|
try {
|
|
92
92
|
const schemaResponse = await fetch(`/hazo_connect/api/sqlite/schema?table=${encodeURIComponent(tableName)}`)
|
|
93
93
|
if (!schemaResponse.ok) {
|
|
94
|
-
|
|
94
|
+
const contentType = schemaResponse.headers.get("content-type");
|
|
95
|
+
if (contentType && contentType.includes("application/json")) {
|
|
96
|
+
const errorData = await schemaResponse.json();
|
|
97
|
+
throw new Error(errorData.error || `Failed to fetch schema: ${schemaResponse.statusText}`);
|
|
98
|
+
} else {
|
|
99
|
+
const errorText = await schemaResponse.text();
|
|
100
|
+
throw new Error(`Failed to fetch schema: ${errorText.substring(0, 200)}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const contentType = schemaResponse.headers.get("content-type");
|
|
104
|
+
if (!contentType || !contentType.includes("application/json")) {
|
|
105
|
+
const text = await schemaResponse.text();
|
|
106
|
+
throw new Error(`Expected JSON but received ${contentType || "unknown content type"}. Response: ${text.substring(0, 200)}`);
|
|
95
107
|
}
|
|
96
108
|
const schemaJson = await schemaResponse.json()
|
|
97
109
|
setSchema(schemaJson.data as TableSchema)
|
|
@@ -170,7 +182,20 @@ export default function SqliteAdminClient({
|
|
|
170
182
|
|
|
171
183
|
const response = await fetch(`/hazo_connect/api/sqlite/data?${params.toString()}`)
|
|
172
184
|
if (!response.ok) {
|
|
173
|
-
|
|
185
|
+
const contentType = response.headers.get("content-type");
|
|
186
|
+
if (contentType && contentType.includes("application/json")) {
|
|
187
|
+
const errorData = await response.json();
|
|
188
|
+
throw new Error(errorData.error || `Failed to load data: ${response.statusText}`);
|
|
189
|
+
} else {
|
|
190
|
+
const errorText = await response.text();
|
|
191
|
+
throw new Error(`Failed to load data: ${errorText.substring(0, 200)}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const contentType = response.headers.get("content-type");
|
|
196
|
+
if (!contentType || !contentType.includes("application/json")) {
|
|
197
|
+
const text = await response.text();
|
|
198
|
+
throw new Error(`Expected JSON but received ${contentType || "unknown content type"}. Response: ${text.substring(0, 200)}`);
|
|
174
199
|
}
|
|
175
200
|
|
|
176
201
|
const json = (await response.json()) as DataResponse
|
|
@@ -197,7 +222,19 @@ export default function SqliteAdminClient({
|
|
|
197
222
|
try {
|
|
198
223
|
const response = await fetch("/hazo_connect/api/sqlite/tables")
|
|
199
224
|
if (!response.ok) {
|
|
200
|
-
|
|
225
|
+
const contentType = response.headers.get("content-type");
|
|
226
|
+
if (contentType && contentType.includes("application/json")) {
|
|
227
|
+
const errorData = await response.json();
|
|
228
|
+
throw new Error(errorData.error || `Failed to refresh tables: ${response.statusText}`);
|
|
229
|
+
} else {
|
|
230
|
+
const errorText = await response.text();
|
|
231
|
+
throw new Error(`Failed to refresh tables: ${errorText.substring(0, 200)}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const contentType = response.headers.get("content-type");
|
|
235
|
+
if (!contentType || !contentType.includes("application/json")) {
|
|
236
|
+
const text = await response.text();
|
|
237
|
+
throw new Error(`Expected JSON but received ${contentType || "unknown content type"}. Response: ${text.substring(0, 200)}`);
|
|
201
238
|
}
|
|
202
239
|
const json = await response.json()
|
|
203
240
|
setTables(json.data ?? [])
|
package/src/app/layout.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// file_description: define the root layout wrapper for the
|
|
1
|
+
// file_description: define the root layout wrapper for the hazo_auth project
|
|
2
2
|
import type { Metadata } from "next";
|
|
3
3
|
import local_font from "next/font/local";
|
|
4
4
|
import { Toaster } from "@/components/ui/sonner";
|
package/src/app/page.tsx
CHANGED
|
@@ -41,7 +41,7 @@ export default function home_page() {
|
|
|
41
41
|
<SidebarMenuItem className="cls_home_sidebar_test_login_item">
|
|
42
42
|
<SidebarMenuButton asChild>
|
|
43
43
|
<Link
|
|
44
|
-
href="/login"
|
|
44
|
+
href="/hazo_auth/login"
|
|
45
45
|
className="cls_home_sidebar_test_login_link flex items-center gap-2"
|
|
46
46
|
aria-label="Test login layout component"
|
|
47
47
|
>
|
|
@@ -53,7 +53,7 @@ export default function home_page() {
|
|
|
53
53
|
<SidebarMenuItem className="cls_home_sidebar_test_register_item">
|
|
54
54
|
<SidebarMenuButton asChild>
|
|
55
55
|
<Link
|
|
56
|
-
href="/register"
|
|
56
|
+
href="/hazo_auth/register"
|
|
57
57
|
className="cls_home_sidebar_test_register_link flex items-center gap-2"
|
|
58
58
|
aria-label="Test register layout component"
|
|
59
59
|
>
|
|
@@ -65,7 +65,7 @@ export default function home_page() {
|
|
|
65
65
|
<SidebarMenuItem className="cls_home_sidebar_test_forgot_password_item">
|
|
66
66
|
<SidebarMenuButton asChild>
|
|
67
67
|
<Link
|
|
68
|
-
href="/forgot_password"
|
|
68
|
+
href="/hazo_auth/forgot_password"
|
|
69
69
|
className="cls_home_sidebar_test_forgot_password_link flex items-center gap-2"
|
|
70
70
|
aria-label="Test forgot password layout component"
|
|
71
71
|
>
|
|
@@ -77,7 +77,7 @@ export default function home_page() {
|
|
|
77
77
|
<SidebarMenuItem className="cls_home_sidebar_test_email_verification_item">
|
|
78
78
|
<SidebarMenuButton asChild>
|
|
79
79
|
<Link
|
|
80
|
-
href="/verify_email"
|
|
80
|
+
href="/hazo_auth/verify_email"
|
|
81
81
|
className="cls_home_sidebar_test_email_verification_link flex items-center gap-2"
|
|
82
82
|
aria-label="Test email verification layout component"
|
|
83
83
|
>
|
|
@@ -47,7 +47,7 @@ const buildInitialValues = (initialEmail?: string): EmailVerificationFormValues
|
|
|
47
47
|
export const use_email_verification = <TClient,>({
|
|
48
48
|
dataClient,
|
|
49
49
|
redirectDelay = 5,
|
|
50
|
-
loginPath = "/login",
|
|
50
|
+
loginPath = "/hazo_auth/login",
|
|
51
51
|
}: UseEmailVerificationParams<TClient>): UseEmailVerificationResult => {
|
|
52
52
|
const router = useRouter();
|
|
53
53
|
const searchParams = useSearchParams();
|
|
@@ -91,7 +91,7 @@ export const use_email_verification = <TClient,>({
|
|
|
91
91
|
setErrorMessage(undefined);
|
|
92
92
|
|
|
93
93
|
try {
|
|
94
|
-
const response = await fetch(`/api/
|
|
94
|
+
const response = await fetch(`/api/hazo_auth/verify_email?token=${encodeURIComponent(token)}`, {
|
|
95
95
|
method: "GET",
|
|
96
96
|
});
|
|
97
97
|
|
|
@@ -131,7 +131,7 @@ export const use_email_verification = <TClient,>({
|
|
|
131
131
|
|
|
132
132
|
// Try to extract email from error response if available
|
|
133
133
|
try {
|
|
134
|
-
const response = await fetch(`/api/
|
|
134
|
+
const response = await fetch(`/api/hazo_auth/verify_email?token=${encodeURIComponent(token)}`, {
|
|
135
135
|
method: "GET",
|
|
136
136
|
});
|
|
137
137
|
const data = await response.json();
|
|
@@ -221,7 +221,7 @@ export const use_email_verification = <TClient,>({
|
|
|
221
221
|
setErrors({});
|
|
222
222
|
|
|
223
223
|
try {
|
|
224
|
-
const response = await fetch("/api/
|
|
224
|
+
const response = await fetch("/api/hazo_auth/resend_verification", {
|
|
225
225
|
method: "POST",
|
|
226
226
|
headers: {
|
|
227
227
|
"Content-Type": "application/json",
|
|
@@ -113,7 +113,7 @@ export const use_forgot_password_form = <TClient,>({
|
|
|
113
113
|
setErrors({});
|
|
114
114
|
|
|
115
115
|
try {
|
|
116
|
-
const response = await fetch("/api/
|
|
116
|
+
const response = await fetch("/api/hazo_auth/forgot_password", {
|
|
117
117
|
method: "POST",
|
|
118
118
|
headers: {
|
|
119
119
|
"Content-Type": "application/json",
|
|
@@ -181,7 +181,7 @@ export const use_login_form = <TClient,>({
|
|
|
181
181
|
setClientIp(currentIp);
|
|
182
182
|
|
|
183
183
|
// Attempt login via API route
|
|
184
|
-
const response = await fetch("/api/
|
|
184
|
+
const response = await fetch("/api/hazo_auth/login", {
|
|
185
185
|
method: "POST",
|
|
186
186
|
headers: {
|
|
187
187
|
"Content-Type": "application/json",
|
|
@@ -202,7 +202,7 @@ export const use_login_form = <TClient,>({
|
|
|
202
202
|
const messageParam = encodeURIComponent(
|
|
203
203
|
"Your email address has not been verified. Please verify your email to continue."
|
|
204
204
|
);
|
|
205
|
-
router.push(`/verify_email?email=${emailParam}&message=${messageParam}`);
|
|
205
|
+
router.push(`/hazo_auth/verify_email?email=${emailParam}&message=${messageParam}`);
|
|
206
206
|
return;
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -188,7 +188,7 @@ export function ProfilePictureDialog({
|
|
|
188
188
|
const formData = new FormData();
|
|
189
189
|
formData.append("file", file);
|
|
190
190
|
|
|
191
|
-
const response = await fetch("/api/
|
|
191
|
+
const response = await fetch("/api/hazo_auth/upload_profile_picture", {
|
|
192
192
|
method: "POST",
|
|
193
193
|
credentials: "include",
|
|
194
194
|
body: formData,
|
|
@@ -57,7 +57,7 @@ export function ProfilePictureLibraryTab({
|
|
|
57
57
|
const loadCategories = async () => {
|
|
58
58
|
setLoadingCategories(true);
|
|
59
59
|
try {
|
|
60
|
-
const response = await fetch("/api/
|
|
60
|
+
const response = await fetch("/api/hazo_auth/library_photos");
|
|
61
61
|
const data = await response.json();
|
|
62
62
|
if (data.success && data.categories) {
|
|
63
63
|
setCategories(data.categories);
|
|
@@ -99,7 +99,7 @@ export function ProfilePictureLibraryTab({
|
|
|
99
99
|
const loadPhotos = async () => {
|
|
100
100
|
setLoadingPhotos(true);
|
|
101
101
|
try {
|
|
102
|
-
const response = await fetch(`/api/
|
|
102
|
+
const response = await fetch(`/api/hazo_auth/library_photos?category=${encodeURIComponent(selectedCategory)}`);
|
|
103
103
|
const data = await response.json();
|
|
104
104
|
if (data.success && data.photos) {
|
|
105
105
|
setPhotos(data.photos);
|
|
@@ -140,6 +140,21 @@ export function ProfilePictureLibraryTab({
|
|
|
140
140
|
return "L";
|
|
141
141
|
};
|
|
142
142
|
|
|
143
|
+
// Map column count to Tailwind grid class
|
|
144
|
+
const getGridColumnsClass = (columns: number): string => {
|
|
145
|
+
const columnMap: Record<number, string> = {
|
|
146
|
+
1: "grid-cols-1",
|
|
147
|
+
2: "grid-cols-2",
|
|
148
|
+
3: "grid-cols-3",
|
|
149
|
+
4: "grid-cols-4",
|
|
150
|
+
5: "grid-cols-5",
|
|
151
|
+
6: "grid-cols-6",
|
|
152
|
+
7: "grid-cols-7",
|
|
153
|
+
8: "grid-cols-8",
|
|
154
|
+
};
|
|
155
|
+
return columnMap[columns] || "grid-cols-4";
|
|
156
|
+
};
|
|
157
|
+
|
|
143
158
|
return (
|
|
144
159
|
<div className="cls_profile_picture_library_tab flex flex-col gap-4">
|
|
145
160
|
{/* Switch */}
|
|
@@ -213,7 +228,7 @@ export function ProfilePictureLibraryTab({
|
|
|
213
228
|
<Loader2 className="h-6 w-6 text-slate-400 animate-spin" aria-hidden="true" />
|
|
214
229
|
</div>
|
|
215
230
|
) : photos.length > 0 ? (
|
|
216
|
-
<div className={`cls_profile_picture_library_tab_photos_grid grid
|
|
231
|
+
<div className={`cls_profile_picture_library_tab_photos_grid grid ${getGridColumnsClass(libraryPhotoGridColumns)} gap-3 overflow-y-auto p-4 border border-slate-200 rounded-lg bg-slate-50 min-h-[400px] max-h-[400px]`}>
|
|
217
232
|
{photos.map((photoUrl) => (
|
|
218
233
|
<button
|
|
219
234
|
key={photoUrl}
|
|
@@ -221,16 +236,21 @@ export function ProfilePictureLibraryTab({
|
|
|
221
236
|
onClick={() => handlePhotoClick(photoUrl)}
|
|
222
237
|
className={`
|
|
223
238
|
cls_profile_picture_library_tab_photo_thumbnail
|
|
224
|
-
aspect-square rounded-lg overflow-hidden border-2 transition-colors
|
|
239
|
+
aspect-square rounded-lg overflow-hidden border-2 transition-colors cursor-pointer
|
|
225
240
|
${selectedPhoto === photoUrl ? "border-blue-500 ring-2 ring-blue-200" : "border-slate-200 hover:border-slate-300"}
|
|
226
241
|
`}
|
|
227
|
-
aria-label={`Select ${photoUrl}`}
|
|
242
|
+
aria-label={`Select photo ${photoUrl.split('/').pop()}`}
|
|
228
243
|
>
|
|
229
244
|
<img
|
|
230
245
|
src={photoUrl}
|
|
231
|
-
alt=
|
|
246
|
+
alt={`Library photo ${photoUrl.split('/').pop()}`}
|
|
232
247
|
className="cls_profile_picture_library_tab_photo_thumbnail_image w-full h-full object-cover"
|
|
233
248
|
loading="lazy"
|
|
249
|
+
onError={(e) => {
|
|
250
|
+
// Fallback if image fails to load
|
|
251
|
+
const target = e.target as HTMLImageElement;
|
|
252
|
+
target.style.display = 'none';
|
|
253
|
+
}}
|
|
234
254
|
/>
|
|
235
255
|
</button>
|
|
236
256
|
))}
|
|
@@ -256,6 +276,15 @@ export function ProfilePictureLibraryTab({
|
|
|
256
276
|
src={selectedPhoto}
|
|
257
277
|
alt="Selected library photo preview"
|
|
258
278
|
className="cls_profile_picture_library_tab_preview_image max-w-full max-h-[350px] rounded-lg object-contain"
|
|
279
|
+
onError={(e) => {
|
|
280
|
+
// Fallback if preview image fails to load
|
|
281
|
+
const target = e.target as HTMLImageElement;
|
|
282
|
+
target.style.display = 'none';
|
|
283
|
+
const wrapper = target.parentElement;
|
|
284
|
+
if (wrapper) {
|
|
285
|
+
wrapper.innerHTML = '<p class="text-sm text-red-500">Failed to load preview</p>';
|
|
286
|
+
}
|
|
287
|
+
}}
|
|
259
288
|
/>
|
|
260
289
|
</div>
|
|
261
290
|
<p className="cls_profile_picture_library_tab_preview_text text-sm text-slate-600 text-center">
|
|
@@ -134,7 +134,7 @@ export function use_my_settings({
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
try {
|
|
137
|
-
const response = await fetch("/api/
|
|
137
|
+
const response = await fetch("/api/hazo_auth/update_user", {
|
|
138
138
|
method: "PATCH",
|
|
139
139
|
headers: {
|
|
140
140
|
"Content-Type": "application/json",
|
|
@@ -171,7 +171,7 @@ export function use_my_settings({
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
try {
|
|
174
|
-
const response = await fetch("/api/
|
|
174
|
+
const response = await fetch("/api/hazo_auth/update_user", {
|
|
175
175
|
method: "PATCH",
|
|
176
176
|
headers: {
|
|
177
177
|
"Content-Type": "application/json",
|
|
@@ -304,7 +304,7 @@ export function use_my_settings({
|
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
try {
|
|
307
|
-
const response = await fetch("/api/
|
|
307
|
+
const response = await fetch("/api/hazo_auth/change_password", {
|
|
308
308
|
method: "POST",
|
|
309
309
|
headers: {
|
|
310
310
|
"Content-Type": "application/json",
|
|
@@ -371,7 +371,7 @@ export function use_my_settings({
|
|
|
371
371
|
*/
|
|
372
372
|
const handleProfilePictureSave = useCallback(async (profilePictureUrl: string, profileSource: "upload" | "library" | "gravatar") => {
|
|
373
373
|
try {
|
|
374
|
-
const response = await fetch("/api/
|
|
374
|
+
const response = await fetch("/api/hazo_auth/update_user", {
|
|
375
375
|
method: "PATCH",
|
|
376
376
|
headers: {
|
|
377
377
|
"Content-Type": "application/json",
|
|
@@ -408,7 +408,7 @@ export function use_my_settings({
|
|
|
408
408
|
*/
|
|
409
409
|
const handleProfilePictureRemove = useCallback(async () => {
|
|
410
410
|
try {
|
|
411
|
-
const response = await fetch("/api/
|
|
411
|
+
const response = await fetch("/api/hazo_auth/remove_profile_picture", {
|
|
412
412
|
method: "DELETE",
|
|
413
413
|
headers: {
|
|
414
414
|
"Content-Type": "application/json",
|
|
@@ -94,7 +94,7 @@ export default function my_settings_layout({
|
|
|
94
94
|
userFields,
|
|
95
95
|
unauthorizedMessage = "You must be logged in to access this page.",
|
|
96
96
|
loginButtonLabel = "Go to login",
|
|
97
|
-
loginPath = "/login",
|
|
97
|
+
loginPath = "/hazo_auth/login",
|
|
98
98
|
heading = "Account Settings",
|
|
99
99
|
subHeading = "Manage your profile, password, and email preferences.",
|
|
100
100
|
profilePhotoLabel = "Profile Photo",
|
|
@@ -194,7 +194,7 @@ export const use_register_form = <TClient,>({
|
|
|
194
194
|
setErrors({});
|
|
195
195
|
|
|
196
196
|
try {
|
|
197
|
-
const response = await fetch("/api/
|
|
197
|
+
const response = await fetch("/api/hazo_auth/register", {
|
|
198
198
|
method: "POST",
|
|
199
199
|
headers: {
|
|
200
200
|
"Content-Type": "application/json",
|
|
@@ -54,7 +54,7 @@ const buildInitialValues = (): ResetPasswordFormValues => ({
|
|
|
54
54
|
export const use_reset_password_form = <TClient,>({
|
|
55
55
|
passwordRequirements,
|
|
56
56
|
dataClient,
|
|
57
|
-
loginPath = "/login",
|
|
57
|
+
loginPath = "/hazo_auth/login",
|
|
58
58
|
}: UseResetPasswordFormParams<TClient>): UseResetPasswordFormResult => {
|
|
59
59
|
const router = useRouter();
|
|
60
60
|
const searchParams = useSearchParams();
|
|
@@ -85,7 +85,7 @@ export const use_reset_password_form = <TClient,>({
|
|
|
85
85
|
setTokenError(null);
|
|
86
86
|
|
|
87
87
|
try {
|
|
88
|
-
const response = await fetch(`/api/
|
|
88
|
+
const response = await fetch(`/api/hazo_auth/validate_reset_token?token=${encodeURIComponent(tokenParam)}`, {
|
|
89
89
|
method: "GET",
|
|
90
90
|
});
|
|
91
91
|
|
|
@@ -217,7 +217,7 @@ export const use_reset_password_form = <TClient,>({
|
|
|
217
217
|
setIsSubmitting(true);
|
|
218
218
|
|
|
219
219
|
try {
|
|
220
|
-
const response = await fetch("/api/
|
|
220
|
+
const response = await fetch("/api/hazo_auth/reset_password", {
|
|
221
221
|
method: "POST",
|
|
222
222
|
headers: {
|
|
223
223
|
"Content-Type": "application/json",
|
|
@@ -75,8 +75,8 @@ export default function reset_password_layout<TClient>({
|
|
|
75
75
|
returnHomePath = "/",
|
|
76
76
|
errorMessage = "Reset password link invalid or has expired. Please go to Reset Password page to get a new link.",
|
|
77
77
|
successMessage = "Password reset successfully. Redirecting to login...",
|
|
78
|
-
loginPath = "/login",
|
|
79
|
-
forgotPasswordPath = "/forgot_password",
|
|
78
|
+
loginPath = "/hazo_auth/login",
|
|
79
|
+
forgotPasswordPath = "/hazo_auth/forgot_password",
|
|
80
80
|
}: ResetPasswordLayoutProps<TClient>) {
|
|
81
81
|
const fieldDefinitions = createResetPasswordFieldDefinitions(field_overrides);
|
|
82
82
|
const resolvedLabels = resolveResetPasswordLabels(labels);
|