<@U04UQ68083H> show example of how to use ory elem...
# ory-copilot
b
@chilly-king-10285 show example of how to use ory elements for recovery in next.js
b
A message from kapa.ai
To demonstrate how to use Ory Elements for recovery in Next.js, I can provide you with an example based on the knowledge sources. Here's a code snippet showing how to implement a recovery page using Ory Elements in a Next.js application:
Copy code
typescript import Head from "next/head" import Image from "next/image" import styles from "../styles/Home.module.css" import { useEffect, useState } from "react" import { useRouter } from "next/router"  import { Configuration, FrontendApi, Session, Identity } from "@ory/client" import { edgeConfig } from "@ory/integrations/next"  const ory = new FrontendApi(new Configuration(edgeConfig))  // Returns either the email or the username depending on the user's Identity Schema const getUserName = (identity: Identity) =>   identity.traits.email || identity.traits.username  const Home = () => {   const router = useRouter()    const [session, setSession] = useState<Session | undefined>()   const [logoutUrl, setLogoutUrl] = useState<string | undefined>()    useEffect(() => {     ory       .toSession()       .then(({ data }) => {         // User has a session!         setSession(data)         // Create a logout url         ory.createBrowserLogoutFlow().then(({ data }) => {           setLogoutUrl(data.logout_url)         })       })       .catch(() => {         // Redirect to login page         return router.push(edgeConfig.basePath + "/ui/login")       })   }, [router])    if (!session) {     // Still loading     return null   }    // ... rest of the component code }  export default Home
This example shows how to integrate Ory Elements for recovery in a Next.js application. It includes the necessary imports from Ory client and integrations, sets up the Ory frontend API client, and implements a basic session check and logout functionality. To specifically handle the recovery flow, you would typically create a separate recovery page component. The recovery page would use Ory Elements to render the recovery form and handle the recovery process. For more detailed information on implementing the recovery flow with Ory Elements in Next.js, you can refer to the following resources: 1. [Custom user interface with Ory Elements](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-ory-elements#recovery-page) 2. [Integration basics](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#create-recovery-flow) These resources provide more comprehensive examples and explanations on how to implement the recovery flow using Ory Elements in a Next.js application.
b
@chilly-king-10285 how do I get this to display the input to enter the sent code after the recovery email is sent?
Copy code
"use client";

import { Form, TextInput, Button, InlineNotification, Stack, Loading } from '@carbon/react'
import type { RecoveryFlow, UiNode, UiNodeInputAttributes, UpdateRecoveryFlowBody } from "@ory/client"
import { filterNodesByGroups, isUiNodeInputAttributes } from '@ory/integrations/ui';
import { useSearchParams, useRouter } from "next/navigation"
import { useState, useEffect } from "react"
import ory from "@/lib/ory"

function Recovery() {
	const [flow, setFlow] = useState<RecoveryFlow>()
	const [error, setError] = useState<string>()
	const router = useRouter()
	const searchParams = useSearchParams()
	const flowId = searchParams.get("flow")
	const returnTo = searchParams.get("return_to")
	const user = searchParams.get("user")

	const handleSubmit = (email: string) => {
		if (!flow) {
			return
		}

		const submitData: UpdateRecoveryFlowBody = {
			email,
			method: "code",
			csrf_token: flow.ui.nodes.find(
				(node) => node.attributes.name === "csrf_token"
			)?.attributes.value as string,
		}

		// FIX: remove
		// console.log(flow)
		// console.log(submitData)

		ory
			.updateRecoveryFlow({
				flow: String(flow.id),
				updateRecoveryFlowBody: submitData,
			})
			.then(({ data }) => {
				setFlow(data)
				setError(undefined)
			})
			.catch((error) => {
				console.error(error)
				if (error.response?.status === 400) {
					setFlow(error.response.data)
					// setError(error.response.data.ui.messages?.[0]?.text)
				}
			})
	}

	useEffect(() => {
		if (flow) {
			return
		}

		if (flowId) {
			ory
				.getRecoveryFlow({ id: String(flowId) })
				.then(({ data }) => {
					setFlow(data)
					// if (user) {
					// 	handleSubmit({ email: user })
					// }
				})
				.catch((error) => {
					// TODO: handle
					console.error(error)
					setError(error.message)
					router.push("/auth/recovery")
				})
			return
		}

		ory
			.createBrowserRecoveryFlow({
				returnTo: returnTo ? String(returnTo) : undefined,
			})
			.then(({ data }) => {
				setFlow(data)
				router.push(`/auth/recovery?flow=${data.id}`)
				// if (user) {
				// 	handleSubmit({ email: user })
				// }
			})
			.catch((error) => {
				console.error(error)
				setError(error.message)
			})
	}, [flowId, router, returnTo, flow, user])

	// eslint-disable-next-line consistent-return
	const mapUINode = (node: UiNode, _: number) => {
		// other node types are also supported
		// if (isUiNodeTextAttributes(node.attributes)) {
		// if (isUiNodeImageAttributes(node.attributes)) {
		// if (isUiNodeAnchorAttributes(node.attributes)) {
		if (isUiNodeInputAttributes(node.attributes)) {
			const attrs = node.attributes as UiNodeInputAttributes
			const nodeType = attrs.type

			// FIX: remove
			console.log(attrs)

			switch (nodeType) {
				case "button":
				case "submit":
					return (

						<Button type="submit" className="w-full" name={attrs.name} value={attrs.value}>
							{attrs.name}
							{/* Reset Password */}
						</Button>
						// <button
						// 	type={attrs.type as "submit" | "reset" | "button" | undefined}
						// 	name={attrs.name}
						// 	value={attrs.value}
						// />
					)
				// case "text":
				// return (<div>{attrs.</div>)
				default:
					return (
						<TextInput
							id="email"
							name={attrs.name}
							type={attrs.type}
							labelText=""
							placeholder="Enter email"
							autoComplete={
								attrs.autocomplete || attrs.name === "identifier"
									? "username"
									: ""
							}
							required={attrs.required}
							disabled={attrs.disabled}
							defaultValue={attrs.value}
						/>
						// <input
						// 	name={attrs.name}
						// 	type={attrs.type}
						// 	autoComplete={
						// 		attrs.autocomplete || attrs.name === "identifier"
						// 			? "username"
						// 			: ""
						// 	}
						// 	defaultValue={attrs.value}
						// 	required={attrs.required}
						// 	disabled={attrs.disabled}
						// />
					)
			}
		}
	}

	if (!flow) {
		return <Loading />
	}

	return (
		<div className="container max-w-md mx-auto p-6">
			<Stack gap={7}>
				<Form
					method={flow.ui.method}
					action={flow.ui.action}
					onSubmit={(e) => {
						e.preventDefault()
						const formData = new FormData(e.currentTarget)
						// FIX:remove. Figure out how to get token into form so we can get it here?
						const body = Object.fromEntries(formData) as unknown as UpdateRecoveryFlowBody;
						handleSubmit(formData.get("email") as string)
					}}>
					<Stack gap={7}>
						{filterNodesByGroups({
							nodes: flow.ui.nodes,
							// we will also map default fields here such as csrf_token
							groups: ["default", "code"],
						}).map((node, idx) => mapUINode(node, idx))}

						{flow.state === "sent_email" && (
							<InlineNotification
								kind="success"
								title="Success"
								subtitle="Recovery email has been sent. Please check your inbox."
								hideCloseButton
							/>
						)}
						{error && (
							<InlineNotification
								kind="error"
								title="Error"
								subtitle={error}
								hideCloseButton
							/>
						)}

						<Button
							kind="ghost"
							onClick={() => { router.push("/auth/login"); }}
							className="w-full"
						>
							Back to Login
						</Button>
					</Stack>
				</Form>
			</Stack>
		</div>
	)
}

export default Recovery
b
A message from kapa.ai
Sorry @bland-finland-95044, I seem to be having a bit of trouble. Don't worry though, I've pinged my support folks and they will try to fix me up! 🧑‍💻 Perhaps try again in 5mins?