mirror of
https://github.com/khoj-ai/khoj.git
synced 2024-11-23 15:38:55 +01:00
Use an intl phone input number field and fix the whole verification flow
- There were some state mismatches in configuring a whatsapp number. This commit fixes those issues and uses an external library for phone number validation
This commit is contained in:
parent
60870a7a3e
commit
84dd1b57fe
4 changed files with 56 additions and 26 deletions
|
@ -1,6 +1,7 @@
|
|||
'use client'
|
||||
|
||||
import styles from "./settings.module.css";
|
||||
import "intl-tel-input/styles";
|
||||
|
||||
import { Suspense, useEffect, useState } from "react";
|
||||
import { useToast } from "@/components/ui/use-toast"
|
||||
|
@ -74,6 +75,8 @@ import NavMenu from "../components/navMenu/navMenu";
|
|||
import SidePanel from "../components/sidePanel/chatHistorySidePanel";
|
||||
import Loading from "../components/loading/loading";
|
||||
|
||||
import IntlTelInput from 'intl-tel-input/react';
|
||||
|
||||
|
||||
const ManageFilesModal: React.FC<{ onClose: () => void }> = ({ onClose }) => {
|
||||
const [syncedFiles, setSyncedFiles] = useState<string[]>([]);
|
||||
|
@ -349,7 +352,7 @@ export default function SettingsView() {
|
|||
const [userConfig, setUserConfig] = useState<UserConfig | null>(null);
|
||||
const [name, setName] = useState<string | undefined>(undefined);
|
||||
const [notionToken, setNotionToken] = useState<string | null>(null);
|
||||
const [number, setNumber] = useState<string | undefined>(undefined);
|
||||
const [phoneNumber, setPhoneNumber] = useState<string | undefined>(undefined);
|
||||
const [otp, setOTP] = useState("");
|
||||
const [numberValidationState, setNumberValidationState] = useState<PhoneNumberValidationState>(PhoneNumberValidationState.Verified);
|
||||
const [isManageFilesModalOpen, setIsManageFilesModalOpen] = useState(false);
|
||||
|
@ -358,7 +361,7 @@ export default function SettingsView() {
|
|||
|
||||
useEffect(() => {
|
||||
setUserConfig(initialUserConfig);
|
||||
setNumber(initialUserConfig?.phone_number);
|
||||
setPhoneNumber(initialUserConfig?.phone_number);
|
||||
setNumberValidationState(
|
||||
initialUserConfig?.is_phone_number_verified
|
||||
? PhoneNumberValidationState.Verified
|
||||
|
@ -379,7 +382,7 @@ export default function SettingsView() {
|
|||
|
||||
const sendOTP = async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/phone?phone_number=${number}`, {
|
||||
const response = await fetch(`/api/phone?phone_number=${phoneNumber}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
@ -942,15 +945,25 @@ export default function SettingsView() {
|
|||
Connect your number to chat with Khoj on WhatsApp. Learn more about the integration <a href="https://docs.khoj.dev/clients/whatsapp">here</a>.
|
||||
</p>
|
||||
<div>
|
||||
<IntlTelInput
|
||||
initialValue={phoneNumber || ""}
|
||||
onChangeNumber={setPhoneNumber}
|
||||
disabled={numberValidationState === PhoneNumberValidationState.Verified || numberValidationState === PhoneNumberValidationState.VerifyOTP}
|
||||
initOptions={{
|
||||
separateDialCode: true,
|
||||
initialCountry: "us",
|
||||
utilsScript: "https://assets.khoj.dev/intl-tel-input%4023.8.0_build_js_utils.js",
|
||||
}}
|
||||
/>
|
||||
{numberValidationState === PhoneNumberValidationState.VerifyOTP && (
|
||||
<>
|
||||
<p>{`Enter the OTP sent to your WhatsApp number: ${number}`}</p>
|
||||
<p>{`Enter the OTP sent to your number: ${phoneNumber}`}</p>
|
||||
<InputOTP
|
||||
autoFocus={true}
|
||||
maxLength={6}
|
||||
value={otp || ""}
|
||||
onChange={setOTP}
|
||||
onComplete={() => setNumberValidationState(PhoneNumberValidationState.Verified)}
|
||||
onComplete={() => setNumberValidationState(PhoneNumberValidationState.VerifyOTP)}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
|
@ -962,16 +975,6 @@ export default function SettingsView() {
|
|||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</>
|
||||
) || (
|
||||
<>
|
||||
<Input
|
||||
type="tel"
|
||||
onChange={(e) => setNumber(e.target.value)}
|
||||
value={number || ""}
|
||||
placeholder="Enter phone number (e.g. +911234567890)"
|
||||
className="w-full border border-gray-300 rounded-lg px-4 py-6"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
|
@ -986,14 +989,14 @@ export default function SettingsView() {
|
|||
) || (
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={!number || number === userConfig.phone_number || !isValidPhoneNumber(number)}
|
||||
disabled={!phoneNumber || (phoneNumber === userConfig.phone_number && numberValidationState === PhoneNumberValidationState.Verified) || !isValidPhoneNumber(phoneNumber)}
|
||||
onClick={sendOTP}
|
||||
>
|
||||
{!userConfig.phone_number
|
||||
? (<><Plugs className="inline mr-2" />Setup Whatsapp</>)
|
||||
: !number || number === userConfig.phone_number || !isValidPhoneNumber(number)
|
||||
: !phoneNumber || (phoneNumber === userConfig.phone_number && numberValidationState === PhoneNumberValidationState.Verified) || !isValidPhoneNumber(phoneNumber)
|
||||
? (<><PlugsConnected className="inline mr-2 text-green-400" />Switch Number</>)
|
||||
: (<>Send OTP to Whatsapp <ArrowRight className="inline ml-2" weight="bold"/></>)
|
||||
: (<>Send OTP <ArrowRight className="inline ml-2" weight="bold"/></>)
|
||||
}
|
||||
</Button>
|
||||
)}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
"eslint": "^8",
|
||||
"eslint-config-next": "14.2.3",
|
||||
"input-otp": "^1.2.4",
|
||||
"intl-tel-input": "^23.8.0",
|
||||
"katex": "^0.16.10",
|
||||
"libphonenumber-js": "^1.11.4",
|
||||
"lucide-react": "^0.397.0",
|
||||
|
@ -64,7 +65,13 @@
|
|||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/intl-tel-input": "^18.1.4",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/markdown-it": "^14.1.1",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.2.3",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
|
@ -73,15 +80,10 @@
|
|||
"lint-staged": "^15.2.7",
|
||||
"nodemon": "^3.1.3",
|
||||
"prettier": "3.3.3",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwindcss": "^3.4.6",
|
||||
"typescript": "^5",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/markdown-it": "^14.1.1",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18"
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"prettier": {
|
||||
"tabWidth": 4
|
||||
|
|
|
@ -1295,6 +1295,20 @@
|
|||
dependencies:
|
||||
"@types/trusted-types" "*"
|
||||
|
||||
"@types/intl-tel-input@^18.1.4":
|
||||
version "18.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/intl-tel-input/-/intl-tel-input-18.1.4.tgz#0eb5211a7490f8a8d7aa940ee594a85138d514c9"
|
||||
integrity sha512-UT4dQ4dQA0w0uxU161aPROEEwMOQj5Qedm3ImdDNfkxi3JXzBX2FhcUS72pTyZ8ypaUr2e9ruJBiK6bwSGfbew==
|
||||
dependencies:
|
||||
"@types/jquery" "*"
|
||||
|
||||
"@types/jquery@*":
|
||||
version "3.5.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.30.tgz#888d584cbf844d3df56834b69925085038fd80f7"
|
||||
integrity sha512-nbWKkkyb919DOUxjmRVk8vwtDb0/k8FKncmUKFi+NY+QXqWltooxTrswvz4LspQwxvLdvzBN1TImr6cw3aQx2A==
|
||||
dependencies:
|
||||
"@types/sizzle" "*"
|
||||
|
||||
"@types/json5@^0.0.29":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
|
@ -1350,6 +1364,11 @@
|
|||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/sizzle@*":
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.8.tgz#518609aefb797da19bf222feb199e8f653ff7627"
|
||||
integrity sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==
|
||||
|
||||
"@types/trusted-types@*":
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11"
|
||||
|
@ -2982,6 +3001,11 @@ internal-slot@^1.0.4, internal-slot@^1.0.7:
|
|||
hasown "^2.0.0"
|
||||
side-channel "^1.0.4"
|
||||
|
||||
intl-tel-input@^23.8.0:
|
||||
version "23.8.0"
|
||||
resolved "https://registry.yarnpkg.com/intl-tel-input/-/intl-tel-input-23.8.0.tgz#37bec095605516aa72529b3da11335b253b65b2f"
|
||||
integrity sha512-lx8Sz5LfVyIXyjWbfjno89o4qHfIuWulctGaWbP2RKKnHvagdt9gdibCsv9uEH7izb/yjB6Nst0sRo988/lhpw==
|
||||
|
||||
invariant@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
|
@ -4442,6 +4466,7 @@ string-argv@~0.3.2:
|
|||
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
|
||||
name string-width-cjs
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
|
|
|
@ -1298,7 +1298,7 @@ def get_user_config(user: KhojUser, request: Request, is_detailed: bool = False)
|
|||
"user_photo": user_picture,
|
||||
"is_active": is_active,
|
||||
"given_name": given_name,
|
||||
"phone_number": user.phone_number,
|
||||
"phone_number": str(user.phone_number),
|
||||
"is_phone_number_verified": user.verified_phone_number,
|
||||
# user content settings
|
||||
"enabled_content_source": enabled_content_sources,
|
||||
|
|
Loading…
Reference in a new issue