@carlonicora/nextjs-jsonapi 1.39.2 → 1.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BlockNoteEditor-WQXQPLMX.js → BlockNoteEditor-4G3L3LSF.js} +14 -14
- package/dist/{BlockNoteEditor-WQXQPLMX.js.map → BlockNoteEditor-4G3L3LSF.js.map} +1 -1
- package/dist/{BlockNoteEditor-CITC7I2Z.mjs → BlockNoteEditor-EKY4AHVK.mjs} +4 -4
- package/dist/billing/index.js +346 -346
- package/dist/billing/index.mjs +3 -3
- package/dist/{chunk-LDH2FGJY.mjs → chunk-BAOP6PTD.mjs} +689 -34
- package/dist/chunk-BAOP6PTD.mjs.map +1 -0
- package/dist/{chunk-2RBYXY6T.js → chunk-GKY5DAIH.js} +1228 -573
- package/dist/chunk-GKY5DAIH.js.map +1 -0
- package/dist/{chunk-TQ5GRRTM.mjs → chunk-GVN7XC3U.mjs} +278 -2
- package/dist/chunk-GVN7XC3U.mjs.map +1 -0
- package/dist/{chunk-XLMJPA4N.mjs → chunk-RRIYLEY6.mjs} +22 -2
- package/dist/chunk-RRIYLEY6.mjs.map +1 -0
- package/dist/{chunk-2PHWAL6Q.js → chunk-T5YYOT4Z.js} +22 -2
- package/dist/chunk-T5YYOT4Z.js.map +1 -0
- package/dist/{chunk-3EZX4G2E.js → chunk-ZNGEVB5M.js} +279 -3
- package/dist/chunk-ZNGEVB5M.js.map +1 -0
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/components/index.d.mts +28 -4
- package/dist/components/index.d.ts +28 -4
- package/dist/components/index.js +16 -4
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +15 -3
- package/dist/contexts/index.js +4 -4
- package/dist/contexts/index.mjs +3 -3
- package/dist/core/index.d.mts +127 -3
- package/dist/core/index.d.ts +127 -3
- package/dist/core/index.js +12 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +11 -1
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -2
- package/dist/{s3.service-hnTPVTm2.d.mts → s3.service-BoOF5-ln.d.mts} +1 -0
- package/dist/{s3.service-DXkDoMf1.d.ts → s3.service-Mxo-7wQ6.d.ts} +1 -0
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +1 -1
- package/dist/waitlist.config-kPfjImle.d.mts +26 -0
- package/dist/waitlist.config-kPfjImle.d.ts +26 -0
- package/package.json +1 -1
- package/src/components/forms/FormCheckbox.tsx +1 -1
- package/src/components/forms/FormSelect.tsx +1 -1
- package/src/components/index.ts +1 -0
- package/src/core/index.ts +3 -0
- package/src/core/registry/ModuleRegistry.ts +3 -0
- package/src/features/auth/components/forms/Register.tsx +180 -1
- package/src/features/auth/data/auth.interface.ts +1 -0
- package/src/features/auth/data/auth.ts +1 -0
- package/src/features/index.ts +1 -0
- package/src/features/waitlist/components/forms/WaitlistForm.tsx +186 -0
- package/src/features/waitlist/components/forms/WaitlistQuestionnaireRenderer.tsx +110 -0
- package/src/features/waitlist/components/forms/index.ts +2 -0
- package/src/features/waitlist/components/index.ts +3 -0
- package/src/features/waitlist/components/lists/WaitlistList.tsx +145 -0
- package/src/features/waitlist/components/lists/index.ts +1 -0
- package/src/features/waitlist/components/sections/WaitlistConfirmation.tsx +68 -0
- package/src/features/waitlist/components/sections/WaitlistHeroSection.tsx +49 -0
- package/src/features/waitlist/components/sections/WaitlistSuccessState.tsx +19 -0
- package/src/features/waitlist/components/sections/index.ts +3 -0
- package/src/features/waitlist/config/waitlist.config.ts +35 -0
- package/src/features/waitlist/data/Waitlist.ts +104 -0
- package/src/features/waitlist/data/WaitlistInterface.ts +32 -0
- package/src/features/waitlist/data/WaitlistService.ts +153 -0
- package/src/features/waitlist/data/index.ts +5 -0
- package/src/features/waitlist/data/waitlist-stats.interface.ts +9 -0
- package/src/features/waitlist/data/waitlist-stats.ts +47 -0
- package/src/features/waitlist/hooks/useWaitlistTableStructure.tsx +121 -0
- package/src/features/waitlist/index.ts +28 -0
- package/src/features/waitlist/waitlist-stats.module.ts +8 -0
- package/src/features/waitlist/waitlist.module.ts +9 -0
- package/src/index.ts +9 -0
- package/src/login/config.ts +9 -0
- package/dist/chunk-2PHWAL6Q.js.map +0 -1
- package/dist/chunk-2RBYXY6T.js.map +0 -1
- package/dist/chunk-3EZX4G2E.js.map +0 -1
- package/dist/chunk-LDH2FGJY.mjs.map +0 -1
- package/dist/chunk-TQ5GRRTM.mjs.map +0 -1
- package/dist/chunk-XLMJPA4N.mjs.map +0 -1
- /package/dist/{BlockNoteEditor-CITC7I2Z.mjs.map → BlockNoteEditor-EKY4AHVK.mjs.map} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -3,13 +3,15 @@ import {
|
|
|
3
3
|
configureJsonApi,
|
|
4
4
|
configureLogin,
|
|
5
5
|
configureRoles,
|
|
6
|
+
configureWaitlist,
|
|
6
7
|
getApiUrl,
|
|
7
8
|
getAppUrl,
|
|
8
9
|
getRoleId,
|
|
9
10
|
getStripePublishableKey,
|
|
10
11
|
getTrackablePages,
|
|
12
|
+
getWaitlistConfig,
|
|
11
13
|
isRolesConfigured
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-RRIYLEY6.mjs";
|
|
13
15
|
import {
|
|
14
16
|
AVAILABLE_OAUTH_SCOPES,
|
|
15
17
|
AbstractApiData,
|
|
@@ -95,6 +97,11 @@ import {
|
|
|
95
97
|
UserFields,
|
|
96
98
|
UserModule,
|
|
97
99
|
UserService,
|
|
100
|
+
Waitlist,
|
|
101
|
+
WaitlistModule,
|
|
102
|
+
WaitlistService,
|
|
103
|
+
WaitlistStats,
|
|
104
|
+
WaitlistStatsModule,
|
|
98
105
|
checkPermissions,
|
|
99
106
|
checkPermissionsFromServer,
|
|
100
107
|
clearLastApiTotal,
|
|
@@ -129,7 +136,7 @@ import {
|
|
|
129
136
|
useComposedRefs,
|
|
130
137
|
useIsMobile,
|
|
131
138
|
userObjectSchema
|
|
132
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-GVN7XC3U.mjs";
|
|
133
140
|
import "./chunk-AUXK7QSA.mjs";
|
|
134
141
|
import "./chunk-C7C7VY4F.mjs";
|
|
135
142
|
import {
|
|
@@ -232,6 +239,11 @@ export {
|
|
|
232
239
|
UserFields,
|
|
233
240
|
UserModule,
|
|
234
241
|
UserService,
|
|
242
|
+
Waitlist,
|
|
243
|
+
WaitlistModule,
|
|
244
|
+
WaitlistService,
|
|
245
|
+
WaitlistStats,
|
|
246
|
+
WaitlistStatsModule,
|
|
235
247
|
checkPermissions,
|
|
236
248
|
checkPermissionsFromServer,
|
|
237
249
|
clearLastApiTotal,
|
|
@@ -242,6 +254,7 @@ export {
|
|
|
242
254
|
configureJsonApi,
|
|
243
255
|
configureLogin,
|
|
244
256
|
configureRoles,
|
|
257
|
+
configureWaitlist,
|
|
245
258
|
createJsonApiInclusion,
|
|
246
259
|
dismissToast,
|
|
247
260
|
entityObjectSchema,
|
|
@@ -266,6 +279,7 @@ export {
|
|
|
266
279
|
getTokenHandler,
|
|
267
280
|
getTrackablePages,
|
|
268
281
|
getValueFromPath,
|
|
282
|
+
getWaitlistConfig,
|
|
269
283
|
hasBootstrapper,
|
|
270
284
|
isRolesConfigured,
|
|
271
285
|
rehydrate,
|
package/dist/server/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import { A as ApiData } from '../ApiData-DPKNfY-9.mjs';
|
|
|
2
2
|
import { M as ModuleWithPermissions, A as Action } from '../notification.interface-DIln2r7X.mjs';
|
|
3
3
|
import { A as ApiRequestDataTypeInterface } from '../ApiRequestDataTypeInterface-CUKFDBx2.mjs';
|
|
4
4
|
import { A as ApiResponseInterface } from '../ApiResponseInterface-zeewugD7.mjs';
|
|
5
|
-
export { f as ServerAuthService, C as ServerCompanyService, h as ServerContentService, F as ServerFeatureService, i as ServerNotificationService, j as ServerPushService, R as ServerRoleService, m as ServerS3Service, U as ServerUserService } from '../s3.service-
|
|
5
|
+
export { f as ServerAuthService, C as ServerCompanyService, h as ServerContentService, F as ServerFeatureService, i as ServerNotificationService, j as ServerPushService, R as ServerRoleService, m as ServerS3Service, U as ServerUserService } from '../s3.service-BoOF5-ln.mjs';
|
|
6
6
|
import 'lucide-react';
|
|
7
7
|
import '../ApiDataInterface-DPP8s46n.mjs';
|
|
8
8
|
import '../feature.interface-BxFFOPNq.mjs';
|
package/dist/server/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { A as ApiData } from '../ApiData-DPKNfY-9.js';
|
|
|
2
2
|
import { M as ModuleWithPermissions, A as Action } from '../notification.interface-XARGKJAq.js';
|
|
3
3
|
import { A as ApiRequestDataTypeInterface } from '../ApiRequestDataTypeInterface-CUKFDBx2.js';
|
|
4
4
|
import { A as ApiResponseInterface } from '../ApiResponseInterface-CAIAeP5d.js';
|
|
5
|
-
export { f as ServerAuthService, C as ServerCompanyService, h as ServerContentService, F as ServerFeatureService, i as ServerNotificationService, j as ServerPushService, R as ServerRoleService, m as ServerS3Service, U as ServerUserService } from '../s3.service-
|
|
5
|
+
export { f as ServerAuthService, C as ServerCompanyService, h as ServerContentService, F as ServerFeatureService, i as ServerNotificationService, j as ServerPushService, R as ServerRoleService, m as ServerS3Service, U as ServerUserService } from '../s3.service-Mxo-7wQ6.js';
|
|
6
6
|
import 'lucide-react';
|
|
7
7
|
import '../ApiDataInterface-DPP8s46n.js';
|
|
8
8
|
import '../feature.interface-CIWxo8NP.js';
|
package/dist/server/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var _chunk3ZPK4QOBjs = require('../chunk-3ZPK4QOB.js');
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
var
|
|
18
|
+
var _chunkZNGEVB5Mjs = require('../chunk-ZNGEVB5M.js');
|
|
19
19
|
require('../chunk-LXKSUWAV.js');
|
|
20
20
|
require('../chunk-IBS6NI7D.js');
|
|
21
21
|
|
|
@@ -86,7 +86,7 @@ var ServerSession = class {
|
|
|
86
86
|
if (!rawModules) return false;
|
|
87
87
|
const modules = JSON.parse(_pako2.default.ungzip(Buffer.from(rawModules, "base64"), { to: "string" }));
|
|
88
88
|
const selectedModule = modules.find((module) => module.id === params.module.moduleId);
|
|
89
|
-
return
|
|
89
|
+
return _chunkZNGEVB5Mjs.checkPermissionsFromServer.call(void 0, {
|
|
90
90
|
module: params.module,
|
|
91
91
|
action: params.action,
|
|
92
92
|
data: params.data,
|
|
@@ -296,5 +296,5 @@ _chunk7QVYU63Ejs.__name.call(void 0, ServerJsonApiDelete, "ServerJsonApiDelete")
|
|
|
296
296
|
|
|
297
297
|
|
|
298
298
|
|
|
299
|
-
exports.ServerAuthService =
|
|
299
|
+
exports.ServerAuthService = _chunkZNGEVB5Mjs.AuthService; exports.ServerCompanyService = _chunkZNGEVB5Mjs.CompanyService; exports.ServerContentService = _chunkZNGEVB5Mjs.ContentService; exports.ServerFeatureService = _chunkZNGEVB5Mjs.FeatureService; exports.ServerJsonApiDelete = ServerJsonApiDelete; exports.ServerJsonApiGet = ServerJsonApiGet; exports.ServerJsonApiPatch = ServerJsonApiPatch; exports.ServerJsonApiPost = ServerJsonApiPost; exports.ServerJsonApiPut = ServerJsonApiPut; exports.ServerNotificationService = _chunkZNGEVB5Mjs.NotificationService; exports.ServerPushService = _chunkZNGEVB5Mjs.PushService; exports.ServerRoleService = _chunkZNGEVB5Mjs.RoleService; exports.ServerS3Service = _chunkZNGEVB5Mjs.S3Service; exports.ServerSession = ServerSession; exports.ServerUserService = _chunkZNGEVB5Mjs.UserService; exports.configureServerJsonApi = configureServerJsonApi; exports.getServerApiUrl = getServerApiUrl; exports.getServerAppUrl = getServerAppUrl; exports.getServerToken = _chunkYUO55Q5Ajs.getServerToken; exports.getServerTrackablePages = getServerTrackablePages; exports.invalidateCacheTag = invalidateCacheTag; exports.invalidateCacheTags = invalidateCacheTags; exports.serverRequest = _chunk3ZPK4QOBjs.serverRequest;
|
|
300
300
|
//# sourceMappingURL=index.js.map
|
package/dist/server/index.mjs
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type QuestionnaireFieldType = "text" | "textarea" | "select" | "checkbox";
|
|
2
|
+
interface QuestionnaireOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
interface QuestionnaireField {
|
|
8
|
+
id: string;
|
|
9
|
+
type: QuestionnaireFieldType;
|
|
10
|
+
label: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
options?: QuestionnaireOption[];
|
|
15
|
+
}
|
|
16
|
+
interface WaitlistConfig {
|
|
17
|
+
questionnaire?: QuestionnaireField[];
|
|
18
|
+
heroTitle?: string;
|
|
19
|
+
heroSubtitle?: string;
|
|
20
|
+
heroDescription?: string;
|
|
21
|
+
benefits?: string[];
|
|
22
|
+
}
|
|
23
|
+
declare function configureWaitlist(config: WaitlistConfig): void;
|
|
24
|
+
declare function getWaitlistConfig(): WaitlistConfig;
|
|
25
|
+
|
|
26
|
+
export { type QuestionnaireField as Q, type WaitlistConfig as W, type QuestionnaireFieldType as a, type QuestionnaireOption as b, configureWaitlist as c, getWaitlistConfig as g };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type QuestionnaireFieldType = "text" | "textarea" | "select" | "checkbox";
|
|
2
|
+
interface QuestionnaireOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
interface QuestionnaireField {
|
|
8
|
+
id: string;
|
|
9
|
+
type: QuestionnaireFieldType;
|
|
10
|
+
label: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
options?: QuestionnaireOption[];
|
|
15
|
+
}
|
|
16
|
+
interface WaitlistConfig {
|
|
17
|
+
questionnaire?: QuestionnaireField[];
|
|
18
|
+
heroTitle?: string;
|
|
19
|
+
heroSubtitle?: string;
|
|
20
|
+
heroDescription?: string;
|
|
21
|
+
benefits?: string[];
|
|
22
|
+
}
|
|
23
|
+
declare function configureWaitlist(config: WaitlistConfig): void;
|
|
24
|
+
declare function getWaitlistConfig(): WaitlistConfig;
|
|
25
|
+
|
|
26
|
+
export { type QuestionnaireField as Q, type WaitlistConfig as W, type QuestionnaireFieldType as a, type QuestionnaireOption as b, configureWaitlist as c, getWaitlistConfig as g };
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@ export function FormCheckbox({ form, id, name, labelBefore, description, isRequi
|
|
|
39
39
|
<div className="flex gap-x-4">
|
|
40
40
|
{labelBefore && label()}
|
|
41
41
|
{labelBefore && isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
|
|
42
|
-
<Checkbox id={id}
|
|
42
|
+
<Checkbox id={id} checked={field.value ?? false} onCheckedChange={field.onChange} />
|
|
43
43
|
{!labelBefore && label()}
|
|
44
44
|
{!labelBefore && isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
|
|
45
45
|
</div>
|
|
@@ -44,7 +44,7 @@ export function FormSelect({
|
|
|
44
44
|
data-testid={testId}
|
|
45
45
|
>
|
|
46
46
|
<SelectTrigger className="w-full">
|
|
47
|
-
<SelectValue
|
|
47
|
+
<SelectValue>{values.find((v) => v.id === field.value)?.text}</SelectValue>
|
|
48
48
|
</SelectTrigger>
|
|
49
49
|
<SelectContent>
|
|
50
50
|
{values.map((type: { id: string; text: string }) => (
|
package/src/components/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * from "../features/onboarding/components";
|
|
|
19
19
|
export * from "../features/role/components";
|
|
20
20
|
export * from "../features/user/components";
|
|
21
21
|
export * from "../features/oauth/components";
|
|
22
|
+
export * from "../features/waitlist/components";
|
|
22
23
|
|
|
23
24
|
// shadcn/ui components (merged from /shadcnui entry point)
|
|
24
25
|
export * from "../shadcnui";
|
package/src/core/index.ts
CHANGED
|
@@ -62,3 +62,6 @@ export * from "../features/user/user.module";
|
|
|
62
62
|
export * from "../features/oauth/oauth.module";
|
|
63
63
|
export * from "../features/oauth/data";
|
|
64
64
|
export * from "../features/oauth/interfaces";
|
|
65
|
+
export * from "../features/waitlist/data";
|
|
66
|
+
export * from "../features/waitlist/waitlist.module";
|
|
67
|
+
export * from "../features/waitlist/waitlist-stats.module";
|
|
@@ -29,6 +29,9 @@ export interface FoundationModuleDefinitions {
|
|
|
29
29
|
StripePromotionCode: ModuleWithPermissions;
|
|
30
30
|
// OAuth modules
|
|
31
31
|
OAuth: ModuleWithPermissions;
|
|
32
|
+
// Waitlist modules
|
|
33
|
+
Waitlist: ModuleWithPermissions;
|
|
34
|
+
WaitlistStats: ModuleWithPermissions;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
// App-specific modules - apps will augment this interface ONLY
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
4
|
+
import { Loader2 } from "lucide-react";
|
|
4
5
|
import { useTranslations } from "next-intl";
|
|
5
6
|
import Image from "next/image";
|
|
6
|
-
import {
|
|
7
|
+
import { useSearchParams } from "next/navigation";
|
|
8
|
+
import { useEffect, useState } from "react";
|
|
7
9
|
import { SubmitHandler, useForm } from "react-hook-form";
|
|
8
10
|
import { v4 } from "uuid";
|
|
9
11
|
import { z } from "zod";
|
|
12
|
+
import { getApiUrl } from "../../../../client/config";
|
|
10
13
|
import { errorToast, FormInput, FormPassword } from "../../../../components";
|
|
14
|
+
import { getRegistrationMode, isDiscordAuthEnabled, isGoogleAuthEnabled } from "../../../../login/config";
|
|
11
15
|
import { GdprConsentSection } from "../GdprConsentSection";
|
|
12
16
|
import {
|
|
13
17
|
Button,
|
|
@@ -22,12 +26,22 @@ import {
|
|
|
22
26
|
import { useAuthContext } from "../../contexts";
|
|
23
27
|
import { AuthService } from "../../data/auth.service";
|
|
24
28
|
import { AuthComponent } from "../../enums";
|
|
29
|
+
import { WaitlistService } from "../../../waitlist/data/WaitlistService";
|
|
25
30
|
|
|
26
31
|
export default function Register() {
|
|
27
32
|
const t = useTranslations();
|
|
28
33
|
const { setComponentType } = useAuthContext();
|
|
34
|
+
const searchParams = useSearchParams();
|
|
35
|
+
const inviteCode = searchParams.get("invite");
|
|
36
|
+
const registrationMode = getRegistrationMode();
|
|
29
37
|
|
|
30
38
|
const [showConfirmation, setShowConfirmation] = useState<boolean>(false);
|
|
39
|
+
const [inviteValidated, setInviteValidated] = useState<boolean>(false);
|
|
40
|
+
const [inviteError, setInviteError] = useState<string>("");
|
|
41
|
+
// Initialize loading state to true if we have an invite code in waitlist mode
|
|
42
|
+
const [isValidatingInvite, setIsValidatingInvite] = useState<boolean>(
|
|
43
|
+
registrationMode === "waitlist" && !!inviteCode,
|
|
44
|
+
);
|
|
31
45
|
|
|
32
46
|
const formSchema = z.object({
|
|
33
47
|
company: z.string().min(1, {
|
|
@@ -63,6 +77,41 @@ export default function Register() {
|
|
|
63
77
|
},
|
|
64
78
|
});
|
|
65
79
|
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
async function validateInvite() {
|
|
82
|
+
console.log("[Register] validateInvite called. registrationMode:", registrationMode, "inviteCode:", inviteCode);
|
|
83
|
+
|
|
84
|
+
if (registrationMode !== "waitlist" || !inviteCode) {
|
|
85
|
+
console.log("[Register] Skipping validation - not in waitlist mode or no invite code");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
setIsValidatingInvite(true);
|
|
90
|
+
try {
|
|
91
|
+
console.log("[Register] Calling WaitlistService.validateInvite...");
|
|
92
|
+
const result = await WaitlistService.validateInvite(inviteCode);
|
|
93
|
+
console.log("[Register] Validation result:", JSON.stringify(result));
|
|
94
|
+
|
|
95
|
+
if (result && result.valid) {
|
|
96
|
+
console.log("[Register] Invite valid! Email:", result.email);
|
|
97
|
+
setInviteValidated(true);
|
|
98
|
+
form.setValue("email", result.email);
|
|
99
|
+
} else {
|
|
100
|
+
const errorMsg = result ? t("waitlist.invite.error_expired") : t("waitlist.invite.error_invalid");
|
|
101
|
+
console.log("[Register] Invite invalid. result:", result, "errorMsg:", errorMsg);
|
|
102
|
+
setInviteError(errorMsg);
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error("[Register] Validation exception:", error);
|
|
106
|
+
setInviteError(t("waitlist.invite.error_validation_failed"));
|
|
107
|
+
} finally {
|
|
108
|
+
setIsValidatingInvite(false);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
validateInvite();
|
|
113
|
+
}, [registrationMode, inviteCode, form, t]);
|
|
114
|
+
|
|
66
115
|
const onSubmit: SubmitHandler<z.infer<typeof formSchema>> = async (values: z.infer<typeof formSchema>) => {
|
|
67
116
|
try {
|
|
68
117
|
const payload = {
|
|
@@ -74,6 +123,7 @@ export default function Register() {
|
|
|
74
123
|
termsAcceptedAt: new Date().toISOString(),
|
|
75
124
|
marketingConsent: values.marketingConsent ?? false,
|
|
76
125
|
marketingConsentAt: values.marketingConsent ? new Date().toISOString() : null,
|
|
126
|
+
inviteCode: inviteCode ?? undefined,
|
|
77
127
|
};
|
|
78
128
|
|
|
79
129
|
await AuthService.register(payload);
|
|
@@ -83,6 +133,71 @@ export default function Register() {
|
|
|
83
133
|
}
|
|
84
134
|
};
|
|
85
135
|
|
|
136
|
+
// Show loading state while validating invite
|
|
137
|
+
if (registrationMode === "waitlist" && inviteCode && isValidatingInvite) {
|
|
138
|
+
return (
|
|
139
|
+
<>
|
|
140
|
+
<CardHeader>
|
|
141
|
+
<CardTitle className="text-primary flex flex-col items-center pb-10 text-4xl">
|
|
142
|
+
<Image src="/logo.webp" alt="Logo" width={100} height={100} priority />
|
|
143
|
+
{t("waitlist.invite.validating_title")}
|
|
144
|
+
</CardTitle>
|
|
145
|
+
</CardHeader>
|
|
146
|
+
<CardContent className="flex flex-col items-center justify-center space-y-4 py-8">
|
|
147
|
+
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
148
|
+
<p className="text-muted-foreground">{t("waitlist.invite.validating_description")}</p>
|
|
149
|
+
</CardContent>
|
|
150
|
+
</>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Show error if invite validation failed
|
|
155
|
+
if (registrationMode === "waitlist" && inviteCode && inviteError) {
|
|
156
|
+
return (
|
|
157
|
+
<>
|
|
158
|
+
<CardHeader>
|
|
159
|
+
<CardTitle className="text-primary flex flex-col items-center pb-10 text-4xl">
|
|
160
|
+
<Image src="/logo.webp" alt="Logo" width={100} height={100} priority />
|
|
161
|
+
{t("waitlist.invite.invalid_title")}
|
|
162
|
+
</CardTitle>
|
|
163
|
+
</CardHeader>
|
|
164
|
+
<CardContent className="text-center">
|
|
165
|
+
<p className="text-destructive mb-4">{inviteError}</p>
|
|
166
|
+
<p className="mb-4">{t("waitlist.invite.join_prompt")}</p>
|
|
167
|
+
<Link href="/waitlist" className="text-primary underline">
|
|
168
|
+
{t("waitlist.invite.join_link")}
|
|
169
|
+
</Link>
|
|
170
|
+
</CardContent>
|
|
171
|
+
</>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Show waitlist message if in waitlist mode without invite
|
|
176
|
+
if (registrationMode === "waitlist" && !inviteCode) {
|
|
177
|
+
return (
|
|
178
|
+
<>
|
|
179
|
+
<CardHeader>
|
|
180
|
+
<CardTitle className="text-primary flex flex-col items-center pb-10 text-4xl">
|
|
181
|
+
<Image src="/logo.webp" alt="Logo" width={100} height={100} priority />
|
|
182
|
+
{t("waitlist.invite.registration_title")}
|
|
183
|
+
</CardTitle>
|
|
184
|
+
</CardHeader>
|
|
185
|
+
<CardContent className="text-center">
|
|
186
|
+
<p className="mb-4">{t("waitlist.invite.registration_description")}</p>
|
|
187
|
+
<p className="mb-4">{t("waitlist.invite.registration_hint")}</p>
|
|
188
|
+
<Link href="/waitlist" className="text-primary underline">
|
|
189
|
+
{t("waitlist.invite.join_link")}
|
|
190
|
+
</Link>
|
|
191
|
+
</CardContent>
|
|
192
|
+
<CardFooter className="flex w-full flex-row justify-between">
|
|
193
|
+
<Link href="#" className="flex w-full justify-start" onClick={() => setComponentType(AuthComponent.Login)}>
|
|
194
|
+
{t("auth.buttons.login")}
|
|
195
|
+
</Link>
|
|
196
|
+
</CardFooter>
|
|
197
|
+
</>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
86
201
|
return (
|
|
87
202
|
<>
|
|
88
203
|
<CardHeader>
|
|
@@ -134,6 +249,70 @@ export default function Register() {
|
|
|
134
249
|
<Button className="mt-4 w-full" type={"submit"}>
|
|
135
250
|
{t(`auth.buttons.register`)}
|
|
136
251
|
</Button>
|
|
252
|
+
|
|
253
|
+
{/* OAuth options when invite code is validated */}
|
|
254
|
+
{registrationMode === "waitlist" &&
|
|
255
|
+
inviteValidated &&
|
|
256
|
+
(isGoogleAuthEnabled() || isDiscordAuthEnabled()) && (
|
|
257
|
+
<div className="space-y-4 pt-4">
|
|
258
|
+
<div className="relative">
|
|
259
|
+
<div className="absolute inset-0 flex items-center">
|
|
260
|
+
<span className="w-full border-t" />
|
|
261
|
+
</div>
|
|
262
|
+
<div className="relative flex justify-center text-xs uppercase">
|
|
263
|
+
<span className="bg-card px-2 text-muted-foreground">{t("auth.buttons.or")}</span>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div className="space-y-2">
|
|
268
|
+
{isGoogleAuthEnabled() && (
|
|
269
|
+
<Link
|
|
270
|
+
href={`${getApiUrl()}auth/google${inviteCode ? `?invite=${inviteCode}` : ""}`}
|
|
271
|
+
className="flex w-full"
|
|
272
|
+
>
|
|
273
|
+
<Button
|
|
274
|
+
className="w-full bg-white hover:bg-gray-50 text-gray-700 border border-gray-300"
|
|
275
|
+
variant="outline"
|
|
276
|
+
type="button"
|
|
277
|
+
>
|
|
278
|
+
<svg className="mr-2 h-5 w-5" viewBox="0 0 24 24">
|
|
279
|
+
<path
|
|
280
|
+
fill="#4285F4"
|
|
281
|
+
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
|
282
|
+
/>
|
|
283
|
+
<path
|
|
284
|
+
fill="#34A853"
|
|
285
|
+
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
|
286
|
+
/>
|
|
287
|
+
<path
|
|
288
|
+
fill="#FBBC05"
|
|
289
|
+
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
|
290
|
+
/>
|
|
291
|
+
<path
|
|
292
|
+
fill="#EA4335"
|
|
293
|
+
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
294
|
+
/>
|
|
295
|
+
</svg>
|
|
296
|
+
{t("waitlist.buttons.register_with_google")}
|
|
297
|
+
</Button>
|
|
298
|
+
</Link>
|
|
299
|
+
)}
|
|
300
|
+
{isDiscordAuthEnabled() && (
|
|
301
|
+
<Link
|
|
302
|
+
href={`${getApiUrl()}auth/discord${inviteCode ? `?invite=${inviteCode}` : ""}`}
|
|
303
|
+
className="flex w-full"
|
|
304
|
+
>
|
|
305
|
+
<Button className="w-full" variant="outline" type="button">
|
|
306
|
+
<svg className="mr-2 h-5 w-5" viewBox="0 0 24 24" fill="currentColor">
|
|
307
|
+
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" />
|
|
308
|
+
</svg>
|
|
309
|
+
{t("waitlist.buttons.register_with_discord")}
|
|
310
|
+
</Button>
|
|
311
|
+
</Link>
|
|
312
|
+
)}
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
)}
|
|
137
316
|
</CardContent>
|
|
138
317
|
<CardFooter className="flex w-full flex-row justify-between">
|
|
139
318
|
<Link
|
|
@@ -49,6 +49,7 @@ export class Auth extends AbstractApiData implements AuthInterface {
|
|
|
49
49
|
if (data.termsAcceptedAt !== undefined) response.data.attributes.termsAcceptedAt = data.termsAcceptedAt;
|
|
50
50
|
if (data.marketingConsent !== undefined) response.data.attributes.marketingConsent = data.marketingConsent;
|
|
51
51
|
if (data.marketingConsentAt !== undefined) response.data.attributes.marketingConsentAt = data.marketingConsentAt;
|
|
52
|
+
if (data.inviteCode !== undefined) response.data.attributes.inviteCode = data.inviteCode;
|
|
52
53
|
|
|
53
54
|
return response;
|
|
54
55
|
}
|
package/src/features/index.ts
CHANGED