diff --git a/.changeset/afraid-worms-pump.md b/.changeset/afraid-worms-pump.md
new file mode 100644
index 000000000..a36021199
--- /dev/null
+++ b/.changeset/afraid-worms-pump.md
@@ -0,0 +1,7 @@
+---
+"@frak-labs/nexus-example": patch
+"@frak-labs/nexus-wallet": patch
+"@frak-labs/nexus-sdk": patch
+---
+
+Add referral workflow
diff --git a/bun.lockb b/bun.lockb
index 049ba56d8..b3e30eb36 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/packages/example/src/module/article/component/Popup/index.module.css b/packages/example/src/module/article/component/Popup/index.module.css
new file mode 100644
index 000000000..632214a27
--- /dev/null
+++ b/packages/example/src/module/article/component/Popup/index.module.css
@@ -0,0 +1,39 @@
+.popup {
+ align-items: center;
+ color: #383f4e;
+ display: flex;
+ justify-content: center;
+ left: 0;
+ overflow: hidden;
+ position: fixed;
+ scroll-behavior: smooth;
+ bottom: 0;
+ width: 100%;
+ z-index: 10000001;
+ font-size: 16px;
+ line-height: 24px;
+}
+
+.popup__content {
+ background-color: #fff;
+ display: flex;
+ flex-direction: column;
+ max-height: calc(100% - 80px);
+ max-width: 978px;
+ overflow: visible;
+ margin: 10px;
+ padding: 10px;
+ position: relative;
+ width: 100%;
+ border-radius: 10px;
+ border: 1px solid #e5e5e5;
+}
+
+.popup__explanation {
+ color: #2a303b;
+ font-size: 18px;
+ line-height: 24px;
+ margin-bottom: 20px;
+ font-weight: 600;
+ text-align: center;
+}
diff --git a/packages/example/src/module/article/component/Popup/index.tsx b/packages/example/src/module/article/component/Popup/index.tsx
new file mode 100644
index 000000000..6874fd32e
--- /dev/null
+++ b/packages/example/src/module/article/component/Popup/index.tsx
@@ -0,0 +1,37 @@
+import css from "!!raw-loader!./index.module.css";
+import { frakWalletSdkConfig } from "@/context/frak-wallet/config";
+import { Button } from "@/module/common/component/Button";
+import type { Article } from "@/type/Article";
+
+export const cssRaw = css;
+
+function buildRedirectUrl(redirectUrl: string) {
+ const outputUrl = new URL(frakWalletSdkConfig.walletUrl);
+ outputUrl.pathname = "/register";
+ outputUrl.searchParams.set("redirectUrl", encodeURIComponent(redirectUrl));
+ return outputUrl.toString();
+}
+
+export function Popup({ article }: { article: Article }) {
+ return (
+
+
+
+ A Nexus user shared this link with you, create a Nexus
+ account to instantly get 50rFRK
+
+
+
+
+ );
+}
diff --git a/packages/example/src/module/article/component/Read/InjectBannerComponent.tsx b/packages/example/src/module/article/component/Read/InjectBannerComponent.tsx
index f120b671a..b1170a40d 100644
--- a/packages/example/src/module/article/component/Read/InjectBannerComponent.tsx
+++ b/packages/example/src/module/article/component/Read/InjectBannerComponent.tsx
@@ -20,7 +20,7 @@ export function InjectBannerComponent({
const articleIframeDocument = articleIframe?.contentWindow?.document;
useEffect(() => {
- const containerName = "frak-paywall";
+ const containerName = "frak-banner";
let containerRoot =
articleIframeDocument?.getElementById(containerName);
diff --git a/packages/example/src/module/article/component/Read/InjectPopupComponent.tsx b/packages/example/src/module/article/component/Read/InjectPopupComponent.tsx
new file mode 100644
index 000000000..31bbaa48a
--- /dev/null
+++ b/packages/example/src/module/article/component/Read/InjectPopupComponent.tsx
@@ -0,0 +1,71 @@
+import { Popup } from "@/module/article/component/Popup";
+import { cssRaw as cssRawButton } from "@/module/common/component/Button";
+import type { Article } from "@/type/Article";
+import { useEffect, useState } from "react";
+import { createPortal } from "react-dom";
+import { cssRaw } from "../Popup";
+
+export function InjectPopupComponent({
+ article,
+}: {
+ article: Article;
+}) {
+ const [containerRoot, setContainerRoot] = useState();
+
+ // Get the article's iframe
+ const articleIframeName = "frak-article-iframe";
+ const articleIframe = document.querySelector(
+ `#${articleIframeName}`
+ ) as HTMLIFrameElement;
+ const articleIframeDocument = articleIframe?.contentWindow?.document;
+
+ useEffect(() => {
+ const containerName = "frak-popup";
+ let containerRoot =
+ articleIframeDocument?.getElementById(containerName);
+
+ // If the container does not exist, create it
+ if (!containerRoot) {
+ const appRoot = document.createElement("div");
+ appRoot.id = containerName;
+ articleIframeDocument?.body?.insertAdjacentElement(
+ "beforeend",
+ appRoot
+ );
+ containerRoot =
+ articleIframeDocument?.getElementById(containerName);
+
+ if (containerRoot) {
+ containerRoot.style.width = "100%";
+ setContainerRoot(containerRoot);
+ }
+ }
+ }, [articleIframeDocument]);
+
+ if (
+ !(
+ articleIframe &&
+ articleIframeDocument &&
+ articleIframe.contentDocument
+ )
+ ) {
+ console.log(`iframe ${articleIframeName} not found`);
+ return null;
+ }
+
+ return (
+ containerRoot && (
+ <>
+ {createPortal(, containerRoot)}
+ {/* Inject the styles into the iframe */}
+ {createPortal(
+ ,
+ articleIframe.contentDocument.head
+ )}
+ >
+ )
+ );
+}
diff --git a/packages/example/src/module/article/component/Read/index.tsx b/packages/example/src/module/article/component/Read/index.tsx
index 0e0052f20..18702e6c1 100644
--- a/packages/example/src/module/article/component/Read/index.tsx
+++ b/packages/example/src/module/article/component/Read/index.tsx
@@ -1,10 +1,12 @@
import { InjectBannerComponent } from "@/module/article/component/Read/InjectBannerComponent";
+import { InjectPopupComponent } from "@/module/article/component/Read/InjectPopupComponent";
import { InjectUnlockComponent } from "@/module/article/component/Read/InjectUnlockComponent";
import { Skeleton } from "@/module/common/component/Skeleton";
import type { Article } from "@/type/Article";
import {
useArticleUnlockOptions,
useArticleUnlockStatus,
+ useNexusReferral,
useWalletStatus,
} from "@frak-labs/nexus-sdk/react";
import { useEffect, useState } from "react";
@@ -24,6 +26,11 @@ export function ReadArticle({
// The iframe reference
const [iframeRef, setIframeRef] = useState(null);
+ // The nexus referral
+ const { data: referral } = useNexusReferral({
+ contentId: article.contentId as Hex,
+ });
+
// The unlock options for the article
const { data: unlockOptions } = useArticleUnlockOptions({
articleId: article.id as Hex,
@@ -71,6 +78,9 @@ export function ReadArticle({
walletStatus?.key === "not-connected" && (
)}
+ {injecting > 0 && referral?.key === "referred-history" && (
+
+ )}
{articleUnlockStatus &&
articleUnlockStatus?.key !== "waiting-response" ? (