heartraite 1.0.214 → 1.0.216
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/enum/cloudfunction.enum.d.ts +0 -4
- package/dist/enum/cloudfunction.enum.js +0 -4
- package/dist/enum/consultation.enum.d.ts +1 -1
- package/dist/enum/consultation.enum.js +1 -1
- package/dist/enum/firestore.enum.d.ts +0 -1
- package/dist/enum/firestore.enum.js +0 -1
- package/dist/hooks/useTypewriter.d.ts +1 -0
- package/dist/hooks/useTypewriter.js +44 -37
- package/dist/hooks/useTypewriter.test.js +39 -0
- package/dist/types/cloud-function-types.d.ts +2 -14
- package/dist/types/request.types.d.ts +0 -5
- package/dist/types/response.types.d.ts +0 -8
- package/package.json +1 -1
- package/src/enum/cloudfunction.enum.ts +0 -4
- package/src/enum/consultation.enum.ts +1 -1
- package/src/enum/firestore.enum.ts +0 -1
- package/src/hooks/useTypewriter.test.ts +47 -0
- package/src/hooks/useTypewriter.ts +51 -41
- package/src/types/cloud-function-types.ts +0 -20
- package/src/types/request.types.ts +0 -9
- package/src/types/response.types.ts +0 -6
|
@@ -43,10 +43,6 @@ export declare enum CloudFunction {
|
|
|
43
43
|
CREATE_REPORT = "report/create-report",
|
|
44
44
|
GET_SELF_AWARENESS = "sa/get-sa",
|
|
45
45
|
ADD_IMAGES = "storage/add-images",
|
|
46
|
-
GET_PRODUCTS = "stripe/get-products",
|
|
47
|
-
STRIPE_WEBWOOK = "stripe/webhook",
|
|
48
|
-
CREATE_BILLING_PORTAL = "stripe/create-billing-portal",
|
|
49
|
-
CREATE_CHECKOUT_SESSION = "stripe/create-checkout-session",
|
|
50
46
|
GET_USER_SURVEYS = "survey/get-user-surveys",
|
|
51
47
|
SUBMIT_USER_SURVEY = "survey/submit-user-survey",
|
|
52
48
|
REGISTER_ONBOARDING = "user/register-onboarding",
|
|
@@ -47,10 +47,6 @@ var CloudFunction;
|
|
|
47
47
|
CloudFunction["CREATE_REPORT"] = "report/create-report";
|
|
48
48
|
CloudFunction["GET_SELF_AWARENESS"] = "sa/get-sa";
|
|
49
49
|
CloudFunction["ADD_IMAGES"] = "storage/add-images";
|
|
50
|
-
CloudFunction["GET_PRODUCTS"] = "stripe/get-products";
|
|
51
|
-
CloudFunction["STRIPE_WEBWOOK"] = "stripe/webhook";
|
|
52
|
-
CloudFunction["CREATE_BILLING_PORTAL"] = "stripe/create-billing-portal";
|
|
53
|
-
CloudFunction["CREATE_CHECKOUT_SESSION"] = "stripe/create-checkout-session";
|
|
54
50
|
CloudFunction["GET_USER_SURVEYS"] = "survey/get-user-surveys";
|
|
55
51
|
CloudFunction["SUBMIT_USER_SURVEY"] = "survey/submit-user-survey";
|
|
56
52
|
CloudFunction["REGISTER_ONBOARDING"] = "user/register-onboarding";
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* PENDING → user expressed interest, team hasn't reached
|
|
9
9
|
* out yet. Initial state on submit.
|
|
10
10
|
* FOLLOWED_UP → team emailed the user. v1 manual; v2 may be
|
|
11
|
-
* automated after
|
|
11
|
+
* automated after payment.
|
|
12
12
|
* BOOKED → consultation session scheduled (v2 only — v1
|
|
13
13
|
* tracks this only via team-internal notes).
|
|
14
14
|
* COMPLETED → session happened.
|
|
@@ -11,7 +11,7 @@ exports.ConsultationInterestStatus = void 0;
|
|
|
11
11
|
* PENDING → user expressed interest, team hasn't reached
|
|
12
12
|
* out yet. Initial state on submit.
|
|
13
13
|
* FOLLOWED_UP → team emailed the user. v1 manual; v2 may be
|
|
14
|
-
* automated after
|
|
14
|
+
* automated after payment.
|
|
15
15
|
* BOOKED → consultation session scheduled (v2 only — v1
|
|
16
16
|
* tracks this only via team-internal notes).
|
|
17
17
|
* COMPLETED → session happened.
|
|
@@ -10,7 +10,6 @@ var FirestoreCollection;
|
|
|
10
10
|
FirestoreCollection["MESSAGES"] = "messages";
|
|
11
11
|
FirestoreCollection["USERS"] = "users";
|
|
12
12
|
FirestoreCollection["RATING"] = "ratings";
|
|
13
|
-
FirestoreCollection["STRIPE_SUBSCRIPTIONS"] = "stripe_subscriptions";
|
|
14
13
|
FirestoreCollection["REPORTS"] = "reports";
|
|
15
14
|
FirestoreCollection["MATCHES"] = "matches";
|
|
16
15
|
FirestoreCollection["REFERRALS"] = "referrals";
|
|
@@ -6,56 +6,63 @@ const useTypewriter = ({ text, typingSpeed = 50, initialDelay = 1000, blinkingSp
|
|
|
6
6
|
const [isComplete, setIsComplete] = (0, react_1.useState)(false);
|
|
7
7
|
const [displayedText, setDisplayedText] = (0, react_1.useState)("");
|
|
8
8
|
const [showDot, setShowDot] = (0, react_1.useState)(false);
|
|
9
|
+
const timersRef = (0, react_1.useRef)({ blinking: null, timeouts: new Set() });
|
|
10
|
+
const clearTimers = (0, react_1.useCallback)(() => {
|
|
11
|
+
const timers = timersRef.current;
|
|
12
|
+
if (timers.blinking)
|
|
13
|
+
clearInterval(timers.blinking);
|
|
14
|
+
timers.blinking = null;
|
|
15
|
+
timers.timeouts.forEach(clearTimeout);
|
|
16
|
+
timers.timeouts.clear();
|
|
17
|
+
}, []);
|
|
9
18
|
(0, react_1.useEffect)(() => {
|
|
10
19
|
if (!text || text.length === 0) {
|
|
11
|
-
setDisplayedText("");
|
|
12
|
-
setIsComplete(true);
|
|
13
|
-
setShowDot(false);
|
|
14
|
-
return;
|
|
20
|
+
setDisplayedText("");
|
|
21
|
+
setIsComplete(true);
|
|
22
|
+
setShowDot(false);
|
|
23
|
+
return;
|
|
15
24
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const timers = timersRef.current;
|
|
26
|
+
const schedule = (fn, ms) => {
|
|
27
|
+
const id = setTimeout(() => {
|
|
28
|
+
timers.timeouts.delete(id);
|
|
29
|
+
fn();
|
|
30
|
+
}, ms);
|
|
31
|
+
timers.timeouts.add(id);
|
|
32
|
+
};
|
|
33
|
+
setDisplayedText("");
|
|
34
|
+
setShowDot(true);
|
|
35
|
+
setIsComplete(false);
|
|
36
|
+
timers.blinking = setInterval(() => {
|
|
24
37
|
setShowDot((prev) => !prev);
|
|
25
38
|
}, blinkingSpeed);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Typing effect
|
|
33
|
-
let currentIndex = 0;
|
|
39
|
+
schedule(() => {
|
|
40
|
+
if (timers.blinking)
|
|
41
|
+
clearInterval(timers.blinking);
|
|
42
|
+
timers.blinking = null;
|
|
43
|
+
setShowDot(false);
|
|
44
|
+
let currentIndex = 1;
|
|
34
45
|
const typeNextChar = () => {
|
|
35
46
|
if (currentIndex < text.length) {
|
|
36
|
-
const charToAdd = text[currentIndex];
|
|
37
|
-
setDisplayedText((prev) => prev + charToAdd); // Append character
|
|
38
47
|
currentIndex++;
|
|
39
|
-
|
|
48
|
+
setDisplayedText(text.slice(0, currentIndex));
|
|
49
|
+
schedule(typeNextChar, typingSpeed);
|
|
40
50
|
}
|
|
41
51
|
else {
|
|
42
|
-
setIsComplete(true);
|
|
52
|
+
setIsComplete(true);
|
|
43
53
|
}
|
|
44
54
|
};
|
|
45
|
-
// Trigger the first character manually
|
|
46
55
|
setDisplayedText(text.charAt(0));
|
|
47
|
-
|
|
48
|
-
// Schedule the rest of the characters
|
|
49
|
-
setTimeout(typeNextChar, typingSpeed);
|
|
56
|
+
schedule(typeNextChar, typingSpeed);
|
|
50
57
|
}, initialDelay);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}, [text,
|
|
59
|
-
return { displayedText, showDot, isComplete };
|
|
58
|
+
return clearTimers;
|
|
59
|
+
}, [text, typingSpeed, initialDelay, blinkingSpeed, clearTimers]);
|
|
60
|
+
const revealAll = (0, react_1.useCallback)(() => {
|
|
61
|
+
clearTimers();
|
|
62
|
+
setDisplayedText(text ?? "");
|
|
63
|
+
setShowDot(false);
|
|
64
|
+
setIsComplete(true);
|
|
65
|
+
}, [text, clearTimers]);
|
|
66
|
+
return { displayedText, showDot, isComplete, revealAll };
|
|
60
67
|
};
|
|
61
68
|
exports.useTypewriter = useTypewriter;
|
|
@@ -68,4 +68,43 @@ describe("useTypewriter", () => {
|
|
|
68
68
|
});
|
|
69
69
|
expect(result.current.displayedText).toBe(sampleText.slice(0, 2));
|
|
70
70
|
});
|
|
71
|
+
it("reveals the full text immediately when revealAll is called mid-typing", () => {
|
|
72
|
+
const { result } = (0, react_1.renderHook)(() => (0, useTypewriter_1.useTypewriter)(defaultOptions));
|
|
73
|
+
(0, react_1.act)(() => {
|
|
74
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
75
|
+
});
|
|
76
|
+
expect(result.current.isComplete).toBe(false);
|
|
77
|
+
(0, react_1.act)(() => {
|
|
78
|
+
result.current.revealAll();
|
|
79
|
+
});
|
|
80
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
81
|
+
expect(result.current.isComplete).toBe(true);
|
|
82
|
+
expect(result.current.showDot).toBe(false);
|
|
83
|
+
(0, react_1.act)(() => {
|
|
84
|
+
jest.advanceTimersByTime(sampleText.length * defaultOptions.typingSpeed);
|
|
85
|
+
});
|
|
86
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
87
|
+
});
|
|
88
|
+
it("reveals the full text when revealAll is called before typing starts", () => {
|
|
89
|
+
const { result } = (0, react_1.renderHook)(() => (0, useTypewriter_1.useTypewriter)(defaultOptions));
|
|
90
|
+
(0, react_1.act)(() => {
|
|
91
|
+
result.current.revealAll();
|
|
92
|
+
});
|
|
93
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
94
|
+
expect(result.current.isComplete).toBe(true);
|
|
95
|
+
expect(result.current.showDot).toBe(false);
|
|
96
|
+
(0, react_1.act)(() => {
|
|
97
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay * 2);
|
|
98
|
+
});
|
|
99
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
100
|
+
expect(result.current.showDot).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
it("stops all timers on unmount", () => {
|
|
103
|
+
const { unmount } = (0, react_1.renderHook)(() => (0, useTypewriter_1.useTypewriter)(defaultOptions));
|
|
104
|
+
(0, react_1.act)(() => {
|
|
105
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
106
|
+
});
|
|
107
|
+
unmount();
|
|
108
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
109
|
+
});
|
|
71
110
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CloudFunction } from "../enum";
|
|
2
|
-
import { AddImagesRequest, AuthenticateBankIDRequest, CollectBankIDRequest,
|
|
3
|
-
import { AddImagesResponse, AuthenticateBankIDResponse, CollectBankIDResponse,
|
|
2
|
+
import { AddImagesRequest, AuthenticateBankIDRequest, CollectBankIDRequest, CreateLikeRequest, CreatePLSInputRequest, CreatePLSSubmissionRequest, CreateReportRequest, DeleteUserRequest, GetCARequest, GetMatchableUserRequest, GetMatchCheckRequest, GetMatchesRequest, GetAdvancedMatchRequest, GetMessagesRequest, GetPLSSubmissionRequest, GetSelfAwarenessRequest, GetUserRequest, HandleLastMessageSeenRequest, HandleLikeSeenRequest, HandleMatchSeenRequest, RegisterOnboardingRequest, RegisterUserRequest, RemoveMatchRequest, SendMessageRequest, SubmitAnswerRequest, SubmitCategoryFeedbackRequest, SubmitPLSCategoryFeedbackRequest, SubmitPLSDemographicsRequest, UpdatePLSAnswerRequest, UpdateQuestionsRequest, UpdateUserRequest, SubmitFeedbackRequest, ExpressConsultationInterestRequest, GetMyConsultationInterestRequest, GetConsultationInterestsRequest, UpdateConsultationInterestRequest, SyncAffiliateRequest, JoinEventRequest, GetEventRequest, GetEventMatchRequest, SendEventFeedbackRequest, GetEventParticipantsRequest } from "./request.types";
|
|
3
|
+
import { AddImagesResponse, AuthenticateBankIDResponse, CollectBankIDResponse, CreateLikeResponse, CreatePLSInputResponse, CreatePLSSubmissionResponse, CreateReportResponse, DeleteUserResponse, GetCAResponse, GetMatchableUserResponse, GetMatchableUsersResponse, GetMatchCheckResponse, GetMatchesResponse, GetAdvancedMatchResponse, GetMessagesResponse, GetPLSSubmissionResponse, GetSelfAwarenessReponse, GetUserResponse, HandleLastMessageSeenResponse, HandleLikeSeenResponse, HandleMatchSeenResponse, RegisterOnboardingResponse, RegisterUserResponse, RemoveMatchResponse, SendMessageResponse, SubmitAnswerResponse, SubmitCategoryFeedbackResponse, SubmitPLSCategoryFeedbackResponse, SubmitPLSDemographicsResponse, UpdatePLSAnswerResponse, UpdateQuestionsResponse, UpdateUserResponse, SubmitFeedbackResponse, ExpressConsultationInterestResponse, GetMyConsultationInterestResponse, GetConsultationInterestsResponse, UpdateConsultationInterestResponse, SyncAffiliateResponse, GetUserEventsResponse, JoinEventResponse, GetEventResponse, GetEventMatchResponse, SendEventFeedbackResponse, GetEventParticipantsResponse } from "./response.types";
|
|
4
4
|
/**
|
|
5
5
|
* @deprecated This function is deprecated.
|
|
6
6
|
* Use `CloudFunctionTypes` inside application code instead.
|
|
@@ -167,18 +167,6 @@ export type CloudFunctionTypes = {
|
|
|
167
167
|
payload: AddImagesRequest;
|
|
168
168
|
response: AddImagesResponse;
|
|
169
169
|
};
|
|
170
|
-
[CloudFunction.GET_PRODUCTS]: {
|
|
171
|
-
payload: GetProductsRequest;
|
|
172
|
-
response: GetProductsResponse;
|
|
173
|
-
};
|
|
174
|
-
[CloudFunction.CREATE_BILLING_PORTAL]: {
|
|
175
|
-
payload: CreateBillingPortalRequest;
|
|
176
|
-
response: CreateBillingPortalResponse;
|
|
177
|
-
};
|
|
178
|
-
[CloudFunction.CREATE_CHECKOUT_SESSION]: {
|
|
179
|
-
payload: CreateCheckoutSessionRequest;
|
|
180
|
-
response: CreateCheckoutSessionResponse;
|
|
181
|
-
};
|
|
182
170
|
[CloudFunction.REGISTER_ONBOARDING]: {
|
|
183
171
|
payload: RegisterOnboardingRequest;
|
|
184
172
|
response: RegisterOnboardingResponse;
|
|
@@ -184,9 +184,6 @@ export type CreateReportRequest = {
|
|
|
184
184
|
reason: ReportReason;
|
|
185
185
|
description?: string;
|
|
186
186
|
};
|
|
187
|
-
export type CreateCheckoutSessionRequest = {
|
|
188
|
-
priceId: string;
|
|
189
|
-
};
|
|
190
187
|
export type RegisterOnboardingRequest = {
|
|
191
188
|
firstName: string;
|
|
192
189
|
state: string;
|
|
@@ -233,5 +230,3 @@ export type GetPLSScoresRequest = undefined;
|
|
|
233
230
|
export type AddImagesRequest = {
|
|
234
231
|
images: string[];
|
|
235
232
|
};
|
|
236
|
-
export type GetProductsRequest = undefined;
|
|
237
|
-
export type CreateBillingPortalRequest = undefined;
|
|
@@ -4,7 +4,6 @@ import { Event, FullParticipant, FullParticipantWithCS } from "./event.types";
|
|
|
4
4
|
import { UserMatch } from "./match.types";
|
|
5
5
|
import { MatchableUser, MatchCheck } from "./matchmaking.types";
|
|
6
6
|
import { Message } from "./message.types";
|
|
7
|
-
import { StripeProduct } from "./stripe.types";
|
|
8
7
|
import { User } from "./user.types";
|
|
9
8
|
import { OutgoingLike } from "./like.types";
|
|
10
9
|
import { CA } from "./ca.types";
|
|
@@ -82,13 +81,6 @@ export type GetSelfAwarenessReponse = SelfAwareness | {
|
|
|
82
81
|
processing: true;
|
|
83
82
|
};
|
|
84
83
|
export type GetPLSScoresResponse = PLSScore[];
|
|
85
|
-
export type CreateBillingPortalResponse = {
|
|
86
|
-
url: string;
|
|
87
|
-
};
|
|
88
|
-
export type CreateCheckoutSessionResponse = {
|
|
89
|
-
url: string;
|
|
90
|
-
};
|
|
91
|
-
export type GetProductsResponse = StripeProduct[];
|
|
92
84
|
export type RegisterOnboardingResponse = void;
|
|
93
85
|
export type GetUserResponse = User;
|
|
94
86
|
export type UpdateUserResponse = User;
|
package/package.json
CHANGED
|
@@ -43,10 +43,6 @@ export enum CloudFunction {
|
|
|
43
43
|
CREATE_REPORT = "report/create-report",
|
|
44
44
|
GET_SELF_AWARENESS = "sa/get-sa",
|
|
45
45
|
ADD_IMAGES = "storage/add-images",
|
|
46
|
-
GET_PRODUCTS = "stripe/get-products",
|
|
47
|
-
STRIPE_WEBWOOK = "stripe/webhook",
|
|
48
|
-
CREATE_BILLING_PORTAL = "stripe/create-billing-portal",
|
|
49
|
-
CREATE_CHECKOUT_SESSION = "stripe/create-checkout-session",
|
|
50
46
|
GET_USER_SURVEYS = "survey/get-user-surveys",
|
|
51
47
|
SUBMIT_USER_SURVEY = "survey/submit-user-survey",
|
|
52
48
|
REGISTER_ONBOARDING = "user/register-onboarding",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* PENDING → user expressed interest, team hasn't reached
|
|
9
9
|
* out yet. Initial state on submit.
|
|
10
10
|
* FOLLOWED_UP → team emailed the user. v1 manual; v2 may be
|
|
11
|
-
* automated after
|
|
11
|
+
* automated after payment.
|
|
12
12
|
* BOOKED → consultation session scheduled (v2 only — v1
|
|
13
13
|
* tracks this only via team-internal notes).
|
|
14
14
|
* COMPLETED → session happened.
|
|
@@ -83,4 +83,51 @@ describe("useTypewriter", () => {
|
|
|
83
83
|
});
|
|
84
84
|
expect(result.current.displayedText).toBe(sampleText.slice(0, 2));
|
|
85
85
|
});
|
|
86
|
+
|
|
87
|
+
it("reveals the full text immediately when revealAll is called mid-typing", () => {
|
|
88
|
+
const { result } = renderHook(() => useTypewriter(defaultOptions));
|
|
89
|
+
|
|
90
|
+
act(() => {
|
|
91
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
92
|
+
});
|
|
93
|
+
expect(result.current.isComplete).toBe(false);
|
|
94
|
+
|
|
95
|
+
act(() => {
|
|
96
|
+
result.current.revealAll();
|
|
97
|
+
});
|
|
98
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
99
|
+
expect(result.current.isComplete).toBe(true);
|
|
100
|
+
expect(result.current.showDot).toBe(false);
|
|
101
|
+
|
|
102
|
+
act(() => {
|
|
103
|
+
jest.advanceTimersByTime(sampleText.length * defaultOptions.typingSpeed);
|
|
104
|
+
});
|
|
105
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("reveals the full text when revealAll is called before typing starts", () => {
|
|
109
|
+
const { result } = renderHook(() => useTypewriter(defaultOptions));
|
|
110
|
+
|
|
111
|
+
act(() => {
|
|
112
|
+
result.current.revealAll();
|
|
113
|
+
});
|
|
114
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
115
|
+
expect(result.current.isComplete).toBe(true);
|
|
116
|
+
expect(result.current.showDot).toBe(false);
|
|
117
|
+
|
|
118
|
+
act(() => {
|
|
119
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay * 2);
|
|
120
|
+
});
|
|
121
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
122
|
+
expect(result.current.showDot).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("stops all timers on unmount", () => {
|
|
126
|
+
const { unmount } = renderHook(() => useTypewriter(defaultOptions));
|
|
127
|
+
act(() => {
|
|
128
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
129
|
+
});
|
|
130
|
+
unmount();
|
|
131
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
132
|
+
});
|
|
86
133
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
interface UseTypewriterOptions {
|
|
4
4
|
text: string;
|
|
5
|
-
typingSpeed?: number;
|
|
6
|
-
initialDelay?: number;
|
|
7
|
-
blinkingSpeed?: number;
|
|
5
|
+
typingSpeed?: number;
|
|
6
|
+
initialDelay?: number;
|
|
7
|
+
blinkingSpeed?: number;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export const useTypewriter = ({
|
|
@@ -16,63 +16,73 @@ export const useTypewriter = ({
|
|
|
16
16
|
const [isComplete, setIsComplete] = useState(false);
|
|
17
17
|
const [displayedText, setDisplayedText] = useState("");
|
|
18
18
|
const [showDot, setShowDot] = useState(false);
|
|
19
|
+
const timersRef = useRef<{
|
|
20
|
+
blinking: ReturnType<typeof setInterval> | null;
|
|
21
|
+
timeouts: Set<ReturnType<typeof setTimeout>>;
|
|
22
|
+
}>({ blinking: null, timeouts: new Set() });
|
|
23
|
+
|
|
24
|
+
const clearTimers = useCallback(() => {
|
|
25
|
+
const timers = timersRef.current;
|
|
26
|
+
if (timers.blinking) clearInterval(timers.blinking);
|
|
27
|
+
timers.blinking = null;
|
|
28
|
+
timers.timeouts.forEach(clearTimeout);
|
|
29
|
+
timers.timeouts.clear();
|
|
30
|
+
}, []);
|
|
19
31
|
|
|
20
32
|
useEffect(() => {
|
|
21
33
|
if (!text || text.length === 0) {
|
|
22
|
-
setDisplayedText("");
|
|
23
|
-
setIsComplete(true);
|
|
24
|
-
setShowDot(false);
|
|
25
|
-
return;
|
|
34
|
+
setDisplayedText("");
|
|
35
|
+
setIsComplete(true);
|
|
36
|
+
setShowDot(false);
|
|
37
|
+
return;
|
|
26
38
|
}
|
|
27
39
|
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
const timers = timersRef.current;
|
|
41
|
+
const schedule = (fn: () => void, ms: number) => {
|
|
42
|
+
const id = setTimeout(() => {
|
|
43
|
+
timers.timeouts.delete(id);
|
|
44
|
+
fn();
|
|
45
|
+
}, ms);
|
|
46
|
+
timers.timeouts.add(id);
|
|
47
|
+
};
|
|
30
48
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
setIsComplete(false); // Reset completion flag
|
|
49
|
+
setDisplayedText("");
|
|
50
|
+
setShowDot(true);
|
|
51
|
+
setIsComplete(false);
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
blinkingInterval = setInterval(() => {
|
|
53
|
+
timers.blinking = setInterval(() => {
|
|
38
54
|
setShowDot((prev) => !prev);
|
|
39
55
|
}, blinkingSpeed);
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
setShowDot(false); // Hide blinking dot
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Typing effect
|
|
49
|
-
let currentIndex = 0;
|
|
57
|
+
schedule(() => {
|
|
58
|
+
if (timers.blinking) clearInterval(timers.blinking);
|
|
59
|
+
timers.blinking = null;
|
|
60
|
+
setShowDot(false);
|
|
50
61
|
|
|
62
|
+
let currentIndex = 1;
|
|
51
63
|
const typeNextChar = () => {
|
|
52
64
|
if (currentIndex < text.length) {
|
|
53
|
-
const charToAdd = text[currentIndex];
|
|
54
|
-
setDisplayedText((prev) => prev + charToAdd); // Append character
|
|
55
65
|
currentIndex++;
|
|
56
|
-
|
|
66
|
+
setDisplayedText(text.slice(0, currentIndex));
|
|
67
|
+
schedule(typeNextChar, typingSpeed);
|
|
57
68
|
} else {
|
|
58
|
-
setIsComplete(true);
|
|
69
|
+
setIsComplete(true);
|
|
59
70
|
}
|
|
60
71
|
};
|
|
61
72
|
|
|
62
|
-
// Trigger the first character manually
|
|
63
73
|
setDisplayedText(text.charAt(0));
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// Schedule the rest of the characters
|
|
67
|
-
setTimeout(typeNextChar, typingSpeed);
|
|
74
|
+
schedule(typeNextChar, typingSpeed);
|
|
68
75
|
}, initialDelay);
|
|
69
76
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
return clearTimers;
|
|
78
|
+
}, [text, typingSpeed, initialDelay, blinkingSpeed, clearTimers]);
|
|
79
|
+
|
|
80
|
+
const revealAll = useCallback(() => {
|
|
81
|
+
clearTimers();
|
|
82
|
+
setDisplayedText(text ?? "");
|
|
83
|
+
setShowDot(false);
|
|
84
|
+
setIsComplete(true);
|
|
85
|
+
}, [text, clearTimers]);
|
|
76
86
|
|
|
77
|
-
return { displayedText, showDot, isComplete };
|
|
87
|
+
return { displayedText, showDot, isComplete, revealAll };
|
|
78
88
|
};
|
|
@@ -3,8 +3,6 @@ import {
|
|
|
3
3
|
AddImagesRequest,
|
|
4
4
|
AuthenticateBankIDRequest,
|
|
5
5
|
CollectBankIDRequest,
|
|
6
|
-
CreateBillingPortalRequest,
|
|
7
|
-
CreateCheckoutSessionRequest,
|
|
8
6
|
CreateLikeRequest,
|
|
9
7
|
CreatePLSInputRequest,
|
|
10
8
|
CreatePLSSubmissionRequest,
|
|
@@ -17,7 +15,6 @@ import {
|
|
|
17
15
|
GetAdvancedMatchRequest,
|
|
18
16
|
GetMessagesRequest,
|
|
19
17
|
GetPLSSubmissionRequest,
|
|
20
|
-
GetProductsRequest,
|
|
21
18
|
GetSelfAwarenessRequest,
|
|
22
19
|
GetUserRequest,
|
|
23
20
|
HandleLastMessageSeenRequest,
|
|
@@ -50,8 +47,6 @@ import {
|
|
|
50
47
|
AddImagesResponse,
|
|
51
48
|
AuthenticateBankIDResponse,
|
|
52
49
|
CollectBankIDResponse,
|
|
53
|
-
CreateBillingPortalResponse,
|
|
54
|
-
CreateCheckoutSessionResponse,
|
|
55
50
|
CreateLikeResponse,
|
|
56
51
|
CreatePLSInputResponse,
|
|
57
52
|
CreatePLSSubmissionResponse,
|
|
@@ -65,7 +60,6 @@ import {
|
|
|
65
60
|
GetAdvancedMatchResponse,
|
|
66
61
|
GetMessagesResponse,
|
|
67
62
|
GetPLSSubmissionResponse,
|
|
68
|
-
GetProductsResponse,
|
|
69
63
|
GetSelfAwarenessReponse,
|
|
70
64
|
GetUserResponse,
|
|
71
65
|
HandleLastMessageSeenResponse,
|
|
@@ -293,20 +287,6 @@ export type CloudFunctionTypes = {
|
|
|
293
287
|
response: AddImagesResponse;
|
|
294
288
|
};
|
|
295
289
|
|
|
296
|
-
// stripe
|
|
297
|
-
[CloudFunction.GET_PRODUCTS]: {
|
|
298
|
-
payload: GetProductsRequest;
|
|
299
|
-
response: GetProductsResponse;
|
|
300
|
-
};
|
|
301
|
-
[CloudFunction.CREATE_BILLING_PORTAL]: {
|
|
302
|
-
payload: CreateBillingPortalRequest;
|
|
303
|
-
response: CreateBillingPortalResponse;
|
|
304
|
-
};
|
|
305
|
-
[CloudFunction.CREATE_CHECKOUT_SESSION]: {
|
|
306
|
-
payload: CreateCheckoutSessionRequest;
|
|
307
|
-
response: CreateCheckoutSessionResponse;
|
|
308
|
-
};
|
|
309
|
-
|
|
310
290
|
// user
|
|
311
291
|
[CloudFunction.REGISTER_ONBOARDING]: {
|
|
312
292
|
payload: RegisterOnboardingRequest;
|
|
@@ -214,11 +214,6 @@ export type CreateReportRequest = {
|
|
|
214
214
|
description?: string;
|
|
215
215
|
};
|
|
216
216
|
|
|
217
|
-
// stripe
|
|
218
|
-
export type CreateCheckoutSessionRequest = {
|
|
219
|
-
priceId: string;
|
|
220
|
-
};
|
|
221
|
-
|
|
222
217
|
// user
|
|
223
218
|
export type RegisterOnboardingRequest = {
|
|
224
219
|
firstName: string;
|
|
@@ -264,7 +259,3 @@ export type GetPLSScoresRequest = undefined;
|
|
|
264
259
|
|
|
265
260
|
// storage
|
|
266
261
|
export type AddImagesRequest = { images: string[] };
|
|
267
|
-
|
|
268
|
-
// stripe
|
|
269
|
-
export type GetProductsRequest = undefined;
|
|
270
|
-
export type CreateBillingPortalRequest = undefined;
|
|
@@ -7,7 +7,6 @@ import { Event, FullParticipant, FullParticipantWithCS } from "./event.types";
|
|
|
7
7
|
import { UserMatch } from "./match.types";
|
|
8
8
|
import { MatchableUser, MatchCheck } from "./matchmaking.types";
|
|
9
9
|
import { Message } from "./message.types";
|
|
10
|
-
import { StripeProduct } from "./stripe.types";
|
|
11
10
|
import { User } from "./user.types";
|
|
12
11
|
import { OutgoingLike } from "./like.types";
|
|
13
12
|
import { CA } from "./ca.types";
|
|
@@ -123,11 +122,6 @@ export type GetSelfAwarenessReponse = SelfAwareness | { processing: true };
|
|
|
123
122
|
// score
|
|
124
123
|
export type GetPLSScoresResponse = PLSScore[];
|
|
125
124
|
|
|
126
|
-
// stripe
|
|
127
|
-
export type CreateBillingPortalResponse = { url: string };
|
|
128
|
-
export type CreateCheckoutSessionResponse = { url: string };
|
|
129
|
-
export type GetProductsResponse = StripeProduct[];
|
|
130
|
-
|
|
131
125
|
// user
|
|
132
126
|
export type RegisterOnboardingResponse = void;
|
|
133
127
|
export type GetUserResponse = User;
|