Skip to content

Commit

Permalink
Support open frames button postUrl
Browse files Browse the repository at this point in the history
  • Loading branch information
rygine committed Jul 26, 2024
1 parent 31e7106 commit 0ba7278
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 74 deletions.
42 changes: 21 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@headlessui/react": "^1.4.3",
"@heroicons/react": "^1.0.5",
"@ipld/car": "^5.2.5",
"@open-frames/proxy-client": "0.3.3",
"@rainbow-me/rainbowkit": "^2.0.1",
"@tanstack/react-query": "^5.24.1",
"@wagmi/connectors": "^4.1.14",
Expand All @@ -43,7 +44,7 @@
"@xmtp/content-type-remote-attachment": "^1.1.4",
"@xmtp/content-type-reply": "^1.1.5",
"@xmtp/experimental-content-type-screen-effect": "^1.0.2",
"@xmtp/frames-client": "0.4.2",
"@xmtp/frames-client": "0.5.4",
"@xmtp/react-sdk": "^5.1.0",
"buffer": "^6.0.3",
"date-fns": "^2.29.3",
Expand Down Expand Up @@ -73,7 +74,6 @@
"zustand": "^4.3.2"
},
"devDependencies": {
"@open-frames/proxy-client": "0.2.0",
"@tailwindcss/forms": "^0.5.7",
"@types/lodash": "^4.14.202",
"@types/node": "^20.11.24",
Expand Down
35 changes: 24 additions & 11 deletions src/component-library/components/Frame/Frame.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { ArrowCircleRightIcon } from "@heroicons/react/outline";
import type { FrameButton } from "../../../helpers/frameInfo";
import type {
OpenFrameButton,
OpenFrameResult,
} from "@open-frames/proxy-client";
import { classNames } from "../../../helpers";
import { ButtonLoader } from "../Loaders/ButtonLoader";

type FrameProps = {
image: string;
title: string;
textInput?: string;
buttons: FrameButton[];
buttons: OpenFrameResult["buttons"];
handleClick: (
buttonNumber: number,
action?: FrameButton["action"],
action?: OpenFrameButton["action"],
) => Promise<void>;
onTextInputChange: (value: string) => void;
frameButtonUpdating: number;
Expand Down Expand Up @@ -77,23 +80,33 @@ const FrameButtonContainer = ({
);
};

type ButtonsContainerProps = Pick<
FrameProps,
"frameButtonUpdating" | "handleClick"
> & {
buttons: NonNullable<OpenFrameResult["buttons"]>;
};

const ButtonsContainer = ({
frameButtonUpdating,
buttons,
handleClick,
}: Pick<FrameProps, "frameButtonUpdating" | "buttons" | "handleClick">) => {
if (buttons.length < 1 || buttons.length > 4) {
}: ButtonsContainerProps) => {
if (Object.keys(buttons).length < 1 || Object.keys(buttons).length > 4) {
return null;
}
// If there is only one button make it full-width
const gridColumns = buttons.length === 1 ? "grid-cols-1" : "grid-cols-2";
const gridColumns =
Object.keys(buttons).length === 1 ? "grid-cols-1" : "grid-cols-2";
return (
<div className={`grid ${gridColumns} gap-2 w-full pt-2`}>
{buttons.map((button, index) => {
{Object.keys(buttons).map((key, index) => {
const button = buttons[key];
const buttonIndex = parseInt(key, 10);
const clickHandler = () => {
void handleClick(button.buttonIndex, button.action);
void handleClick(buttonIndex, button.action);
};
const isFullWidth = buttons.length === 3 && index === 2;
const isFullWidth = Object.keys(buttons).length === 3 && index === 2;
return (
<FrameButtonContainer
key={button.label}
Expand All @@ -102,7 +115,7 @@ const ButtonsContainer = ({
isExternalLink={["post_redirect", "link"].includes(
button.action || "",
)}
isLoading={frameButtonUpdating === button.buttonIndex}
isLoading={frameButtonUpdating === buttonIndex}
isDisabled={frameButtonUpdating > 0}
clickHandler={clickHandler}
/>
Expand Down Expand Up @@ -139,7 +152,7 @@ export const Frame = ({
/>
)}
<div className="flex flex-col items-center">
{interactionsEnabled && buttons.length ? (
{interactionsEnabled && buttons ? (
<ButtonsContainer
frameButtonUpdating={frameButtonUpdating}
handleClick={handleClick}
Expand Down
20 changes: 9 additions & 11 deletions src/controllers/FullMessageController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ import type { CachedConversation, CachedMessageWithId } from "@xmtp/react-sdk";
import { useClient } from "@xmtp/react-sdk";
import { FramesClient } from "@xmtp/frames-client";
import { useEffect, useState } from "react";
import type { GetMetadataResponse } from "@open-frames/proxy-client";
import type {
GetMetadataResponse,
OpenFrameButton,
} from "@open-frames/proxy-client";
import { FullMessage } from "../component-library/components/FullMessage/FullMessage";
import { classNames, shortAddress } from "../helpers";
import MessageContentController from "./MessageContentController";
import { useXmtpStore } from "../store/xmtp";
import { Frame } from "../component-library/components/Frame/Frame";
import { readMetadata } from "../helpers/openFrames";
import type { FrameButton } from "../helpers/frameInfo";
import {
getFrameTitle,
getOrderedButtons,
isValidFrame,
isXmtpFrame,
} from "../helpers/frameInfo";
import { getFrameTitle, isValidFrame, isXmtpFrame } from "../helpers/frameInfo";

interface FullMessageControllerProps {
message: CachedMessageWithId;
Expand All @@ -40,7 +37,7 @@ export const FullMessageController = ({

const handleFrameButtonClick = async (
buttonIndex: number,
action: FrameButton["action"] = "post",
action: OpenFrameButton["action"] = "post",
) => {
if (!frameMetadata || !client || !frameMetadata?.frameInfo?.buttons) {
return;
Expand All @@ -54,7 +51,8 @@ export const FullMessageController = ({
setFrameButtonUpdating(buttonIndex);

const framesClient = new FramesClient(client);
const postUrl = button.target || frameInfo.postUrl || frameUrl;
const postUrl =
button.target || button.postUrl || frameInfo.postUrl || frameUrl;
const payload = await framesClient.signFrameAction({
frameUrl,
inputText: textInputValue || undefined,
Expand Down Expand Up @@ -135,7 +133,7 @@ export const FullMessageController = ({
<Frame
image={frameMetadata?.frameInfo?.image.content}
title={getFrameTitle(frameMetadata)}
buttons={getOrderedButtons(frameMetadata)}
buttons={frameMetadata?.frameInfo?.buttons}
handleClick={handleFrameButtonClick}
frameButtonUpdating={frameButtonUpdating}
interactionsEnabled={isXmtpFrame(frameMetadata)}
Expand Down
27 changes: 1 addition & 26 deletions src/helpers/frameInfo.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,8 @@
import type {
GetMetadataResponse,
OpenFrameButton,
} from "@open-frames/proxy-client";
import type { GetMetadataResponse } from "@open-frames/proxy-client";
import { PROTOCOL_VERSION } from "@xmtp/frames-client";

const OG_TITLE_TAG = "og:title";

export type FrameButton = OpenFrameButton & { buttonIndex: number };

export function getOrderedButtons(
metadata: GetMetadataResponse,
): FrameButton[] {
const buttonMap = metadata?.frameInfo?.buttons;

if (!buttonMap) {
return [];
}

return Object.keys(buttonMap)
.sort()
.map((key) => {
const button = buttonMap[key];
return {
...button,
buttonIndex: parseInt(key, 10),
};
});
}

export function isXmtpFrame(metadata: GetMetadataResponse): boolean {
const minXmtpVersion = metadata.frameInfo?.acceptedClients?.xmtp;

Expand Down
5 changes: 2 additions & 3 deletions src/helpers/openFrames.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { OpenFramesProxy, type FramesApiResponse } from "@xmtp/frames-client";
import { OpenFramesProxy } from "@xmtp/frames-client";

const proxy = new OpenFramesProxy();
const BUTTON_INDEX_REGEX = /fc:frame:button:(\d)(?:$|:).*/;

export const readMetadata = async (url: string): Promise<FramesApiResponse> =>
proxy.readMetadata(url);
export const readMetadata = async (url: string) => proxy.readMetadata(url);

export const mediaUrl = (url: string): string => proxy.mediaUrl(url);

Expand Down

0 comments on commit 0ba7278

Please sign in to comment.