@mezo-org/passport 0.15.1-dev.7 → 0.16.0-dev.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/src/api/auth.d.ts +9 -0
- package/dist/src/api/auth.d.ts.map +1 -1
- package/dist/src/api/auth.js +7 -0
- package/dist/src/api/auth.js.map +1 -1
- package/dist/src/assets/DefaultAvatar.d.ts +5 -0
- package/dist/src/assets/DefaultAvatar.d.ts.map +1 -0
- package/dist/src/assets/DefaultAvatar.js +21 -0
- package/dist/src/assets/DefaultAvatar.js.map +1 -0
- package/dist/src/assets/EditIcon.d.ts +5 -0
- package/dist/src/assets/EditIcon.d.ts.map +1 -0
- package/dist/src/assets/EditIcon.js +10 -0
- package/dist/src/assets/EditIcon.js.map +1 -0
- package/dist/src/components/Dropdown/ConnectedTrigger.d.ts +8 -0
- package/dist/src/components/Dropdown/ConnectedTrigger.d.ts.map +1 -0
- package/dist/src/components/Dropdown/ConnectedTrigger.js +39 -0
- package/dist/src/components/Dropdown/ConnectedTrigger.js.map +1 -0
- package/dist/src/components/Dropdown/Content.d.ts +8 -0
- package/dist/src/components/Dropdown/Content.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Content.js +29 -0
- package/dist/src/components/Dropdown/Content.js.map +1 -0
- package/dist/src/components/Dropdown/DisconnectedTrigger.d.ts +7 -0
- package/dist/src/components/Dropdown/DisconnectedTrigger.d.ts.map +1 -0
- package/dist/src/components/Dropdown/DisconnectedTrigger.js +13 -0
- package/dist/src/components/Dropdown/DisconnectedTrigger.js.map +1 -0
- package/dist/src/components/Dropdown/Dropdown.d.ts +23 -0
- package/dist/src/components/Dropdown/Dropdown.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Dropdown.js +45 -0
- package/dist/src/components/Dropdown/Dropdown.js.map +1 -0
- package/dist/src/components/Dropdown/ListingItem.d.ts +14 -0
- package/dist/src/components/Dropdown/ListingItem.d.ts.map +1 -0
- package/dist/src/components/Dropdown/ListingItem.js +42 -0
- package/dist/src/components/Dropdown/ListingItem.js.map +1 -0
- package/dist/src/components/Dropdown/NestedViewLayout.d.ts +8 -0
- package/dist/src/components/Dropdown/NestedViewLayout.d.ts.map +1 -0
- package/dist/src/components/Dropdown/NestedViewLayout.js +33 -0
- package/dist/src/components/Dropdown/NestedViewLayout.js.map +1 -0
- package/dist/src/components/Dropdown/Receive/Receive.d.ts +4 -0
- package/dist/src/components/Dropdown/Receive/Receive.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Receive/Receive.js +64 -0
- package/dist/src/components/Dropdown/Receive/Receive.js.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountAddressActions.d.ts +4 -0
- package/dist/src/components/Dropdown/Root/AccountAddressActions.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountAddressActions.js +49 -0
- package/dist/src/components/Dropdown/Root/AccountAddressActions.js.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountBalance.d.ts +6 -0
- package/dist/src/components/Dropdown/Root/AccountBalance.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountBalance.js +32 -0
- package/dist/src/components/Dropdown/Root/AccountBalance.js.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountBtcListing.d.ts +6 -0
- package/dist/src/components/Dropdown/Root/AccountBtcListing.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountBtcListing.js +28 -0
- package/dist/src/components/Dropdown/Root/AccountBtcListing.js.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountError.d.ts +8 -0
- package/dist/src/components/Dropdown/Root/AccountError.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountError.js +17 -0
- package/dist/src/components/Dropdown/Root/AccountError.js.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountMusdListing.d.ts +4 -0
- package/dist/src/components/Dropdown/Root/AccountMusdListing.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountMusdListing.js +21 -0
- package/dist/src/components/Dropdown/Root/AccountMusdListing.js.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountOtherAssets.d.ts +8 -0
- package/dist/src/components/Dropdown/Root/AccountOtherAssets.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/AccountOtherAssets.js +43 -0
- package/dist/src/components/Dropdown/Root/AccountOtherAssets.js.map +1 -0
- package/dist/src/components/Dropdown/Root/Root.d.ts +8 -0
- package/dist/src/components/Dropdown/Root/Root.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/Root.js +49 -0
- package/dist/src/components/Dropdown/Root/Root.js.map +1 -0
- package/dist/src/components/Dropdown/Root/WalletAddress.d.ts +4 -0
- package/dist/src/components/Dropdown/Root/WalletAddress.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/WalletAddress.js +66 -0
- package/dist/src/components/Dropdown/Root/WalletAddress.js.map +1 -0
- package/dist/src/components/Dropdown/Root/WelcomeBlock.d.ts +6 -0
- package/dist/src/components/Dropdown/Root/WelcomeBlock.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Root/WelcomeBlock.js +88 -0
- package/dist/src/components/Dropdown/Root/WelcomeBlock.js.map +1 -0
- package/dist/src/components/Dropdown/Settings/InlineEditField.d.ts +12 -0
- package/dist/src/components/Dropdown/Settings/InlineEditField.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Settings/InlineEditField.js +95 -0
- package/dist/src/components/Dropdown/Settings/InlineEditField.js.map +1 -0
- package/dist/src/components/Dropdown/Settings/Settings.d.ts +4 -0
- package/dist/src/components/Dropdown/Settings/Settings.d.ts.map +1 -0
- package/dist/src/components/Dropdown/Settings/Settings.js +36 -0
- package/dist/src/components/Dropdown/Settings/Settings.js.map +1 -0
- package/dist/src/components/Dropdown/SlotNumber.d.ts +19 -0
- package/dist/src/components/Dropdown/SlotNumber.d.ts.map +1 -0
- package/dist/src/components/Dropdown/SlotNumber.js +67 -0
- package/dist/src/components/Dropdown/SlotNumber.js.map +1 -0
- package/dist/src/components/Dropdown/TestnetTopBanner.d.ts +3 -0
- package/dist/src/components/Dropdown/TestnetTopBanner.d.ts.map +1 -0
- package/dist/src/components/Dropdown/TestnetTopBanner.js +14 -0
- package/dist/src/components/Dropdown/TestnetTopBanner.js.map +1 -0
- package/dist/src/components/Dropdown/index.d.ts +3 -0
- package/dist/src/components/Dropdown/index.d.ts.map +1 -0
- package/dist/src/components/Dropdown/index.js +2 -0
- package/dist/src/components/Dropdown/index.js.map +1 -0
- package/dist/src/components/index.d.ts +2 -0
- package/dist/src/components/index.d.ts.map +1 -0
- package/dist/src/components/index.js +2 -0
- package/dist/src/components/index.js.map +1 -0
- package/dist/src/hooks/index.d.ts +1 -0
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/hooks/index.js +1 -0
- package/dist/src/hooks/index.js.map +1 -1
- package/dist/src/hooks/useAcceptDocuments.d.ts +18 -0
- package/dist/src/hooks/useAcceptDocuments.d.ts.map +1 -1
- package/dist/src/hooks/useAuthenticateWithWallet.d.ts +11 -11
- package/dist/src/hooks/useCreateAccount.d.ts +18 -0
- package/dist/src/hooks/useCreateAccount.d.ts.map +1 -1
- package/dist/src/hooks/useSignInWithWallet.d.ts +11 -11
- package/dist/src/hooks/useSignUpWithWallet.d.ts +11 -11
- package/dist/src/hooks/useUpdateMezoId.d.ts +18 -0
- package/dist/src/hooks/useUpdateMezoId.d.ts.map +1 -1
- package/dist/src/hooks/useUpdateUserProfile.d.ts +171 -0
- package/dist/src/hooks/useUpdateUserProfile.d.ts.map +1 -0
- package/dist/src/hooks/useUpdateUserProfile.js +19 -0
- package/dist/src/hooks/useUpdateUserProfile.js.map +1 -0
- package/dist/src/hooks/useWalletAccount.d.ts +2 -5
- package/dist/src/hooks/useWalletAccount.d.ts.map +1 -1
- package/dist/src/hooks/useWalletAccount.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/stores/dropdownStore.d.ts +2 -1
- package/dist/src/stores/dropdownStore.d.ts.map +1 -1
- package/dist/src/stores/dropdownStore.js +1 -0
- package/dist/src/stores/dropdownStore.js.map +1 -1
- package/dist/src/utils/validation.d.ts +13 -0
- package/dist/src/utils/validation.d.ts.map +1 -0
- package/dist/src/utils/validation.js +34 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/dist/src/utils/validation.test.d.ts +2 -0
- package/dist/src/utils/validation.test.d.ts.map +1 -0
- package/dist/src/utils/validation.test.js +63 -0
- package/dist/src/utils/validation.test.js.map +1 -0
- package/package.json +10 -7
- package/src/api/auth.ts +22 -0
- package/src/assets/DefaultAvatar.tsx +74 -0
- package/src/assets/EditIcon.tsx +33 -0
- package/src/components/Dropdown/ConnectedTrigger.tsx +76 -0
- package/src/components/Dropdown/Content.tsx +56 -0
- package/src/components/Dropdown/DisconnectedTrigger.tsx +36 -0
- package/src/components/Dropdown/Dropdown.tsx +100 -0
- package/src/components/Dropdown/ListingItem.tsx +176 -0
- package/src/components/Dropdown/NestedViewLayout.tsx +88 -0
- package/src/components/Dropdown/README.md +41 -0
- package/src/components/Dropdown/Receive/Receive.tsx +144 -0
- package/src/components/Dropdown/Root/AccountAddressActions.tsx +99 -0
- package/src/components/Dropdown/Root/AccountBalance.tsx +69 -0
- package/src/components/Dropdown/Root/AccountBtcListing.tsx +53 -0
- package/src/components/Dropdown/Root/AccountError.tsx +34 -0
- package/src/components/Dropdown/Root/AccountMusdListing.tsx +45 -0
- package/src/components/Dropdown/Root/AccountOtherAssets.tsx +85 -0
- package/src/components/Dropdown/Root/Root.tsx +104 -0
- package/src/components/Dropdown/Root/WalletAddress.tsx +123 -0
- package/src/components/Dropdown/Root/WelcomeBlock.tsx +173 -0
- package/src/components/Dropdown/Settings/InlineEditField.tsx +212 -0
- package/src/components/Dropdown/Settings/Settings.tsx +87 -0
- package/src/components/Dropdown/SlotNumber.tsx +131 -0
- package/src/components/Dropdown/TestnetTopBanner.tsx +32 -0
- package/src/components/Dropdown/index.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useUpdateUserProfile.ts +34 -0
- package/src/hooks/useWalletAccount.ts +2 -8
- package/src/index.ts +1 -0
- package/src/stores/dropdownStore.ts +1 -0
- package/src/utils/validation.test.ts +97 -0
- package/src/utils/validation.ts +35 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/* eslint-disable react/no-array-index-key */
|
|
2
|
+
import React, { useMemo } from "react"
|
|
3
|
+
import { AnimatePresence, motion } from "motion/react"
|
|
4
|
+
import { Block, useStyletron } from "@mezo-org/mezo-clay"
|
|
5
|
+
|
|
6
|
+
type SlotNumberProps = {
|
|
7
|
+
className?: string
|
|
8
|
+
children: number
|
|
9
|
+
formatFunction?: (value: number) => string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type SlotNumberDigitProps = {
|
|
13
|
+
className?: string
|
|
14
|
+
children: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function SlotNumberDigit(props: SlotNumberDigitProps) {
|
|
18
|
+
const { children: value, ...restProps } = props
|
|
19
|
+
|
|
20
|
+
const [css] = useStyletron()
|
|
21
|
+
|
|
22
|
+
const digits = [...Array(10).keys()]
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<AnimatePresence initial={false}>
|
|
26
|
+
<motion.div
|
|
27
|
+
initial={{
|
|
28
|
+
y: "100%",
|
|
29
|
+
}}
|
|
30
|
+
animate={{
|
|
31
|
+
y: "0%",
|
|
32
|
+
}}
|
|
33
|
+
layout="position"
|
|
34
|
+
className={css({
|
|
35
|
+
position: "relative",
|
|
36
|
+
})}
|
|
37
|
+
{...restProps}
|
|
38
|
+
>
|
|
39
|
+
<Block
|
|
40
|
+
overrides={{
|
|
41
|
+
Block: {
|
|
42
|
+
style: {
|
|
43
|
+
visibility: "hidden",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
{value}
|
|
49
|
+
</Block>
|
|
50
|
+
|
|
51
|
+
<motion.div
|
|
52
|
+
className={css({
|
|
53
|
+
display: "flex",
|
|
54
|
+
flexDirection: "column",
|
|
55
|
+
position: "absolute",
|
|
56
|
+
inset: 0,
|
|
57
|
+
height: "fit-content",
|
|
58
|
+
})}
|
|
59
|
+
initial={false}
|
|
60
|
+
animate={{ y: `${(value / 10) * -100}%` }}
|
|
61
|
+
transition={{
|
|
62
|
+
type: "spring",
|
|
63
|
+
damping: 16,
|
|
64
|
+
stiffness: 220,
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
{digits.map((digit) => (
|
|
68
|
+
<Block as="span" key={digit}>
|
|
69
|
+
{digit}
|
|
70
|
+
</Block>
|
|
71
|
+
))}
|
|
72
|
+
</motion.div>
|
|
73
|
+
</motion.div>
|
|
74
|
+
</AnimatePresence>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* SlotNumber component displays a number with animated digits.
|
|
80
|
+
*
|
|
81
|
+
* @typedef {object} SlotNumberProps
|
|
82
|
+
* @property {number} children - The number to display.
|
|
83
|
+
* @property {function} [formatFunction] - Optional function to format the number.
|
|
84
|
+
* @property {BlockProps} [restProps] - Additional properties for the Block component.
|
|
85
|
+
* @see https://pyszkowski.dev/writings/slot-number
|
|
86
|
+
* @returns {JSX.Element} The rendered SlotNumber component.
|
|
87
|
+
*/
|
|
88
|
+
function SlotNumber(props: SlotNumberProps) {
|
|
89
|
+
const { children: value, formatFunction, ...restProps } = props
|
|
90
|
+
|
|
91
|
+
const [css] = useStyletron()
|
|
92
|
+
|
|
93
|
+
const characters = useMemo(() => {
|
|
94
|
+
const formattedValue = formatFunction
|
|
95
|
+
? formatFunction(value)
|
|
96
|
+
: value.toString()
|
|
97
|
+
|
|
98
|
+
return formattedValue
|
|
99
|
+
.split("")
|
|
100
|
+
.map((character) => (/^[0-9]$/.test(character) ? +character : character))
|
|
101
|
+
.reverse()
|
|
102
|
+
}, [formatFunction, value])
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<motion.div
|
|
106
|
+
layout
|
|
107
|
+
className={css({
|
|
108
|
+
display: "inline-flex",
|
|
109
|
+
flexDirection: "row-reverse",
|
|
110
|
+
justifyContent: "flex-end",
|
|
111
|
+
overflow: "hidden",
|
|
112
|
+
userSelect: "none",
|
|
113
|
+
})}
|
|
114
|
+
{...restProps}
|
|
115
|
+
>
|
|
116
|
+
{characters.map((character, index) =>
|
|
117
|
+
typeof character === "number" ? (
|
|
118
|
+
<SlotNumberDigit key={`slot-number-character-${index}`}>
|
|
119
|
+
{character}
|
|
120
|
+
</SlotNumberDigit>
|
|
121
|
+
) : (
|
|
122
|
+
<motion.span layout key={`slot-number-character-${index}`}>
|
|
123
|
+
{character}
|
|
124
|
+
</motion.span>
|
|
125
|
+
),
|
|
126
|
+
)}
|
|
127
|
+
</motion.div>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default SlotNumber
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import {
|
|
3
|
+
Block,
|
|
4
|
+
InfoCircle,
|
|
5
|
+
LabelSmall,
|
|
6
|
+
useStyletron,
|
|
7
|
+
} from "@mezo-org/mezo-clay"
|
|
8
|
+
import { usePassportContext } from "../../hooks/usePassportContext"
|
|
9
|
+
|
|
10
|
+
export default function TestnetTopBanner() {
|
|
11
|
+
const [, theme] = useStyletron()
|
|
12
|
+
|
|
13
|
+
const { environment } = usePassportContext()
|
|
14
|
+
|
|
15
|
+
if (environment !== "testnet") {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Block
|
|
21
|
+
display="flex"
|
|
22
|
+
alignItems="center"
|
|
23
|
+
padding={`${theme.sizing.scale700} ${theme.sizing.scale600}`}
|
|
24
|
+
backgroundColor={theme.colors.warning}
|
|
25
|
+
>
|
|
26
|
+
<InfoCircle size={theme.sizing.scale550} />
|
|
27
|
+
<LabelSmall marginLeft={theme.sizing.scale500}>
|
|
28
|
+
You are using testnet funds.
|
|
29
|
+
</LabelSmall>
|
|
30
|
+
</Block>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Dropdown, DropdownProps } from "./Dropdown"
|
package/src/hooks/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export {
|
|
|
25
25
|
useResetTokensBalances,
|
|
26
26
|
} from "./useTokensBalances"
|
|
27
27
|
export * from "./useUpdateMezoId"
|
|
28
|
+
export * from "./useUpdateUserProfile"
|
|
28
29
|
export * from "./useValidateMezoId"
|
|
29
30
|
export * from "./useRewardsApiClient"
|
|
30
31
|
export * from "./useWalletAccount"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useQueryClient,
|
|
3
|
+
useMutation,
|
|
4
|
+
MutationOptions,
|
|
5
|
+
DefaultError,
|
|
6
|
+
} from "@tanstack/react-query"
|
|
7
|
+
import { useAuthApiClient } from "./useAuthApiClient"
|
|
8
|
+
import { QUERY_KEYS } from "./constants"
|
|
9
|
+
import type { UpdateAccountRequest, UpdateAccountResponse } from "../api"
|
|
10
|
+
|
|
11
|
+
export function useUpdateUserProfile(
|
|
12
|
+
mutationOptions: Omit<
|
|
13
|
+
MutationOptions<UpdateAccountResponse, DefaultError, UpdateAccountRequest>,
|
|
14
|
+
"mutationFn" | "mutationKey"
|
|
15
|
+
> = {},
|
|
16
|
+
) {
|
|
17
|
+
const queryClient = useQueryClient()
|
|
18
|
+
const authApiClient = useAuthApiClient()
|
|
19
|
+
|
|
20
|
+
const { onSuccess: customOnSuccess, ...restMutationOptions } = mutationOptions
|
|
21
|
+
|
|
22
|
+
const { mutate, mutateAsync, ...rest } = useMutation({
|
|
23
|
+
mutationFn: (updates: UpdateAccountRequest) =>
|
|
24
|
+
authApiClient.updateAccount(updates),
|
|
25
|
+
onSuccess: (data, variables, context) => {
|
|
26
|
+
queryClient.resetQueries({ queryKey: [QUERY_KEYS.ACCOUNT] })
|
|
27
|
+
|
|
28
|
+
if (customOnSuccess) customOnSuccess(data, variables, context)
|
|
29
|
+
},
|
|
30
|
+
...restMutationOptions,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
return { updateProfile: mutate, updateProfileAsync: mutateAsync, ...rest }
|
|
34
|
+
}
|
|
@@ -2,18 +2,12 @@ import { OrangeKitConnector } from "@mezo-org/orangekit"
|
|
|
2
2
|
import { useQuery } from "@tanstack/react-query"
|
|
3
3
|
import { useMemo } from "react"
|
|
4
4
|
import { Address } from "viem"
|
|
5
|
-
import {
|
|
5
|
+
import { useAccount, UseAccountReturnType } from "wagmi"
|
|
6
6
|
|
|
7
|
-
type UseWalletAccountReturn = Omit<
|
|
8
|
-
UseAccountReturnType,
|
|
9
|
-
"isConnected" | "address" | "connector" | "chainId"
|
|
10
|
-
> & {
|
|
7
|
+
type UseWalletAccountReturn = Omit<UseAccountReturnType, "address"> & {
|
|
11
8
|
accountAddress?: Address
|
|
12
9
|
walletAddress?: string
|
|
13
|
-
isConnected: boolean
|
|
14
10
|
networkFamily: "bitcoin" | "evm"
|
|
15
|
-
connector?: Connector
|
|
16
|
-
chainId?: number
|
|
17
11
|
}
|
|
18
12
|
|
|
19
13
|
export function useWalletAccount(): UseWalletAccountReturn {
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { validateEmail, validateTelegram } from "./validation"
|
|
2
|
+
|
|
3
|
+
describe("validateEmail", () => {
|
|
4
|
+
it("returns null for empty string", () => {
|
|
5
|
+
expect(validateEmail("")).toBeNull()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it("returns null for valid email", () => {
|
|
9
|
+
expect(validateEmail("user@example.com")).toBeNull()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it("returns null for valid email with subdomain", () => {
|
|
13
|
+
expect(validateEmail("user@mail.example.com")).toBeNull()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it("returns null for valid email with plus addressing", () => {
|
|
17
|
+
expect(validateEmail("user+tag@example.com")).toBeNull()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("returns error for email without @", () => {
|
|
21
|
+
expect(validateEmail("userexample.com")).toBe(
|
|
22
|
+
"Please enter a valid email address",
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it("returns error for email without domain", () => {
|
|
27
|
+
expect(validateEmail("user@")).toBe("Please enter a valid email address")
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it("returns error for email without TLD", () => {
|
|
31
|
+
expect(validateEmail("user@example")).toBe(
|
|
32
|
+
"Please enter a valid email address",
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("returns error for email with spaces", () => {
|
|
37
|
+
expect(validateEmail("user @example.com")).toBe(
|
|
38
|
+
"Please enter a valid email address",
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
describe("validateTelegram", () => {
|
|
44
|
+
it("returns null for empty string", () => {
|
|
45
|
+
expect(validateTelegram("")).toBeNull()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it("returns null for valid handle without @", () => {
|
|
49
|
+
expect(validateTelegram("username")).toBeNull()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it("returns null for valid handle with @", () => {
|
|
53
|
+
expect(validateTelegram("@username")).toBeNull()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it("returns null for handle with numbers", () => {
|
|
57
|
+
expect(validateTelegram("user123")).toBeNull()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("returns null for handle with underscores", () => {
|
|
61
|
+
expect(validateTelegram("user_name")).toBeNull()
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("returns null for exactly 5 character handle", () => {
|
|
65
|
+
expect(validateTelegram("abcde")).toBeNull()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it("returns error for handle shorter than 5 characters", () => {
|
|
69
|
+
expect(validateTelegram("abcd")).toBe(
|
|
70
|
+
"Telegram handle must be at least 5 characters",
|
|
71
|
+
)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it("returns error for handle with @ that is too short", () => {
|
|
75
|
+
expect(validateTelegram("@abcd")).toBe(
|
|
76
|
+
"Telegram handle must be at least 5 characters",
|
|
77
|
+
)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it("returns error for handle with special characters", () => {
|
|
81
|
+
expect(validateTelegram("user-name")).toBe(
|
|
82
|
+
"Telegram handle can only contain letters, numbers, and underscores",
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it("returns error for handle with spaces", () => {
|
|
87
|
+
expect(validateTelegram("user name")).toBe(
|
|
88
|
+
"Telegram handle can only contain letters, numbers, and underscores",
|
|
89
|
+
)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it("returns error for handle with dots", () => {
|
|
93
|
+
expect(validateTelegram("user.name")).toBe(
|
|
94
|
+
"Telegram handle can only contain letters, numbers, and underscores",
|
|
95
|
+
)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validates an email address.
|
|
5
|
+
* @param value - The email address to validate
|
|
6
|
+
* @returns An error message if invalid, null if valid or empty
|
|
7
|
+
*/
|
|
8
|
+
export function validateEmail(value: string): string | null {
|
|
9
|
+
if (!value) {
|
|
10
|
+
return null
|
|
11
|
+
}
|
|
12
|
+
if (!EMAIL_REGEX.test(value)) {
|
|
13
|
+
return "Please enter a valid email address"
|
|
14
|
+
}
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validates a Telegram handle.
|
|
20
|
+
* @param value - The Telegram handle to validate (with or without @ prefix)
|
|
21
|
+
* @returns An error message if invalid, null if valid or empty
|
|
22
|
+
*/
|
|
23
|
+
export function validateTelegram(value: string): string | null {
|
|
24
|
+
if (!value) {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
const handle = value.startsWith("@") ? value.slice(1) : value
|
|
28
|
+
if (handle.length < 5) {
|
|
29
|
+
return "Telegram handle must be at least 5 characters"
|
|
30
|
+
}
|
|
31
|
+
if (!/^[a-zA-Z0-9_]+$/.test(handle)) {
|
|
32
|
+
return "Telegram handle can only contain letters, numbers, and underscores"
|
|
33
|
+
}
|
|
34
|
+
return null
|
|
35
|
+
}
|