@redzone/taunt-logins-ui-react 0.0.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.
Files changed (101) hide show
  1. package/.history/index_20251002141038.html +13 -0
  2. package/.history/index_20251002141344.html +13 -0
  3. package/.history/package_20251002154235.json +32 -0
  4. package/.history/package_20251002160110.json +33 -0
  5. package/.history/package_20251002161109.json +33 -0
  6. package/.history/package_20251002161124.json +32 -0
  7. package/.history/src/App_20251002141038.tsx +35 -0
  8. package/.history/src/App_20251002142848.tsx +15 -0
  9. package/.history/src/App_20251002152540.tsx +15 -0
  10. package/.history/src/App_20251002152831.tsx +17 -0
  11. package/.history/src/App_20251002153145.tsx +18 -0
  12. package/.history/src/App_20251002153323.tsx +25 -0
  13. package/.history/src/App_20251002153420.tsx +32 -0
  14. package/.history/src/App_20251002153429.tsx +33 -0
  15. package/.history/src/App_20251002153457.tsx +39 -0
  16. package/.history/src/App_20251002153516.tsx +39 -0
  17. package/.history/src/App_20251002153520.tsx +39 -0
  18. package/.history/src/App_20251002153546.tsx +41 -0
  19. package/.history/src/App_20251002154625.tsx +41 -0
  20. package/.history/src/App_20251002154740.tsx +47 -0
  21. package/.history/src/App_20251002154812.tsx +47 -0
  22. package/.history/src/App_20251002154841.tsx +47 -0
  23. package/.history/src/App_20251002154915.tsx +54 -0
  24. package/.history/src/App_20251002160347.tsx +54 -0
  25. package/.history/src/lib/exports_20251002160004.ts +0 -0
  26. package/.history/src/lib/exports_20251002160045.ts +3 -0
  27. package/.history/src/lib/magic_20251002142829.tsx +0 -0
  28. package/.history/src/lib/magic_20251002142848.tsx +44 -0
  29. package/.history/src/lib/magic_20251002152540.tsx +28 -0
  30. package/.history/src/lib/magic_20251002152543.tsx +28 -0
  31. package/.history/src/lib/magic_20251002152546.tsx +28 -0
  32. package/.history/src/lib/magic_20251002152802.tsx +47 -0
  33. package/.history/src/lib/magic_20251002154740.tsx +47 -0
  34. package/.history/src/lib/magic_20251002155035.tsx +47 -0
  35. package/.history/src/lib/magic_20251002160411.tsx +49 -0
  36. package/.history/src/lib/magic_20251002160428.tsx +49 -0
  37. package/.history/src/lib/magic_20251002161028.tsx +50 -0
  38. package/.history/src/lib/metamask_20251002141612.tsx +0 -0
  39. package/.history/src/lib/metamask_20251002142622.tsx +38 -0
  40. package/.history/src/lib/metamask_20251002142654.tsx +41 -0
  41. package/.history/src/lib/metamask_20251002142726.tsx +44 -0
  42. package/.history/src/lib/metamask_20251002142848.tsx +0 -0
  43. package/.history/src/lib/metamask_20251002152802.tsx +28 -0
  44. package/.history/src/lib/metamask_20251002153516.tsx +27 -0
  45. package/.history/src/lib/metamask_20251002154228.tsx +27 -0
  46. package/.history/src/lib/metamask_20251002154523.tsx +27 -0
  47. package/.history/src/lib/styling_20251002154448.css +0 -0
  48. package/.history/src/lib/styling_20251002154523.css +19 -0
  49. package/.history/src/lib/styling_20251002154531.css +19 -0
  50. package/.history/src/lib/styling_20251002154544.css +20 -0
  51. package/.history/src/lib/styling_20251002154548.css +19 -0
  52. package/.history/src/lib/styling_20251002160446.css +20 -0
  53. package/.history/src/lib/styling_20251002160511.css +23 -0
  54. package/.history/src/lib/styling_20251002160515.css +24 -0
  55. package/.history/src/lib/styling_20251002160815.css +24 -0
  56. package/.history/src/lib/styling_20251002160910.css +24 -0
  57. package/.history/src/lib/styling_20251002160915.css +24 -0
  58. package/.history/src/lib/styling_20251002160952.css +24 -0
  59. package/.history/src/lib/styling_20251002161001.css +24 -0
  60. package/.history/src/lib/styling_20251002161011.css +24 -0
  61. package/.history/src/lib/styling_20251002161016.css +24 -0
  62. package/.history/src/lib/styling_20251002161036.css +25 -0
  63. package/.history/src/lib/tauntContext_20251002142359.ts +0 -0
  64. package/.history/src/lib/tauntContext_20251002142622.ts +17 -0
  65. package/.history/src/lib/tauntContext_20251002152540.ts +22 -0
  66. package/.history/src/lib/tauntContext_20251002152802.ts +22 -0
  67. package/.history/src/lib/tauntProvider_20251002142503.tsx +0 -0
  68. package/.history/src/lib/tauntProvider_20251002142622.tsx +15 -0
  69. package/.history/src/lib/tauntProvider_20251002143158.tsx +19 -0
  70. package/.history/src/lib/tauntProvider_20251002144018.tsx +19 -0
  71. package/.history/src/lib/tauntProvider_20251002152234.tsx +40 -0
  72. package/.history/src/lib/tauntProvider_20251002152802.tsx +40 -0
  73. package/.history/src/lib/tauntProvider_20251002153101.tsx +49 -0
  74. package/.history/src/lib/taunt_20251002160026.ts +0 -0
  75. package/.history/src/lib/taunt_20251002160045.ts +2 -0
  76. package/.history/src/main_20251002141038.tsx +10 -0
  77. package/.history/src/main_20251002141444.tsx +12 -0
  78. package/.history/src/main_20251002160347.tsx +12 -0
  79. package/.history/vite.config_20251002141038.ts +7 -0
  80. package/.history/vite.config_20251002141323.ts +10 -0
  81. package/.prettierrc.mjs +22 -0
  82. package/README.md +73 -0
  83. package/eslint.config.js +23 -0
  84. package/index.html +13 -0
  85. package/package.json +32 -0
  86. package/public/vite.svg +1 -0
  87. package/src/App.css +42 -0
  88. package/src/App.tsx +54 -0
  89. package/src/index.css +68 -0
  90. package/src/lib/exports.ts +3 -0
  91. package/src/lib/magic.tsx +50 -0
  92. package/src/lib/metamask.tsx +27 -0
  93. package/src/lib/styling.css +25 -0
  94. package/src/lib/taunt.ts +2 -0
  95. package/src/lib/tauntContext.ts +22 -0
  96. package/src/lib/tauntProvider.tsx +49 -0
  97. package/src/main.tsx +12 -0
  98. package/tsconfig.app.json +28 -0
  99. package/tsconfig.json +7 -0
  100. package/tsconfig.node.json +26 -0
  101. package/vite.config.ts +10 -0
@@ -0,0 +1,47 @@
1
+ import "./App.css"
2
+
3
+ import { MagicEmailInput } from "./lib/magic"
4
+ import { MetaMaskButton } from "./lib/metamask"
5
+ import { useTaunt } from "./lib/tauntContext"
6
+ import { TauntProvider } from "./lib/tauntProvider"
7
+
8
+ function App() {
9
+ return (
10
+ <TauntProvider
11
+ tauntServiceEndpoint={import.meta.env.VITE_TAUNT_SERVICE_ENDPOINT}
12
+ magicKey={import.meta.env.VITE_MAGIC_KEY}>
13
+ <div
14
+ style={{
15
+ display: "flex",
16
+ flexDirection: "column",
17
+ gap: 8,
18
+ alignItems: "center"
19
+ }}>
20
+ <MagicEmailInput />
21
+ <MetaMaskButton />
22
+ <LogoutButton />
23
+ <TauntDeets />
24
+ </div>
25
+ </TauntProvider>
26
+ )
27
+ }
28
+
29
+ function LogoutButton() {
30
+ const { deets } = useTaunt()
31
+ if (!deets) return null
32
+
33
+ return (
34
+ <button
35
+ className="ml-2 p-2 bg-blue-500 text-white rounded-md"
36
+ type="button">
37
+ Logout
38
+ </button>
39
+ )
40
+ }
41
+
42
+ function TauntDeets() {
43
+ const { deets } = useTaunt()
44
+ return <textarea value={JSON.stringify(deets, null, 2)} readOnly />
45
+ }
46
+
47
+ export default App
@@ -0,0 +1,54 @@
1
+ import "./App.css"
2
+
3
+ import { MagicEmailInput } from "./lib/magic"
4
+ import { MetaMaskButton } from "./lib/metamask"
5
+ import { useTaunt } from "./lib/tauntContext"
6
+ import { TauntProvider } from "./lib/tauntProvider"
7
+
8
+ function App() {
9
+ return (
10
+ <TauntProvider
11
+ tauntServiceEndpoint={import.meta.env.VITE_TAUNT_SERVICE_ENDPOINT}
12
+ magicKey={import.meta.env.VITE_MAGIC_KEY}>
13
+ <div
14
+ style={{
15
+ display: "flex",
16
+ flexDirection: "column",
17
+ gap: 8,
18
+ alignItems: "center"
19
+ }}>
20
+ <MagicEmailInput />
21
+ <MetaMaskButton />
22
+ <LogoutButton />
23
+ <TauntDeets />
24
+ </div>
25
+ </TauntProvider>
26
+ )
27
+ }
28
+
29
+ function LogoutButton() {
30
+ const { deets } = useTaunt()
31
+ if (!deets) return null
32
+
33
+ return (
34
+ <button
35
+ className="ml-2 p-2 bg-blue-500 text-white rounded-md"
36
+ type="button">
37
+ Logout
38
+ </button>
39
+ )
40
+ }
41
+
42
+ function TauntDeets() {
43
+ const { deets } = useTaunt()
44
+ return (
45
+ <textarea
46
+ rows={5}
47
+ cols={50}
48
+ value={JSON.stringify(deets, null, 2)}
49
+ readOnly
50
+ />
51
+ )
52
+ }
53
+
54
+ export default App
@@ -0,0 +1,54 @@
1
+ // import "./App.css"
2
+
3
+ import { MagicEmailInput } from "./lib/magic"
4
+ import { MetaMaskButton } from "./lib/metamask"
5
+ import { useTaunt } from "./lib/tauntContext"
6
+ import { TauntProvider } from "./lib/tauntProvider"
7
+
8
+ function App() {
9
+ return (
10
+ <TauntProvider
11
+ tauntServiceEndpoint={import.meta.env.VITE_TAUNT_SERVICE_ENDPOINT}
12
+ magicKey={import.meta.env.VITE_MAGIC_KEY}>
13
+ <div
14
+ style={{
15
+ display: "flex",
16
+ flexDirection: "column",
17
+ gap: 8,
18
+ alignItems: "center"
19
+ }}>
20
+ <MagicEmailInput />
21
+ <MetaMaskButton />
22
+ <LogoutButton />
23
+ <TauntDeets />
24
+ </div>
25
+ </TauntProvider>
26
+ )
27
+ }
28
+
29
+ function LogoutButton() {
30
+ const { deets } = useTaunt()
31
+ if (!deets) return null
32
+
33
+ return (
34
+ <button
35
+ className="ml-2 p-2 bg-blue-500 text-white rounded-md"
36
+ type="button">
37
+ Logout
38
+ </button>
39
+ )
40
+ }
41
+
42
+ function TauntDeets() {
43
+ const { deets } = useTaunt()
44
+ return (
45
+ <textarea
46
+ rows={5}
47
+ cols={50}
48
+ value={JSON.stringify(deets, null, 2)}
49
+ readOnly
50
+ />
51
+ )
52
+ }
53
+
54
+ export default App
File without changes
@@ -0,0 +1,3 @@
1
+ export * from "./magic"
2
+ export * from "./metamask"
3
+ export * from "./taunt"
File without changes
@@ -0,0 +1,44 @@
1
+ import { tauntMagicDidLogin } from "@redzone/taunt-logins"
2
+ import { useCallback, useMemo, useState } from "react"
3
+
4
+ import { useTaunt } from "./tauntContext"
5
+
6
+ export const Emailer = ({ onEmail }: { onEmail?: (email: string) => void }) => {
7
+ const { tauntServiceEndpoint } = useTaunt()
8
+ const [email, setEmail] = useState<string>()
9
+
10
+ const initialised = useMemo(() => email !== undefined, [email])
11
+
12
+ const validEmail = useMemo(() => {
13
+ const validRegex =
14
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
15
+ return email?.match(validRegex) ? email : undefined
16
+ }, [email])
17
+
18
+ const runMagic = useCallback(() => {
19
+ if (!validEmail) return
20
+
21
+ if (onEmail) {
22
+ onEmail(email!)
23
+ } else {
24
+ tauntMagicDidLogin(tauntServiceEndpoint, email!)
25
+ }
26
+ }, [validEmail, onEmail])
27
+
28
+ return (
29
+ <div>
30
+ {initialised && !validEmail && (
31
+ <div style={{ color: "red" }}>Please enter a valid email</div>
32
+ )}
33
+ <input
34
+ onChange={(e) => setEmail(e.target.value)}
35
+ placeholder="Enter your email"
36
+ type="email"
37
+ value={email}
38
+ />
39
+ <button onClick={runMagic} type="button">
40
+ Send Magic Link
41
+ </button>
42
+ </div>
43
+ )
44
+ }
@@ -0,0 +1,28 @@
1
+ import { tauntMagicDidLogin } from "@redzone/taunt-logins"
2
+ import { useCallback, useMemo, useState } from "react"
3
+
4
+ import { useTaunt } from "./tauntContext"
5
+
6
+ export const MetaMaskButton = ({openMetamask}: {openMetamask?: () => void}) => {
7
+ const { metamaskLogin } = useTaunt()
8
+
9
+ const runMetamask = useCallback(() => {
10
+ if(openMetamask) {
11
+ openMetamask()
12
+ } else {
13
+
14
+ metamaskLogin()
15
+ }
16
+ }, [metamaskLogin, openMetamask])
17
+
18
+ return (
19
+
20
+ <button
21
+ className="ml-2 p-2 bg-blue-500 text-white rounded-md"
22
+ onClick={runMetamask}
23
+ type="button">
24
+ Login with Metamask
25
+ </button>
26
+ )
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ import { tauntMagicDidLogin } from "@redzone/taunt-logins"
2
+ import { useCallback, useMemo, useState } from "react"
3
+
4
+ import { useTaunt } from "./tauntContext"
5
+
6
+ export const MetaMaskButton = ({openMetamask}: {openMetamask?: () => void}) => {
7
+ const { metamaskLogin } = useTaunt()
8
+
9
+ const runMetamask = useCallback(() => {
10
+ if(openMetamask) {
11
+ openMetamask()
12
+ } else {
13
+
14
+ metamaskLogin()
15
+ }
16
+ }, [metamaskLogin, openMetamask])
17
+
18
+ return (
19
+
20
+ <button
21
+ className="ml-2 p-2 bg-blue-500 text-white rounded-md"
22
+ onClick={runMetamask}
23
+ type="button">
24
+ Login with Metamask
25
+ </button>
26
+ )
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ import { useCallback } from "react"
2
+
3
+ import { useTaunt } from "./tauntContext"
4
+
5
+ export const MetaMaskButton = ({
6
+ openMetamask
7
+ }: {
8
+ openMetamask?: () => void
9
+ }) => {
10
+ const { metamaskLogin } = useTaunt()
11
+
12
+ const runMetamask = useCallback(() => {
13
+ if (openMetamask) {
14
+ openMetamask()
15
+ } else {
16
+ metamaskLogin()
17
+ }
18
+ }, [metamaskLogin, openMetamask])
19
+
20
+ return (
21
+ <button
22
+ className="ml-2 p-2 bg-blue-500 text-white rounded-md"
23
+ onClick={runMetamask}
24
+ type="button">
25
+ Login with Metamask
26
+ </button>
27
+ )
28
+ }
@@ -0,0 +1,47 @@
1
+ import { useCallback, useMemo, useState } from "react"
2
+
3
+ import { useTaunt } from "./tauntContext"
4
+
5
+ export const MagicEmailInput = ({
6
+ onEmail
7
+ }: {
8
+ onEmail?: (email: string) => void
9
+ }) => {
10
+ const { otpMagicLogin } = useTaunt()
11
+ const [email, setEmail] = useState<string>()
12
+
13
+ const initialised = useMemo(() => email !== undefined, [email])
14
+
15
+ const validEmail = useMemo(() => {
16
+ const validRegex =
17
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
18
+ return email?.match(validRegex) ? email : undefined
19
+ }, [email])
20
+
21
+ const runMagic = useCallback(() => {
22
+ if (!validEmail) return
23
+
24
+ if (onEmail) {
25
+ onEmail(email!)
26
+ } else {
27
+ otpMagicLogin(email!)
28
+ }
29
+ }, [validEmail, onEmail])
30
+
31
+ return (
32
+ <div>
33
+ {initialised && !validEmail && (
34
+ <div style={{ color: "red" }}>Please enter a valid email</div>
35
+ )}
36
+ <input
37
+ onChange={(e) => setEmail(e.target.value)}
38
+ placeholder="Enter your email"
39
+ type="email"
40
+ value={email}
41
+ />
42
+ <button onClick={runMagic} type="button">
43
+ Send Magic Link
44
+ </button>
45
+ </div>
46
+ )
47
+ }
@@ -0,0 +1,47 @@
1
+ import { useCallback, useMemo, useState } from "react"
2
+
3
+ import { useTaunt } from "./tauntContext"
4
+
5
+ export const MagicEmailInput = ({
6
+ onEmail
7
+ }: {
8
+ onEmail?: (email: string) => void
9
+ }) => {
10
+ const { otpMagicLogin } = useTaunt()
11
+ const [email, setEmail] = useState<string>()
12
+
13
+ const initialised = useMemo(() => email !== undefined, [email])
14
+
15
+ const validEmail = useMemo(() => {
16
+ const validRegex =
17
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
18
+ return email?.match(validRegex) ? email : undefined
19
+ }, [email])
20
+
21
+ const runMagic = useCallback(() => {
22
+ if (!validEmail) return
23
+
24
+ if (onEmail) {
25
+ onEmail(email!)
26
+ } else {
27
+ otpMagicLogin(email!)
28
+ }
29
+ }, [validEmail, onEmail])
30
+
31
+ return (
32
+ <div style={{ display: "flex", flexDirection: "row", gap: 8 }}>
33
+ {initialised && !validEmail && (
34
+ <div style={{ color: "red" }}>Please enter a valid email</div>
35
+ )}
36
+ <input
37
+ onChange={(e) => setEmail(e.target.value)}
38
+ placeholder="Enter your email"
39
+ type="email"
40
+ value={email}
41
+ />
42
+ <button onClick={runMagic} type="button">
43
+ Send Magic Link
44
+ </button>
45
+ </div>
46
+ )
47
+ }
@@ -0,0 +1,47 @@
1
+ import { useCallback, useMemo, useState } from "react"
2
+
3
+ import { useTaunt } from "./tauntContext"
4
+
5
+ export const MagicEmailInput = ({
6
+ onEmail
7
+ }: {
8
+ onEmail?: (email: string) => void
9
+ }) => {
10
+ const { otpMagicLogin } = useTaunt()
11
+ const [email, setEmail] = useState<string>()
12
+
13
+ const initialised = useMemo(() => email !== undefined, [email])
14
+
15
+ const validEmail = useMemo(() => {
16
+ const validRegex =
17
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
18
+ return email?.match(validRegex) ? email : undefined
19
+ }, [email])
20
+
21
+ const runMagic = useCallback(() => {
22
+ if (!validEmail) return
23
+
24
+ if (onEmail) {
25
+ onEmail(email!)
26
+ } else {
27
+ otpMagicLogin(email!)
28
+ }
29
+ }, [validEmail, onEmail])
30
+
31
+ return (
32
+ <div style={{ display: "flex", flexDirection: "row", gap: 8 }}>
33
+ {initialised && !validEmail && (
34
+ <div style={{ color: "red" }}>Please enter a valid email</div>
35
+ )}
36
+ <input
37
+ onChange={(e) => setEmail(e.target.value ? e.target.value : undefined)}
38
+ placeholder="Enter your email"
39
+ type="email"
40
+ value={email}
41
+ />
42
+ <button onClick={runMagic} type="button">
43
+ Send Magic Link
44
+ </button>
45
+ </div>
46
+ )
47
+ }
@@ -0,0 +1,49 @@
1
+ import { useCallback, useMemo, useState } from "react"
2
+
3
+ import "./styling.css"
4
+
5
+ import { useTaunt } from "./tauntContext"
6
+
7
+ export const MagicEmailInput = ({
8
+ onEmail
9
+ }: {
10
+ onEmail?: (email: string) => void
11
+ }) => {
12
+ const { otpMagicLogin } = useTaunt()
13
+ const [email, setEmail] = useState<string>()
14
+
15
+ const initialised = useMemo(() => email !== undefined, [email])
16
+
17
+ const validEmail = useMemo(() => {
18
+ const validRegex =
19
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
20
+ return email?.match(validRegex) ? email : undefined
21
+ }, [email])
22
+
23
+ const runMagic = useCallback(() => {
24
+ if (!validEmail) return
25
+
26
+ if (onEmail) {
27
+ onEmail(email!)
28
+ } else {
29
+ otpMagicLogin(email!)
30
+ }
31
+ }, [validEmail, onEmail])
32
+
33
+ return (
34
+ <div style={{ display: "flex", flexDirection: "row", gap: 8 }}>
35
+ {initialised && !validEmail && (
36
+ <div style={{ color: "red" }}>Please enter a valid email</div>
37
+ )}
38
+ <input
39
+ onChange={(e) => setEmail(e.target.value ? e.target.value : undefined)}
40
+ placeholder="Enter your email"
41
+ type="email"
42
+ value={email}
43
+ />
44
+ <button onClick={runMagic} type="button">
45
+ Send Magic Link
46
+ </button>
47
+ </div>
48
+ )
49
+ }
@@ -0,0 +1,49 @@
1
+ import { useCallback, useMemo, useState } from "react"
2
+
3
+ import "./styling.css"
4
+
5
+ import { useTaunt } from "./tauntContext"
6
+
7
+ export const MagicEmailInput = ({
8
+ onEmail
9
+ }: {
10
+ onEmail?: (email: string) => void
11
+ }) => {
12
+ const { otpMagicLogin } = useTaunt()
13
+ const [email, setEmail] = useState<string>()
14
+
15
+ const initialised = useMemo(() => email !== undefined, [email])
16
+
17
+ const validEmail = useMemo(() => {
18
+ const validRegex =
19
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
20
+ return email?.match(validRegex) ? email : undefined
21
+ }, [email])
22
+
23
+ const runMagic = useCallback(() => {
24
+ if (!validEmail) return
25
+
26
+ if (onEmail) {
27
+ onEmail(email!)
28
+ } else {
29
+ otpMagicLogin(email!)
30
+ }
31
+ }, [validEmail, onEmail])
32
+
33
+ return (
34
+ <div style={{ display: "flex", flexDirection: "row", gap: 8 }}>
35
+ {initialised && !validEmail && (
36
+ <div style={{ color: "red" }}>Please enter a valid email</div>
37
+ )}
38
+ <input
39
+ onChange={(e) => setEmail(e.target.value ? e.target.value : undefined)}
40
+ placeholder="Enter your email"
41
+ type="email"
42
+ value={email}
43
+ />
44
+ <button className="rdz-button" onClick={runMagic} type="button">
45
+ Send Magic Link
46
+ </button>
47
+ </div>
48
+ )
49
+ }
@@ -0,0 +1,50 @@
1
+ import { useCallback, useMemo, useState } from "react"
2
+
3
+ import "./styling.css"
4
+
5
+ import { useTaunt } from "./tauntContext"
6
+
7
+ export const MagicEmailInput = ({
8
+ onEmail
9
+ }: {
10
+ onEmail?: (email: string) => void
11
+ }) => {
12
+ const { otpMagicLogin } = useTaunt()
13
+ const [email, setEmail] = useState<string>()
14
+
15
+ const initialised = useMemo(() => email !== undefined, [email])
16
+
17
+ const validEmail = useMemo(() => {
18
+ const validRegex =
19
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
20
+ return email?.match(validRegex) ? email : undefined
21
+ }, [email])
22
+
23
+ const runMagic = useCallback(() => {
24
+ if (!validEmail) return
25
+
26
+ if (onEmail) {
27
+ onEmail(email!)
28
+ } else {
29
+ otpMagicLogin(email!)
30
+ }
31
+ }, [validEmail, onEmail])
32
+
33
+ return (
34
+ <div style={{ display: "flex", flexDirection: "row", gap: 8 }}>
35
+ {initialised && !validEmail && (
36
+ <div style={{ color: "red" }}>Please enter a valid email</div>
37
+ )}
38
+ <input
39
+ className="rdz-input"
40
+ onChange={(e) => setEmail(e.target.value ? e.target.value : undefined)}
41
+ placeholder="Enter your email"
42
+ type="email"
43
+ value={email}
44
+ />
45
+ <button className="rdz-button" onClick={runMagic} type="button">
46
+ Send Magic Link
47
+ </button>
48
+ </div>
49
+ )
50
+ }
File without changes
@@ -0,0 +1,38 @@
1
+ import { tauntMagicDidLogin } from "@redzone/taunt-logins"
2
+ import { useCallback, useMemo, useState } from "react"
3
+
4
+ export const Emailer = ({ onEmail }: { onEmail?: (email: string) => void }) => {
5
+ const [email, setEmail] = useState<string>()
6
+
7
+ const initialised = useMemo(() => email !== undefined, [email])
8
+
9
+ const validEmail = useMemo(() => {
10
+ const validRegex =
11
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
12
+ return email?.match(validRegex) ? email : undefined
13
+ }, [email])
14
+
15
+ const runMagic = useCallback(() => {
16
+ if (!validEmail) return
17
+
18
+ if (onEmail) {
19
+ onEmail(email!)
20
+ } else {
21
+ tauntMagicDidLogin(email!)
22
+ }
23
+ }, [validEmail, onEmail])
24
+
25
+ return (
26
+ <div>
27
+ <input
28
+ onChange={(e) => setEmail(e.target.value)}
29
+ placeholder="Enter your email"
30
+ type="email"
31
+ value={email}
32
+ />
33
+ <button onClick={runMagic} type="button">
34
+ Send Magic Link
35
+ </button>
36
+ </div>
37
+ )
38
+ }
@@ -0,0 +1,41 @@
1
+ import { tauntMagicDidLogin } from "@redzone/taunt-logins"
2
+ import { useCallback, useMemo, useState } from "react"
3
+
4
+ import { useTaunt } from "./tauntContext"
5
+
6
+ export const Emailer = ({ onEmail }: { onEmail?: (email: string) => void }) => {
7
+ const { tauntServiceEndpoint } = useTaunt()
8
+ const [email, setEmail] = useState<string>()
9
+
10
+ const initialised = useMemo(() => email !== undefined, [email])
11
+
12
+ const validEmail = useMemo(() => {
13
+ const validRegex =
14
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
15
+ return email?.match(validRegex) ? email : undefined
16
+ }, [email])
17
+
18
+ const runMagic = useCallback(() => {
19
+ if (!validEmail) return
20
+
21
+ if (onEmail) {
22
+ onEmail(email!)
23
+ } else {
24
+ tauntMagicDidLogin(tauntServiceEndpoint, email!)
25
+ }
26
+ }, [validEmail, onEmail])
27
+
28
+ return (
29
+ <div>
30
+ <input
31
+ onChange={(e) => setEmail(e.target.value)}
32
+ placeholder="Enter your email"
33
+ type="email"
34
+ value={email}
35
+ />
36
+ <button onClick={runMagic} type="button">
37
+ Send Magic Link
38
+ </button>
39
+ </div>
40
+ )
41
+ }