Skip to content

Commit

Permalink
feat: add Magic provider (#180)
Browse files Browse the repository at this point in the history
* feat: add Magic Link provider

* feat: add Magic Link provider to example apps

* docs: update README
  • Loading branch information
drichar authored Jun 5, 2024
1 parent cfb9f00 commit afb981f
Show file tree
Hide file tree
Showing 38 changed files with 2,621 additions and 209 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"@typescript-eslint/no-explicit-any": "off"
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
},
"ignorePatterns": ["node_modules/", "dist/", ".env"]
}
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Some wallets require additional packages to be installed. The following table li
| Pera Wallet | `@perawallet/connect-beta` |
| WalletConnect | `@walletconnect/modal`, `@walletconnect/sign-client` |
| Lute Wallet | `lute-connect` |
| Magic.link | `magic-sdk`, `@magic-ext/algorand` |

## Configuration

Expand All @@ -82,6 +83,10 @@ const walletManager = new WalletManager({
{
id: WalletId.LUTE,
options: { siteName: '<YOUR_SITE_NAME>' }
},
{
id: WalletId.MAGIC,
options: { apiKey: '<YOUR_API_KEY>' }
}
],
network: NetworkId.TESTNET
Expand All @@ -96,6 +101,8 @@ To initialize wallets with default options, pass the wallet ID using the `Wallet

> **Note:** Pera and WalletConnect's `projectId` option is required. You can obtain a project ID by registering your application at https://cloud.walletconnect.com/
> **Note:** Magic's required `apiKey` can be obtained by signing up at https://dashboard.magic.link/signup
#### `network` (optional)

The `network` property is used to set the network for the application. Using the `NetworkId` emum, it can be set to either `BETANET`, `TESTNET`, `MAINNET`, or `LOCALNET`. If unset, the default is `TESTNET`.
Expand Down
63 changes: 23 additions & 40 deletions examples/nextjs/src/app/Connect.module.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
.walletName {
.walletGroup {
display: flex;
flex-direction: column;
align-items: center;
gap: 1em;
margin-bottom: 2em;
}

.walletGroup h4 {
line-height: 1.5;
margin: 1.33em 0;
text-align: center;
margin: 0;
}

.walletName[data-active='true']:after {
.walletGroup h4[data-active='true']:after {
content: ' [active]';
}

Expand All @@ -14,46 +21,22 @@
justify-content: center;
flex-wrap: wrap;
gap: 0.5em;
margin-bottom: 0.9em;
}

.walletButtons button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
.inputGroup {
display: flex;
align-items: center;
justify-content: center;
gap: 0.6em;
}
.walletButtons button:not(:disabled):hover {
border-color: #0071ff;
.inputGroup label {
margin-left: 1em;
font-weight: 500;
}
.walletButtons button:focus,
.walletButtons button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
.inputGroup input {
min-width: 16em;
}
.walletButtons button:disabled {
.inputGroup input[disabled] {
opacity: 0.75;
cursor: default;
}

.walletMenu {
margin-top: 1.5em;
}

.fallbackMsg {
font-size: 1.125rem;
line-height: 1.5rem;
text-align: center;
opacity: 0.5;
margin: 2em 0;
}

@media (prefers-color-scheme: light) {
.walletButtons button {
background-color: #ffffff;
}
color: light-dark(rgba(16, 16, 16, 0.3), rgba(255, 255, 255, 0.3));
}
48 changes: 44 additions & 4 deletions examples/nextjs/src/app/Connect.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
'use client'

import { useWallet, type Wallet } from '@txnlab/use-wallet-react'
import { WalletId, useWallet, type Wallet } from '@txnlab/use-wallet-react'
import algosdk from 'algosdk'
import * as React from 'react'
import styles from './Connect.module.css'

export function Connect() {
const { algodClient, activeAddress, transactionSigner, wallets } = useWallet()

const [isSending, setIsSending] = React.useState(false)
const [magicEmail, setMagicEmail] = React.useState('')

const { algodClient, activeAddress, transactionSigner, wallets } = useWallet()
const isMagicLink = (wallet: Wallet) => wallet.id === WalletId.MAGIC
const isEmailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(magicEmail)

const isConnectDisabled = (wallet: Wallet) => {
if (wallet.isConnected) {
return true
}
if (isMagicLink(wallet) && !isEmailValid) {
return true
}
return false
}

const getConnectArgs = (wallet: Wallet) => {
if (isMagicLink(wallet)) {
return { email: magicEmail }
}
return undefined
}

const setActiveAccount = (event: React.ChangeEvent<HTMLSelectElement>, wallet: Wallet) => {
const target = event.target
Expand Down Expand Up @@ -53,12 +74,16 @@ export function Connect() {
return (
<div>
{wallets.map((wallet) => (
<div key={wallet.id}>
<div key={wallet.id} className={styles.walletGroup}>
<h4 className={styles.walletName} data-active={wallet.isActive}>
{wallet.metadata.name}
</h4>
<div className={styles.walletButtons}>
<button type="button" onClick={() => wallet.connect()} disabled={wallet.isConnected}>
<button
type="button"
onClick={() => wallet.connect(getConnectArgs(wallet))}
disabled={isConnectDisabled(wallet)}
>
Connect
</button>
<button
Expand All @@ -82,6 +107,21 @@ export function Connect() {
</button>
)}
</div>

{isMagicLink(wallet) && (
<div className={styles.inputGroup}>
<label htmlFor="magic-email">Email:</label>
<input
id="magic-email"
type="email"
value={magicEmail}
onChange={(e) => setMagicEmail(e.target.value)}
placeholder="Enter email to connect..."
disabled={wallet.isConnected}
/>
</div>
)}

{wallet.isActive && wallet.accounts.length > 0 && (
<div>
<select onChange={(e) => setActiveAccount(e, wallet)}>
Expand Down
80 changes: 80 additions & 0 deletions examples/nextjs/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,88 @@ a {
text-decoration: none;
}

h1 {
font-size: 3.2em;
line-height: 1.1;
}

button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:not(:disabled):hover {
border-color: #0071ff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
button:disabled {
opacity: 0.75;
cursor: default;
}

input[type='text'],
input[type='email'] {
border-radius: 8px;
border: 1px solid #1a1a1a;
padding: 0.6em 0.9em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
color: #ffffff;
transition: border-color 0.25s;
}

select {
border-radius: 8px;
border: 1px solid #1a1a1a;
padding: 0.6em 0.9em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
color: #ffffff;
transition: border-color 0.25s;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: right 0.5rem center;
background-repeat: no-repeat;
background-size: 1.5em 1.5em;
padding-right: 2.5rem;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
-moz-appearance: none !important;
-webkit-appearance: none !important;
appearance: none !important;
}

@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}

@media (prefers-color-scheme: light) {
button {
background-color: #f9f9f9;
border-color: #cacaca;
}
button:disabled {
border-color: #dddddd;
}
input[type='text'],
input[type='email'],
select {
background-color: #f9f9f9;
color: #1a1a1a;
border-color: #cacaca;
}
}
2 changes: 1 addition & 1 deletion examples/nextjs/src/app/page.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
text-align: center;
font-size: 3.2em;
line-height: 1.1;
margin: 0.67em 0 0.25em;
margin: 0.67em 0;
}

/* Enable hover only on non-touch devices */
Expand Down
4 changes: 4 additions & 0 deletions examples/nextjs/src/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const walletManager = new WalletManager({
{
id: WalletId.LUTE,
options: { siteName: 'Example Site' }
},
{
id: WalletId.MAGIC,
options: { apiKey: 'pk_live_D17FD8D89621B5F3' }
}
],
network: NetworkId.TESTNET
Expand Down
Loading

0 comments on commit afb981f

Please sign in to comment.