@devvistatech/devvista-kit 0.0.12 → 0.0.13

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 (84) hide show
  1. package/README.md +40 -0
  2. package/app/ClientLayout.tsx +66 -0
  3. package/app/about/page.tsx +11 -248
  4. package/app/adRequest/page.tsx +101 -25
  5. package/app/admin-profile/page.tsx +123 -0
  6. package/app/analytics/page.tsx +41 -5
  7. package/app/api/about/route.ts +2 -18
  8. package/app/api/adRequest/route.ts +7 -27
  9. package/app/api/analytics/[reportType]/route.ts +1 -64
  10. package/app/api/bio/route.ts +1 -17
  11. package/app/api/blog/route.ts +1 -19
  12. package/app/api/contacts/route.ts +1 -46
  13. package/app/api/files/route.ts +1 -15
  14. package/app/api/gallery-data/route.ts +53 -61
  15. package/app/api/schedule/route.ts +5 -21
  16. package/app/api/signup/route.ts +129 -0
  17. package/app/api/sync-user/route.ts +268 -94
  18. package/app/api/verify-admin/route.ts +46 -0
  19. package/app/blog/[id]/page.tsx +71 -52
  20. package/app/blog/page.tsx +43 -10
  21. package/app/favicon.ico +0 -0
  22. package/app/gallery/page.tsx +27 -6
  23. package/app/layout.tsx +31 -82
  24. package/app/page.tsx +20 -311
  25. package/app/products/constants/product.ts +27 -0
  26. package/app/products/page.tsx +296 -0
  27. package/app/products/productOne/page.tsx +266 -0
  28. package/app/products/productTwo/page.tsx +272 -0
  29. package/app/schedule/page.tsx +78 -40
  30. package/bin/init.js +0 -12
  31. package/components/addOns/functional/ClassList.tsx +21 -17
  32. package/components/addOns/functional/ProductList.tsx +1027 -0
  33. package/components/addOns/functional/aboutSections/AboutSection.tsx +107 -70
  34. package/components/addOns/functional/aboutSections/constants/aboutSection.ts +9 -4
  35. package/components/addOns/functional/banner/Banner.tsx +150 -0
  36. package/components/addOns/functional/banner/BannerDashboard.tsx +283 -0
  37. package/components/addOns/functional/bioSections/BioEditor.tsx +471 -0
  38. package/components/addOns/functional/bioSections/constants/bioEditor.ts +36 -0
  39. package/components/addOns/functional/blogSections/BlogDashboard.tsx +1 -1
  40. package/components/addOns/functional/blogSections/BlogFormPopUp.tsx +2 -1
  41. package/components/addOns/functional/{ImageDescCarousel.tsx → carousels/ImageDescCarousel.tsx} +166 -57
  42. package/components/addOns/functional/carousels/ProductDescCarousel.tsx +1129 -0
  43. package/components/addOns/functional/{ScheduleCarousel.tsx → carousels/ScheduleCarousel.tsx} +110 -50
  44. package/components/addOns/functional/carousels/constants.ts/productDescCarousel.ts +197 -0
  45. package/components/addOns/functional/carousels/constants.ts/scheduleCarousel.ts +20 -0
  46. package/components/addOns/functional/contactsDashboard/ContactsDashboard.tsx +1 -1
  47. package/components/addOns/functional/fileUploaders/FileUploader.tsx +437 -0
  48. package/components/addOns/functional/fileUploaders/constants/fileUploader.ts +45 -0
  49. package/components/addOns/functional/galleries/GalleryComplex.tsx +468 -267
  50. package/components/addOns/functional/galleries/GallerySimple.tsx +78 -50
  51. package/components/addOns/functional/galleries/ThreeSetGallery.tsx +260 -0
  52. package/components/addOns/functional/schedules/ScheduleGridOne.tsx +22 -8
  53. package/components/addOns/functional/schedules/ScheduleGridTwo.tsx +12 -7
  54. package/components/addOns/functional/schedules/ScheduleGridTwoBasic.tsx +12 -7
  55. package/components/addOns/non-functional/SampleCarousel.tsx +3 -3
  56. package/components/addOns/non-functional/ThreeSetGallery.tsx +3 -3
  57. package/components/addOns/non-functional/featureSections/FeaturesSection.tsx +74 -0
  58. package/components/addOns/non-functional/featureSections/constants/featuresSection.ts +30 -0
  59. package/components/addOns/non-functional/{Heros/HeroSection.tsx → heros/HomeHero.tsx} +17 -15
  60. package/components/addOns/non-functional/heros/ProductHero.tsx +111 -0
  61. package/components/addOns/non-functional/heros/constants/hero.ts +62 -0
  62. package/components/addOns/non-functional/imageCarousels/ProductSlider.tsx +6 -6
  63. package/components/addOns/non-functional/imageCarousels/ProgramCarousel.tsx +10 -10
  64. package/components/footers/footer.tsx +161 -198
  65. package/components/other/admin-menu.tsx +1 -1
  66. package/lib/auth/auth-context.tsx +225 -0
  67. package/lib/auth/auth-utils.tsx +30 -0
  68. package/lib/constants/adRequest.ts +199 -56
  69. package/lib/constants/admin-profile.ts +12 -0
  70. package/lib/constants/page.ts +15 -15
  71. package/lib/google/google-analytics-tracking.tsx +44 -0
  72. package/lib/types.ts +235 -0
  73. package/lib/utils/compressImage.tsx +32 -0
  74. package/middleware.ts +9 -5
  75. package/next.config.js +1 -1
  76. package/package.json +3 -2
  77. package/public/images/test.png +0 -0
  78. package/components/addOns/functional/BioEditor.tsx +0 -447
  79. package/components/addOns/functional/FileUploader.tsx +0 -295
  80. package/components/addOns/non-functional/FeaturesSection.tsx +0 -63
  81. package/components/types.ts +0 -50
  82. package/lib/auth-context.tsx +0 -131
  83. package/lib/verify-user.ts +0 -118
  84. /package/lib/{google-analytics.tsx → google/google-analytics.tsx} +0 -0
@@ -1,51 +1,9 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
2
  import { getAuth } from "@clerk/nextjs/server";
3
+ import { StrapiUser, UploadedImage } from "@/lib/types";
3
4
 
4
5
  export const revalidate = 0;
5
6
 
6
- interface StrapiUser {
7
- id: number;
8
- username: string;
9
- email: string;
10
- authId: string;
11
- authProvider: string;
12
- businessAdminId?: string;
13
- userRole?: string;
14
- firstName?: string;
15
- lastName?: string;
16
- businessId?: string[] | null;
17
- dateJoined?: string;
18
- businessOwner?: boolean;
19
- userStatus?: string;
20
- timezone?: string | null;
21
- language?: string | null;
22
- isVerified?: boolean;
23
- businessTitle?: string | null;
24
- userTitle?: string | null;
25
- number?: string | null;
26
- address?: {
27
- zip: string;
28
- city: string;
29
- state: string;
30
- street: string;
31
- country: string;
32
- } | null;
33
- websiteUrl?: string | null;
34
- primaryBusinessColor?: string | null;
35
- secondaryBusinessColor?: string | null;
36
- logoImage?: string | null;
37
- }
38
-
39
- interface UploadedImage {
40
- id: number;
41
- documentId: string;
42
- title?: string;
43
- description?: string;
44
- url: string;
45
- createdAt: string;
46
- category?: "none" | "indoor" | "outdoor" | "commercial";
47
- }
48
-
49
7
  const CONTENT_API_URL = process.env.STRAPI_CONTENT_API_URL || "";
50
8
  const BASE_URL = process.env.STRAPI_API_URL || "";
51
9
  const UPLOAD_API_URL = `${BASE_URL}/api/upload`;
@@ -151,7 +109,7 @@ export async function GET(request: NextRequest) {
151
109
  }
152
110
 
153
111
  const response = await fetch(
154
- `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&pagination[pageSize]=100&t=${Date.now()}`,
112
+ `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&fields[4]=subCategory&fields[5]=banner&fields[6]=favorite&fields[7]=startDate&fields[8]=endDate&pagination[pageSize]=100&t=${Date.now()}`,
155
113
  {
156
114
  headers: {
157
115
  "Content-Type": "application/json",
@@ -177,7 +135,7 @@ export async function GET(request: NextRequest) {
177
135
  const totalPages = result.meta.pagination.pageCount;
178
136
  for (let page = 2; page <= totalPages; page++) {
179
137
  const nextPageResponse = await fetch(
180
- `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&pagination[page]=${page}&pagination[pageSize]=100&t=${Date.now()}`,
138
+ `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&fields[4]=subCategory&fields[5]=banner&fields[6]=favorite&fields[7]=startDate&fields[8]=endDate&pagination[page]=${page}&pagination[pageSize]=100&t=${Date.now()}`,
181
139
  {
182
140
  headers: {
183
141
  "Content-Type": "application/json",
@@ -193,23 +151,24 @@ export async function GET(request: NextRequest) {
193
151
  const images: UploadedImage[] = allImages
194
152
  .map((item: any) => {
195
153
  const image = item.image;
196
- if (!image || !image.url) {
197
- console.warn(`Image missing for item ${item.id}:`, JSON.stringify(item, null, 2));
198
- return null;
199
- }
200
- const rawUrl = image.url || "";
154
+ const rawUrl = image?.url || "";
201
155
  const imageUrl = rawUrl.startsWith("http") ? rawUrl : `${BASE_URL}${rawUrl}`;
202
156
  return {
203
157
  id: item.id,
204
- documentId: item.documentId,
158
+ documentId: item.documentId || "",
205
159
  title: item.title || "",
206
160
  description: item.description || "",
207
- url: imageUrl,
208
- createdAt: item.createdAt,
161
+ url: image ? imageUrl : "",
162
+ createdAt: item.createdAt || new Date().toISOString(),
209
163
  category: item.category || "none",
164
+ subCategory: item.subCategory || "",
165
+ banner: item.banner || false,
166
+ favorite: item.favorite ?? false,
167
+ startDate: item.startDate || undefined,
168
+ endDate: item.endDate || undefined,
210
169
  };
211
170
  })
212
- .filter((image: UploadedImage | null): image is UploadedImage => image !== null)
171
+ .filter((image: UploadedImage): image is UploadedImage => image !== null)
213
172
  .sort((a: UploadedImage, b: UploadedImage) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
214
173
 
215
174
  return NextResponse.json({
@@ -262,7 +221,12 @@ export async function POST(request: NextRequest) {
262
221
  const file = formData.get("file") as File | null;
263
222
  const title = formData.get("title") as string | null;
264
223
  const description = formData.get("description") as string | null;
265
- const category = formData.get("category") as UploadedImage["category"] | null;
224
+ const category = formData.get("category") as string | null;
225
+ const subCategory = formData.get("subCategory") as string | null;
226
+ const banner = formData.get("banner") === "true";
227
+ const favorite = formData.get("favorite") === "true";
228
+ const startDate = formData.get("startDate") as string | null;
229
+ const endDate = formData.get("endDate") as string | null;
266
230
 
267
231
  if (!file) {
268
232
  console.error("POST /api/gallery-data: No file provided");
@@ -310,6 +274,11 @@ export async function POST(request: NextRequest) {
310
274
  title: title || `Image ${new Date().toISOString()}`,
311
275
  description: description || "",
312
276
  category: validCategory,
277
+ subCategory: subCategory || "",
278
+ banner: banner,
279
+ favorite: favorite ?? false,
280
+ startDate: startDate || null,
281
+ endDate: endDate || null,
313
282
  publishedAt: new Date().toISOString(),
314
283
  },
315
284
  };
@@ -334,7 +303,7 @@ export async function POST(request: NextRequest) {
334
303
  }
335
304
 
336
305
  const filesResponse = await fetch(
337
- `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&pagination[pageSize]=100&t=${Date.now()}`,
306
+ `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&fields[4]=subCategory&fields[5]=banner&fields[6]=favorite&fields[7]=startDate&fields[8]=endDate&pagination[pageSize]=100&t=${Date.now()}`,
338
307
  {
339
308
  headers: {
340
309
  "Content-Type": "application/json",
@@ -371,6 +340,11 @@ export async function POST(request: NextRequest) {
371
340
  url: imageUrl,
372
341
  createdAt: item.createdAt,
373
342
  category: item.category || "none",
343
+ subCategory: item.subCategory || "",
344
+ banner: item.banner || false,
345
+ favorite: item.favorite ?? false,
346
+ startDate: item.startDate || undefined,
347
+ endDate: item.endDate || undefined,
374
348
  };
375
349
  })
376
350
  .filter((image: UploadedImage | null): image is UploadedImage => image !== null)
@@ -428,6 +402,11 @@ export async function PUT(request: NextRequest) {
428
402
  const title = formData.get("title") as string | null;
429
403
  const description = formData.get("description") as string | null;
430
404
  const category = formData.get("category") as string | null;
405
+ const subCategory = formData.get("subCategory") as string | null;
406
+ const banner = formData.get("banner") === "true";
407
+ const favorite = formData.get("favorite") === "true";
408
+ const startDate = formData.get("startDate") as string | null;
409
+ const endDate = formData.get("endDate") as string | null;
431
410
  const file = formData.get("file") as File | null;
432
411
 
433
412
  if (!documentId) {
@@ -498,6 +477,11 @@ export async function PUT(request: NextRequest) {
498
477
  title: title || `Image ${new Date().toISOString()}`,
499
478
  description: description || "",
500
479
  category: validCategory,
480
+ subCategory: subCategory || "",
481
+ banner: banner,
482
+ favorite: favorite ?? false,
483
+ startDate: startDate || null,
484
+ endDate: endDate || null,
501
485
  ...(imageId && { image: imageId }),
502
486
  },
503
487
  };
@@ -535,7 +519,7 @@ export async function PUT(request: NextRequest) {
535
519
  }
536
520
 
537
521
  const filesResponse = await fetch(
538
- `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&pagination[pageSize]=100&t=${Date.now()}`,
522
+ `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&fields[4]=subCategory&fields[5]=banner&fields[6]=favorite&fields[7]=startDate&fields[8]=endDate&pagination[pageSize]=100&t=${Date.now()}`,
539
523
  {
540
524
  headers: {
541
525
  "Content-Type": "application/json",
@@ -572,6 +556,11 @@ export async function PUT(request: NextRequest) {
572
556
  url: imageUrl,
573
557
  createdAt: item.createdAt,
574
558
  category: item.category || "none",
559
+ subCategory: item.subCategory || "",
560
+ banner: item.banner || false,
561
+ favorite: item.favorite ?? false,
562
+ startDate: item.startDate || undefined,
563
+ endDate: item.endDate || undefined,
575
564
  };
576
565
  })
577
566
  .filter((image: UploadedImage | null): image is UploadedImage => image !== null)
@@ -668,19 +657,17 @@ export async function DELETE(request: NextRequest) {
668
657
  const deleteFileResponse = await fetch(`${UPLOAD_API_URL}/files/${uploadFileId}`, {
669
658
  method: "DELETE",
670
659
  headers: {
671
- "Content-Type": "application/json",
672
660
  Authorization: `Bearer ${STRAPI_API_TOKEN}`,
673
661
  },
674
662
  });
675
663
 
676
664
  if (!deleteFileResponse.ok) {
677
- const errorText = await deleteFileResponse.text();
678
- console.warn(`DELETE /api/gallery-data: Failed to delete associated file: ${deleteFileResponse.status} - ${errorText}`);
665
+ console.warn(`DELETE /api/gallery-data: Failed to delete associated file: ${deleteFileResponse.status}`);
679
666
  }
680
667
  }
681
668
 
682
669
  const filesResponse = await fetch(
683
- `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&pagination[pageSize]=100&t=${Date.now()}`,
670
+ `${CONTENT_API_URL}?publicationState=live&populate=image&fields[0]=title&fields[1]=description&fields[2]=createdAt&fields[3]=category&fields[4]=subCategory&fields[5]=banner&fields[6]=favorite&fields[7]=startDate&fields[8]=endDate&pagination[pageSize]=100&t=${Date.now()}`,
684
671
  {
685
672
  headers: {
686
673
  "Content-Type": "application/json",
@@ -717,6 +704,11 @@ export async function DELETE(request: NextRequest) {
717
704
  url: imageUrl,
718
705
  createdAt: item.createdAt,
719
706
  category: item.category || "none",
707
+ subCategory: item.subCategory || "",
708
+ banner: item.banner || false,
709
+ favorite: item.favorite ?? false,
710
+ startDate: item.startDate || undefined,
711
+ endDate: item.endDate || undefined,
720
712
  };
721
713
  })
722
714
  .filter((image: UploadedImage | null): image is UploadedImage => image !== null)
@@ -1,22 +1,6 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
2
  import { getAuth } from "@clerk/nextjs/server";
3
-
4
- interface StrapiUser {
5
- id: number;
6
- username: string;
7
- email: string;
8
- businessAdminId?: string;
9
- }
10
-
11
- interface ScheduleClass {
12
- id: number;
13
- documentId: string;
14
- title: string;
15
- startTime: string;
16
- endTime: string;
17
- daysOfWeek: number[];
18
- classDescription?: string;
19
- }
3
+ import { StrapiUser, ScheduleClass } from "@/lib/types";
20
4
 
21
5
  const CALENDAR_API_URL = process.env.STRAPI_CALENDAR_API_URL || "";
22
6
  const BASE_URL = process.env.STRAPI_API_URL || "";
@@ -94,7 +78,7 @@ export async function GET() {
94
78
 
95
79
  const result = await response.json();
96
80
 
97
- const events = (result.data || []).map((event: any) => {
81
+ const events: ScheduleClass[] = (result.data || []).map((event: any) => {
98
82
  const daysOfWeekRaw = event.attributes?.daysOfWeek || event.daysOfWeek || [];
99
83
  const daysOfWeekNumbers = Array.isArray(daysOfWeekRaw)
100
84
  ? daysOfWeekRaw
@@ -231,7 +215,7 @@ export async function POST(request: NextRequest) {
231
215
  }
232
216
 
233
217
  const result = await eventsResponse.json();
234
- const events = (result.data || []).map((event: any) => ({
218
+ const events: ScheduleClass[] = (result.data || []).map((event: any) => ({
235
219
  id: event.id || 0,
236
220
  documentId: event.documentId || "",
237
221
  title: event.attributes?.title || event.title || "Untitled",
@@ -335,7 +319,7 @@ export async function PUT(request: NextRequest) {
335
319
  }
336
320
 
337
321
  const result = await eventsResponse.json();
338
- const events = (result.data || []).map((event: any) => ({
322
+ const events: ScheduleClass[] = (result.data || []).map((event: any) => ({
339
323
  id: event.id || 0,
340
324
  documentId: event.documentId || "",
341
325
  title: event.attributes?.title || event.title || "Untitled",
@@ -433,7 +417,7 @@ export async function DELETE(request: NextRequest) {
433
417
  }
434
418
 
435
419
  const result = await eventsResponse.json();
436
- const events = (result.data || []).map((event: any) => ({
420
+ const events: ScheduleClass[] = (result.data || []).map((event: any) => ({
437
421
  id: event.id || 0,
438
422
  documentId: event.documentId || "",
439
423
  title: event.attributes?.title || event.title || "Untitled",
@@ -0,0 +1,129 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import crypto from "crypto";
3
+
4
+ export async function POST(req: NextRequest) {
5
+ const STRAPI_USER_LIST_API_URL = process.env.STRAPI_USER_LIST_API_URL;
6
+ const STRAPI_API_TOKEN = process.env.STRAPI_API_TOKEN;
7
+ const allowedOrigin = process.env.NEXT_PUBLIC_BASE_URL;
8
+
9
+ if (!STRAPI_USER_LIST_API_URL || !STRAPI_API_TOKEN || !allowedOrigin) {
10
+ console.error("POST /api/signup: Missing environment variables", {
11
+ hasStrapiUrl: !!STRAPI_USER_LIST_API_URL,
12
+ hasStrapiToken: !!STRAPI_API_TOKEN,
13
+ hasBaseUrl: !!allowedOrigin,
14
+ timestamp: new Date().toISOString(),
15
+ });
16
+ return NextResponse.json({ error: "Server configuration error" }, { status: 500 });
17
+ }
18
+
19
+ const headers = new Headers({
20
+ "Access-Control-Allow-Origin": allowedOrigin,
21
+ "Access-Control-Allow-Methods": "POST",
22
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
23
+ });
24
+
25
+ if (req.method === "OPTIONS") {
26
+ return new NextResponse(null, { status: 204, headers });
27
+ }
28
+
29
+ const requestId = crypto.randomUUID();
30
+ let body;
31
+ try {
32
+ body = await req.json();
33
+ } catch (error) {
34
+ console.error("POST /api/signup: Failed to parse request body", { requestId, error, timestamp: new Date().toISOString() });
35
+ return NextResponse.json({ error: "Invalid request body" }, { status: 400, headers });
36
+ }
37
+
38
+ const { authId, email, username } = body;
39
+
40
+ if (!authId || !email || !username) {
41
+ console.error("POST /api/signup: Missing required fields", { requestId, body, timestamp: new Date().toISOString() });
42
+ return NextResponse.json({ error: "Missing required fields: authId, email, or username" }, { status: 400, headers });
43
+ }
44
+
45
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
46
+ if (!emailRegex.test(email)) {
47
+ console.error("POST /api/signup: Invalid email format", { requestId, email, timestamp: new Date().toISOString() });
48
+ return NextResponse.json({ error: "Invalid email format" }, { status: 400, headers });
49
+ }
50
+
51
+ try {
52
+ // Check if user exists by authId or email
53
+ const checkResponse = await fetch(
54
+ `${STRAPI_USER_LIST_API_URL}?filters[$or][0][authId][$eq]=${encodeURIComponent(authId)}&filters[$or][1][email][$eq]=${encodeURIComponent(email)}`,
55
+ {
56
+ headers: {
57
+ Authorization: `Bearer ${STRAPI_API_TOKEN}`,
58
+ "Content-Type": "application/json",
59
+ },
60
+ }
61
+ );
62
+
63
+ if (!checkResponse.ok) {
64
+ console.error("POST /api/signup: Failed to check existing user:", {
65
+ requestId,
66
+ status: checkResponse.status,
67
+ timestamp: new Date().toISOString(),
68
+ });
69
+ return NextResponse.json({ error: "Failed to check existing user" }, { status: checkResponse.status, headers });
70
+ }
71
+
72
+ const checkResult = await checkResponse.json();
73
+ if (checkResult.data && checkResult.data.length > 0) {
74
+ return NextResponse.json(checkResult.data[0], { status: 200, headers });
75
+ }
76
+
77
+ // Create new Strapi user
78
+ const strapiUserData = {
79
+ data: {
80
+ authId,
81
+ email,
82
+ username,
83
+ userRole: "user",
84
+ businessAdminId: null,
85
+ publishedAt: new Date().toISOString(),
86
+ },
87
+ };
88
+
89
+ const createResponse = await fetch(STRAPI_USER_LIST_API_URL, {
90
+ method: "POST",
91
+ headers: {
92
+ Authorization: `Bearer ${STRAPI_API_TOKEN}`,
93
+ "Content-Type": "application/json",
94
+ },
95
+ body: JSON.stringify(strapiUserData),
96
+ });
97
+
98
+ if (!createResponse.ok) {
99
+ const errorData = await createResponse.json();
100
+ console.error("POST /api/signup: Failed to create Strapi user:", {
101
+ requestId,
102
+ status: createResponse.status,
103
+ errorData,
104
+ timestamp: new Date().toISOString(),
105
+ });
106
+ return NextResponse.json({ error: errorData.error?.message || "Failed to create user" }, { status: createResponse.status, headers });
107
+ }
108
+
109
+ const newStrapiUser = await createResponse.json();
110
+
111
+ return NextResponse.json(newStrapiUser.data, { status: 201, headers });
112
+ } catch (error) {
113
+ console.error("POST /api/signup: Error:", {
114
+ requestId,
115
+ error: error instanceof Error ? error.message : "Unknown error",
116
+ timestamp: new Date().toISOString(),
117
+ });
118
+ return NextResponse.json(
119
+ { error: "Internal server error", details: error instanceof Error ? error.message : "Unknown error" },
120
+ { status: 500, headers }
121
+ );
122
+ }
123
+ }
124
+
125
+ export const config = {
126
+ api: {
127
+ bodyParser: true,
128
+ },
129
+ };