Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/pages/hooks/useAuth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ connected).

### connect

`(signerIdOrUrl?: string) => void{:typescript}`
`(signerIdOrUrl?: string) => Promise<void>{:typescript}`

Function to trigger will open connect wallet modal wihout `signerIdOrUrl` provided, will open signer
if signers includes one with provided id or provided value is valid signer url.

<Callout type="warning" emoji="⚠️">
Function will throw `Error("Identitykit is not initialized yet"){:typescript}` until identitykit <a href="/hooks/useIdentityKit#isinitializing"><strong>initializes</strong></a>. So make sure you disable your connect button in these cases.
Function will throw `Error("Identitykit is not initialized yet"){:typescript}` until identitykit <a href="/hooks/useIdentityKit#isinitializing"><strong>initializes</strong></a>, so make sure you disable your connect button in these cases. In case of a connection failure, it will throw an error with an appropriate reason only if <a href="/getting-started/connect-wallet">onConnectFailure</a> was not provided.
</Callout>

### disconnect
Expand Down
2 changes: 2 additions & 0 deletions examples/react-demo/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export const MOCKED_SIGNER_SECOND_ACCOUNT =
"6pfju-rc52z-aihtt-ahhg6-z2bzc-ofp5r-igp5i-qy5ep-j6vob-gs3ae-nae"

export const e8s = 10 ** 8

export const ICP_API_HOST = "https://icp-api.io/"
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
CallCanisterMethodTitle,
CallCanisterMethodType,
} from "./constants"
import { ICP_API_HOST } from "../../../constants"

const MethodComponent = {
[CallCanisterMethod.greet_no_consent]: ToTarget,
Expand All @@ -24,7 +25,7 @@ const MethodComponent = {

export function CallCanisterSection() {
const { user } = useAuth()
const agent = useAgent()
const agent = useAgent({ host: ICP_API_HOST })
const [selectedMethod, setSelectedMethod] = useState<CallCanisterMethodType>(
CallCanisterMethod.greet_no_consent
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { IDL } from "@dfinity/candid"
import { Button } from "../../atoms"
import { CodeSection, RequestSection, ResponseSection } from "../../molecules"
import { CallCanisterMethodType } from "./constants"
import { ICP_API_HOST } from "../../../constants"

type Request = {
method: string
Expand Down Expand Up @@ -47,7 +48,7 @@ export function Section({
const { user } = useAuth()
const signer = useSigner()

const agent = useAgent()
const agent = useAgent({ host: ICP_API_HOST })

const handleSubmit = async () => {
if (!signer) return
Expand Down
1 change: 0 additions & 1 deletion packages/identitykit/src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export const DEFAULT_MAX_TIME_TO_LIVE = BigInt(1.8e12) // 30 min
export const DEFAULT_IDLE_TIMEOUT = 14_400_000 // 4 hours
export const ICP_API_HOST = "https://icp-api.io/"
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
InternetIdentity,
Stoic,
} from "../../../../lib"
import { useCreateIdentityKit, useProceedSigner } from "../../hooks"
import { useCreateIdentityKit, useCreatePromise, useProceedSigner } from "../../hooks"
import { validateUrl } from "../../utils"
import { SignerConfig } from "../../../../lib/types"
import { ConnectWalletModal } from "../connect-wallet"
Expand Down Expand Up @@ -47,6 +47,7 @@ export const Provider = <T extends IdentityKitAuthType>({
...props
}: ProviderProps<T>) => {
const [isModalOpen, setIsModalOpen] = useState(false)
const { createPromise, resolve, reject } = useCreatePromise<void>()
const toggleModal = () => {
setIsModalOpen((prev) => !prev)
}
Expand Down Expand Up @@ -93,16 +94,16 @@ export const Provider = <T extends IdentityKitAuthType>({

const onConnectSuccess = useCallback(() => {
setSelectedSignerToLocalStorage()
props.onConnectSuccess?.()
}, [setSelectedSignerToLocalStorage, props.onConnectSuccess])
resolve()
}, [setSelectedSignerToLocalStorage, resolve])

const identityKit = useCreateIdentityKit({
selectedSigner,
clearSigner,
signerClientOptions: { ...signerClientOptions, crypto },
authType,
onConnectSuccess,
onConnectFailure: props.onConnectFailure,
onConnectFailure: reject,
onDisconnect: props.onDisconnect,
realConnectDisabled,
})
Expand All @@ -117,17 +118,28 @@ export const Provider = <T extends IdentityKitAuthType>({
)

const connect = useCallback(
(signerIdOrUrl?: string) => {
async (signerIdOrUrl?: string) => {
if (isInitializing) throw new Error("Identitykit is not initialized yet")
if (!signerIdOrUrl) setIsModalOpen(true)
else {
if (signers.find((s) => s.id === signerIdOrUrl)) selectSigner(signerIdOrUrl)
if (signers.find((s) => s.id === signerIdOrUrl)) await selectSigner(signerIdOrUrl)
else {
if (!validateUrl(signerIdOrUrl))
throw new Error("Provided value is not valid signer id or url")
selectCustomSigner(signerIdOrUrl)
await selectCustomSigner(signerIdOrUrl)
}
}
return createPromise()
.then(() => {
props.onConnectSuccess?.()
})
.catch((e) => {
if (props.onConnectFailure) {
props.onConnectFailure(e)
} else {
throw e
}
})
},
[isInitializing, signers]
)
Expand Down
2 changes: 1 addition & 1 deletion packages/identitykit/src/libs/react/contexts/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface Context {
toggleModal: () => void
selectSigner: (signerId?: string) => Promise<SignerConfig | void>
selectCustomSigner: (url: string) => Promise<void>
connect: (signerIdOrUrl?: string) => void
connect: (signerIdOrUrl?: string) => Promise<void>
disconnect: () => Promise<void>
fetchIcpBalance?: () => Promise<void>
}
Expand Down
1 change: 1 addition & 0 deletions packages/identitykit/src/libs/react/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./use-agent"
export * from "./use-click-outside"
export * from "./context-selectors"
export * from "./use-auth"
export * from "./use-create-promise"
44 changes: 44 additions & 0 deletions packages/identitykit/src/libs/react/hooks/use-create-promise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useCallback, useRef, useState } from "react"

export function useCreatePromise<T>() {
// Internal state to force re-renders when the promise resolves
const [, setResolvedValue] = useState<unknown>()

// Store the promise and its resolve/reject handlers in a ref
const promiseRef = useRef<{
promise: Promise<T> | null
resolve: ((value: T) => void) | null
reject: ((reason?: unknown) => void) | null
}>({
promise: null,
resolve: null,
reject: null,
})

// Create the promise
const createPromise = useCallback(() => {
promiseRef.current.promise = new Promise((resolve, reject) => {
promiseRef.current.resolve = resolve
promiseRef.current.reject = reject
})
return promiseRef.current.promise
}, [])

// Resolve the promise
const resolve = useCallback((value: T) => {
if (promiseRef.current.resolve) {
promiseRef.current.resolve(value)
setResolvedValue(value) // Trigger re-render
}
}, [])

// Reject the promise
const reject = useCallback((error: unknown) => {
if (promiseRef.current.reject) {
promiseRef.current.reject(error)
setResolvedValue(undefined) // Trigger re-render (optional)
}
}, [])

return { createPromise, resolve, reject, promise: promiseRef.current.promise }
}
Loading