Skip to content

Commit d864e9c

Browse files
committed
fix (onboarding): fixed redirection issues
1 parent 0952b96 commit d864e9c

6 files changed

Lines changed: 267 additions & 40 deletions

File tree

src/client/app/complete-profile/page.js

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
"use client"
22

3-
import React, { useState } from "react"
3+
import React, { useState, useRef } from "react"
44
import { motion } from "framer-motion"
55
import { cn } from "@utils/cn"
66
import toast from "react-hot-toast"
77
import { useRouter } from "next/navigation"
88
import {
99
IconBrandWhatsapp,
1010
IconLoader,
11-
IconSparkles
11+
IconSparkles,
12+
IconCheck,
13+
IconX
1214
} from "@tabler/icons-react"
1315
import InteractiveNetworkBackground from "@components/ui/InteractiveNetworkBackground"
1416

@@ -23,7 +25,7 @@ const questions = [
2325
{
2426
id: "whatsapp_notifications_number",
2527
question:
26-
"To send you important notifications, task updates, and reminders on WhatsApp, please enter your number with the country code.",
28+
"I will send you important notifications, task updates, and reminders on WhatsApp. We're in the process of getting an official number, so for now, messages will come from our co-founder Sarthak (+91827507823), who may also occasionally reach out for feedback. \n\nPlease enter your number with the country code.",
2729
type: "text-input",
2830
required: true,
2931
placeholder: "+14155552671",
@@ -36,9 +38,60 @@ const CompleteProfilePage = () => {
3638
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0)
3739
const [isSubmitting, setIsSubmitting] = useState(false)
3840
const router = useRouter()
41+
const [whatsappStatus, setWhatsappStatus] = useState("idle") // idle, checking, valid, invalid
42+
const [whatsappError, setWhatsappError] = useState("")
43+
const debounceTimeoutRef = useRef(null)
44+
45+
const verifyWhatsappNumber = async (number) => {
46+
if (!/^\+[1-9]\d{1,14}$/.test(number.trim())) {
47+
setWhatsappStatus("invalid")
48+
setWhatsappError(
49+
"Please use E.164 format with country code (e.g., +14155552671)."
50+
)
51+
return
52+
}
53+
setWhatsappStatus("checking")
54+
setWhatsappError("")
55+
try {
56+
const response = await fetch("/api/testing/whatsapp/verify", {
57+
method: "POST",
58+
headers: { "Content-Type": "application/json" },
59+
body: JSON.stringify({ phone_number: number })
60+
})
61+
const result = await response.json()
62+
if (!response.ok) {
63+
throw new Error(result.detail || "Verification request failed.")
64+
}
65+
if (result.numberExists) {
66+
setWhatsappStatus("valid")
67+
setWhatsappError("")
68+
} else {
69+
setWhatsappStatus("invalid")
70+
setWhatsappError(
71+
"This number does not appear to be on WhatsApp."
72+
)
73+
}
74+
} catch (error) {
75+
setWhatsappStatus("invalid")
76+
setWhatsappError(error.message)
77+
}
78+
}
3979

4080
const handleAnswer = (questionId, answer) => {
4181
setAnswers((prev) => ({ ...prev, [questionId]: answer }))
82+
if (questionId === "whatsapp_notifications_number") {
83+
setWhatsappStatus("idle")
84+
if (debounceTimeoutRef.current) {
85+
clearTimeout(debounceTimeoutRef.current)
86+
}
87+
if (answer.trim()) {
88+
debounceTimeoutRef.current = setTimeout(() => {
89+
verifyWhatsappNumber(answer)
90+
}, 800)
91+
} else {
92+
setWhatsappError("")
93+
}
94+
}
4295
}
4396

4497
const handleNext = () => {
@@ -52,6 +105,10 @@ const CompleteProfilePage = () => {
52105
toast.error("Please answer all questions to continue.")
53106
return
54107
}
108+
if (whatsappStatus !== "valid") {
109+
toast.error("Please provide a valid WhatsApp number to continue.")
110+
return
111+
}
55112
setIsSubmitting(true)
56113
try {
57114
const response = await fetch("/api/settings/complete-profile", {
@@ -64,7 +121,7 @@ const CompleteProfilePage = () => {
64121
throw new Error(result.detail || "Failed to update profile.")
65122
}
66123
toast.success("Thank you! Your profile is now complete.")
67-
router.push("/chat")
124+
window.location.href = "/chat"
68125
} catch (error) {
69126
toast.error(`Error: ${error.message}`)
70127
} finally {
@@ -98,9 +155,34 @@ const CompleteProfilePage = () => {
98155
</p>
99156

100157
<div className="bg-neutral-900/50 border border-neutral-700/50 rounded-2xl p-6 sm:p-8 text-left space-y-6">
101-
<p className="whitespace-pre-wrap text-neutral-200">
102-
{currentQuestion.question}
103-
</p>
158+
{currentQuestion.id === "needs-pa" ? (
159+
<div className="text-neutral-200 space-y-4">
160+
<p>
161+
Are you someone who finds themselves spending
162+
too much time on administrative work? For
163+
example:
164+
</p>
165+
<ul className="list-disc list-inside pl-4 space-y-2 text-neutral-300">
166+
<li>Juggling multiple priorities</li>
167+
<li>
168+
Managing a small team or leading projects
169+
</li>
170+
<li>
171+
Scheduling meetings and organizing calendars
172+
</li>
173+
<li>Responding to routine emails</li>
174+
</ul>
175+
<p className="font-semibold pt-2">
176+
Do you ever feel the need for a personal
177+
assistant (human or AI) to handle these
178+
repetitive tasks?
179+
</p>
180+
</div>
181+
) : (
182+
<p className="whitespace-pre-wrap text-neutral-200">
183+
{currentQuestion.question}
184+
</p>
185+
)}
104186

105187
{currentQuestion.type === "yes-no" && (
106188
<div className="flex gap-4 pt-2">
@@ -140,19 +222,50 @@ const CompleteProfilePage = () => {
140222
)
141223
}
142224
placeholder={currentQuestion.placeholder}
143-
className="w-full pl-10 pr-4 py-3 bg-neutral-800 border border-neutral-700 rounded-lg focus:ring-2 focus:ring-brand-orange"
225+
className="w-full pl-10 pr-10 py-3 bg-neutral-800 border border-neutral-700 rounded-lg focus:ring-2 focus:ring-brand-orange"
144226
autoFocus
145227
/>
228+
{currentQuestion.id ===
229+
"whatsapp_notifications_number" && (
230+
<div className="absolute right-3 top-1/2 -translate-y-1/2">
231+
{whatsappStatus === "checking" && (
232+
<IconLoader
233+
size={18}
234+
className="animate-spin text-neutral-400"
235+
/>
236+
)}
237+
{whatsappStatus === "valid" && (
238+
<IconCheck
239+
size={18}
240+
className="text-green-500"
241+
/>
242+
)}
243+
{whatsappStatus === "invalid" && (
244+
<IconX
245+
size={18}
246+
className="text-red-500"
247+
/>
248+
)}
249+
</div>
250+
)}
146251
</div>
147252
)}
253+
{currentQuestion.id === "whatsapp_notifications_number" &&
254+
whatsappStatus === "invalid" &&
255+
whatsappError && (
256+
<p className="text-red-500 text-sm mt-2">
257+
{whatsappError}
258+
</p>
259+
)}
148260
</div>
149261

150262
<div className="mt-8">
151263
<button
152264
onClick={handleSubmit}
153265
disabled={
154266
isSubmitting ||
155-
currentQuestionIndex !== questions.length - 1
267+
currentQuestionIndex !== questions.length - 1 ||
268+
whatsappStatus !== "valid"
156269
}
157270
className="w-full max-w-xs py-3 px-6 rounded-lg bg-brand-orange text-brand-black font-semibold text-lg transition-all hover:bg-brand-orange/90 disabled:opacity-50 disabled:cursor-not-allowed"
158271
>

src/client/app/onboarding/page.js

Lines changed: 106 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import toast from "react-hot-toast"
66
import { usePostHog } from "posthog-js/react"
77
import { useRouter } from "next/navigation"
88
import {
9-
IconLoader,
10-
IconCheck,
119
IconSparkles,
1210
IconHeart,
13-
IconBrandWhatsapp
11+
IconBrandWhatsapp,
12+
IconLoader,
13+
IconCheck,
14+
IconX
1415
} from "@tabler/icons-react"
1516
import InteractiveNetworkBackground from "@components/ui/InteractiveNetworkBackground"
1617
import ProgressBar from "@components/onboarding/ProgressBar"
@@ -183,8 +184,7 @@ const questions = [
183184
},
184185
{
185186
id: "whatsapp_notifications_number",
186-
question:
187-
"Please enter your WhatsApp number with the country code.",
187+
question: "Please enter your WhatsApp number with the country code.",
188188
type: "text-input",
189189
required: true,
190190
placeholder: "+14155552671",
@@ -219,6 +219,9 @@ const OnboardingPage = () => {
219219
const router = useRouter()
220220
const chatEndRef = useRef(null)
221221
const statusChecked = useRef(false)
222+
const [whatsappStatus, setWhatsappStatus] = useState("idle") // idle, checking, valid, invalid
223+
const [whatsappError, setWhatsappError] = useState("")
224+
const debounceTimeoutRef = useRef(null)
222225

223226
const [locationState, setLocationState] = useState({
224227
loading: false,
@@ -251,8 +254,56 @@ const OnboardingPage = () => {
251254
[answers]
252255
)
253256

257+
const verifyWhatsappNumber = async (number) => {
258+
if (!/^\+[1-9]\d{1,14}$/.test(number.trim())) {
259+
setWhatsappStatus("invalid")
260+
setWhatsappError(
261+
"Please use E.164 format with country code (e.g., +14155552671)."
262+
)
263+
return
264+
}
265+
setWhatsappStatus("checking")
266+
setWhatsappError("")
267+
try {
268+
const response = await fetch("/api/testing/whatsapp/verify", {
269+
method: "POST",
270+
headers: { "Content-Type": "application/json" },
271+
body: JSON.stringify({ phone_number: number })
272+
})
273+
const result = await response.json()
274+
if (!response.ok) {
275+
throw new Error(result.detail || "Verification request failed.")
276+
}
277+
if (result.numberExists) {
278+
setWhatsappStatus("valid")
279+
setWhatsappError("")
280+
} else {
281+
setWhatsappStatus("invalid")
282+
setWhatsappError(
283+
"This number does not appear to be on WhatsApp."
284+
)
285+
}
286+
} catch (error) {
287+
setWhatsappStatus("invalid")
288+
setWhatsappError(error.message)
289+
}
290+
}
291+
254292
const handleAnswer = (questionId, answer) => {
255293
setAnswers((prev) => ({ ...prev, [questionId]: answer }))
294+
if (questionId === "whatsapp_notifications_number") {
295+
setWhatsappStatus("idle")
296+
if (debounceTimeoutRef.current) {
297+
clearTimeout(debounceTimeoutRef.current)
298+
}
299+
if (answer.trim()) {
300+
debounceTimeoutRef.current = setTimeout(() => {
301+
verifyWhatsappNumber(answer)
302+
}, 800)
303+
} else {
304+
setWhatsappError("")
305+
}
306+
}
256307
}
257308

258309
const handleMultiChoice = (questionId, option) => {
@@ -357,8 +408,15 @@ const OnboardingPage = () => {
357408
if (answer === undefined || answer === null || answer === "")
358409
return false
359410
if (Array.isArray(answer) && answer.length === 0) return false
411+
// NEW check for whatsapp
412+
if (
413+
currentQuestion.id === "whatsapp_notifications_number" &&
414+
whatsappStatus !== "valid"
415+
) {
416+
return false
417+
}
360418
return true
361-
}, [answers, currentQuestionIndex, stage, questions.length])
419+
}, [answers, currentQuestionIndex, stage, questions.length, whatsappStatus])
362420

363421
const handleSubmit = async () => {
364422
setStage("submitting")
@@ -418,7 +476,7 @@ const OnboardingPage = () => {
418476
referral_source: "direct" // Placeholder, can be populated from URL params
419477
})
420478
posthog?.capture("onboarding_completed")
421-
router.push("/chat?show_demo=true")
479+
window.location.href = "/chat?show_demo=true"
422480
} catch (error) {
423481
toast.error(`Error: ${error.message}`)
424482
setStage("questions") // Go back to questions on error
@@ -765,17 +823,47 @@ const OnboardingPage = () => {
765823
switch (currentQuestion.type) {
766824
case "text-input":
767825
return (
768-
<input
769-
type="text"
770-
value={answers[currentQuestion.id] || ""}
771-
onChange={(e) =>
772-
handleAnswer(currentQuestion.id, e.target.value)
773-
}
774-
placeholder={currentQuestion.placeholder}
775-
required={currentQuestion.required}
776-
autoFocus
777-
className="w-full px-4 py-2 bg-transparent text-brand-white placeholder:text-neutral-500 focus:ring-0 border-none p-0"
778-
/>
826+
<div className="relative w-full">
827+
<input
828+
type="text"
829+
value={answers[currentQuestion.id] || ""}
830+
onChange={(e) =>
831+
handleAnswer(currentQuestion.id, e.target.value)
832+
}
833+
placeholder={currentQuestion.placeholder}
834+
required={currentQuestion.required}
835+
autoFocus
836+
className="w-full px-4 py-2 bg-transparent text-brand-white placeholder:text-neutral-500 focus:ring-0 border-none p-0"
837+
/>
838+
{currentQuestion.id ===
839+
"whatsapp_notifications_number" && (
840+
<div className="absolute right-0 top-1/2 -translate-y-1/2">
841+
{whatsappStatus === "checking" && (
842+
<IconLoader
843+
size={18}
844+
className="animate-spin text-neutral-400"
845+
/>
846+
)}
847+
{whatsappStatus === "valid" && (
848+
<IconCheck
849+
size={18}
850+
className="text-green-500"
851+
/>
852+
)}
853+
{whatsappStatus === "invalid" && (
854+
<IconX size={18} className="text-red-500" />
855+
)}
856+
</div>
857+
)}
858+
{currentQuestion.id ===
859+
"whatsapp_notifications_number" &&
860+
whatsappStatus === "invalid" &&
861+
whatsappError && (
862+
<p className="text-red-500 text-xs mt-2">
863+
{whatsappError}
864+
</p>
865+
)}
866+
</div>
779867
)
780868
case "select":
781869
return (

0 commit comments

Comments
 (0)