From 4669e591e31b38e213eb8e5f7739b01f89c0ed4d Mon Sep 17 00:00:00 2001 From: "zewei.zhang" Date: Wed, 6 Mar 2024 14:22:54 +0800 Subject: [PATCH] fix: remove useless code. --- src/app/api/chapters/[chapter_id]/up/route.ts | 118 -------------- src/app/api/upload/chapter/route.ts | 69 -------- src/app/api/upload/service/SDKTool.ts | 154 ------------------ src/app/api/upload/service/upload.ts | 104 ------------ src/app/chapters/[chapter_id]/ChapterList.tsx | 31 ---- .../[chapter_id]/EnterWalletAddress.tsx | 128 --------------- .../[chapter_id]/NewChapterTextarea.tsx | 76 --------- .../[chapter_id]/SubmitMethodChoose.tsx | 41 ----- src/app/chapters/[chapter_id]/SubmitSheet.tsx | 149 ----------------- src/app/chapters/[chapter_id]/page.tsx | 67 -------- src/app/chapters/page.tsx | 74 --------- src/app/graph/GraphChapters.tsx | 69 -------- src/app/og/graph/[highlight_id]/route.tsx | 106 ------------ src/app/tv/page.tsx | 42 ----- src/components/pages/GraphDesktopRender.tsx | 2 - src/components/pages/GraphMobileRender.tsx | 7 - 16 files changed, 1237 deletions(-) delete mode 100644 src/app/api/chapters/[chapter_id]/up/route.ts delete mode 100644 src/app/api/upload/chapter/route.ts delete mode 100644 src/app/api/upload/service/SDKTool.ts delete mode 100644 src/app/api/upload/service/upload.ts delete mode 100644 src/app/chapters/[chapter_id]/ChapterList.tsx delete mode 100644 src/app/chapters/[chapter_id]/EnterWalletAddress.tsx delete mode 100644 src/app/chapters/[chapter_id]/NewChapterTextarea.tsx delete mode 100644 src/app/chapters/[chapter_id]/SubmitMethodChoose.tsx delete mode 100644 src/app/chapters/[chapter_id]/SubmitSheet.tsx delete mode 100644 src/app/chapters/[chapter_id]/page.tsx delete mode 100644 src/app/chapters/page.tsx delete mode 100644 src/app/graph/GraphChapters.tsx delete mode 100644 src/app/og/graph/[highlight_id]/route.tsx delete mode 100644 src/app/tv/page.tsx diff --git a/src/app/api/chapters/[chapter_id]/up/route.ts b/src/app/api/chapters/[chapter_id]/up/route.ts deleted file mode 100644 index e27cab0..0000000 --- a/src/app/api/chapters/[chapter_id]/up/route.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { CfgDefaultValue } from "@/app/api/config"; -import { - CusEntityNotFoundError, - CusEnvVarsConfigError, - CusTypeError, - ErrorCode, - errorHandler, -} from "@/app/api/errorUtils"; -import { - ChapterMO, - queryChapterById, - queryChapterByIds, - queryChapterChildNodes, - queryChapterSiblingNodes, -} from "@/app/api/model"; -import { EnvKey, GetEnv } from "@/app/api/utils"; -import { Chapter } from "@/interface/chapter"; -import { NextRequest, NextResponse } from "next/server"; - -export const dynamic = "force-dynamic"; - -export async function GET( - request: NextRequest, - { params }: { params: { chapter_id: string } }, -): Promise { - const searchParams = request.nextUrl.searchParams; - - let chapters: Chapter[] = []; - - try { - const chapterId = params["chapter_id"]; - if (!chapterId || isNaN(Number(chapterId))) { - throw new CusTypeError( - ErrorCode.ChapterIDTypeError, - "chapter_id should be a number", - ); - } - - const depth = verifyDepth(searchParams.get("depth")); - let parentDepth = depth - 1; - - const lastChapter = await queryChapterById(Number(chapterId)); - if (depth > lastChapter.path.length) { - parentDepth = lastChapter.path.length; - } - - let totalChapter: ChapterMO[] = []; - if (parentDepth == 0) { - totalChapter.push(lastChapter); - } else { - const parentIds = lastChapter.path.slice(-parentDepth); - let parentChapters = await queryChapterByIds(parentIds); - if (parentChapters.length != parentDepth) { - return errorHandler( - new CusEntityNotFoundError( - ErrorCode.ChapterNotExistError, - `Chapter's parent nodes not found`, - ), - ); - } - parentChapters.push(lastChapter); - totalChapter.push(...parentChapters); - } - - chapters = await process(totalChapter); - } catch (err) { - return errorHandler(err as Error); - } - - return NextResponse.json({ chapters: chapters }); -} - -function verifyDepth(value: string | null): number { - let depth = value || CfgDefaultValue.ChapterUpDepthMinCount; - if (isNaN(Number(depth))) { - throw new CusTypeError( - ErrorCode.ChapterUpDepthTypeError, - "depth should be a number", - ); - } - - const maxDepth = - GetEnv(EnvKey.ChapterUpWithSelfMaxDepth) || - CfgDefaultValue.ChapterUpDepthMaxCount; - if (isNaN(Number(maxDepth))) { - throw new CusEnvVarsConfigError( - ErrorCode.ChapterUpDepthMaxError, - "max depth should be a number", - ); - } - - if (Number(depth) > Number(maxDepth)) { - throw new CusTypeError( - ErrorCode.ChapterUpDepthRangeError, - `depth should be less than ${maxDepth}`, - ); - } - - return Number(depth); -} - -async function process(chapters: ChapterMO[]): Promise { - let result: Chapter[] = []; - for (let i = 0; i < chapters.length; i++) { - let chapter = chapters[i]; - const children = await queryChapterChildNodes(chapter.id); - result.push({ - id: chapter.id, - story_id: chapter.story_id, - content: chapter.content, - parent_id: chapter.parent_id, - wallet_address: chapter.wallet_address, - path: chapter.path, - child_count: children.length, - } as Chapter); - } - return result; -} diff --git a/src/app/api/upload/chapter/route.ts b/src/app/api/upload/chapter/route.ts deleted file mode 100644 index 5977d16..0000000 --- a/src/app/api/upload/chapter/route.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { NextRequest } from "next/server"; -import { uploadChapter, uploadRelationship } from "../service/upload"; -import { - queryUploadStatistics, - updateUploadStatistics, - UploadStatisticMO, -} from "../../model"; - -export const dynamic = "force-dynamic"; -export const maxDuration = 300; - -const uploadTotal = process.env.UPLOAD_TOTAL || "10"; -const uploadInterval = process.env.UPLOAD_INTERVAL || "15"; -const isOpen = process.env.IS_UPLOAD_OPEN || "false"; - -export async function GET(request: NextRequest): Promise { - if (isOpen === "false") { - const response = { - result: "reject", - message: "Upload is not open", - }; - return Response.json(response); - } - - const now = Date.now(); - const uploadStatistics: UploadStatisticMO = await queryUploadStatistics(); - console.log( - `Last upload time: ${uploadStatistics.lastUploadTime}, now: ${now}`, - ); - - if ( - now - uploadStatistics.lastUploadTime < - 1000 * 60 * parseInt(uploadInterval) - ) { - const response = { - result: "reject", - message: "Upload too frequently", - }; - return Response.json(response); - } - - const total = parseInt(uploadTotal); - const chapterResult: number = await uploadChapter(total); - const relationshipResult: number = await uploadRelationship( - total, - "PREVIOUS_CHAPTER", - ); - const response = { - result: "success", - message: `Upload result: ${chapterResult} chapters, ${relationshipResult} relationships`, - }; - await updateUploadStatistics({ - id: uploadStatistics.id, - lastUploadTime: now, - storyUploaded: uploadStatistics.storyUploaded, - chapterUploaded: sum(uploadStatistics.chapterUploaded, chapterResult), - relationshipUploaded: sum( - uploadStatistics.relationshipUploaded, - relationshipResult, - ), - }); - return Response.json(response); -} - -function sum(a: number | string, b: number | string): number { - const aNum = typeof a === "string" ? parseInt(a) : a; - const bNum = typeof b === "string" ? parseInt(b) : b; - return aNum + bNum; -} diff --git a/src/app/api/upload/service/SDKTool.ts b/src/app/api/upload/service/SDKTool.ts deleted file mode 100644 index fd6c6ce..0000000 --- a/src/app/api/upload/service/SDKTool.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { privateKeyToAccount } from "viem/accounts"; -import { Chain, Transport, Hex } from "viem"; -import { StoryClient, Client } from "@story-protocol/core-sdk"; -import { - CreateIpAssetResponse, - CreateIpAssetRequest, -} from "@story-protocol/core-sdk"; -import { - CreateIPOrgResponse, - CreateIPOrgRequest, -} from "@story-protocol/core-sdk"; -import { - RegisterRelationshipTypeRequest, - RegisterRelationshipTypeResponse, -} from "@story-protocol/core-sdk"; -import { - RegisterRelationshipRequest, - RegisterRelationshipResponse, -} from "@story-protocol/core-sdk"; - -export interface RegisterIPOrgParams { - name: string; - symbol: string; - owner?: string; - assetTypes: string[]; -} - -export interface RegisterIPOrgRelationTypeParams { - relType: string; - ipOrg?: string; - allowedElements: { - src: number; - dst: number; - }; - allowedSrcs: number[]; - allowedDsts: number[]; -} - -export interface RegisterIPAssetParams { - orgAddress: string; - owner?: string; - name: string; - ipAssetType: number; - hash?: `0x${string}`; - mediaUrl?: string; -} - -export interface RelationshipParams { - orgAddress: string; - relType: string; - srcAddress: string; - srcId: string; - dstAddress: string; - dstId: string; -} - -export class SDKTool { - public accountAddress: string; - public client: Client; - - constructor(privateKey: Hex, chain?: Chain, transport?: Transport) { - const account = privateKeyToAccount(privateKey); - this.client = StoryClient.newClient({ - account, - chain, - transport, - }); - this.accountAddress = account.address; - } - - public createIPOrg( - orgItem: RegisterIPOrgParams, - ): Promise { - const params: CreateIPOrgRequest = { - name: orgItem.name, - symbol: orgItem.symbol, - owner: orgItem.owner, - ipAssetTypes: orgItem.assetTypes, - txOptions: { - waitForTransaction: true, - }, - }; - return this.client.ipOrg.create(params); - } - - public createIPOrgRelationType( - item: RegisterIPOrgRelationTypeParams, - ): Promise { - if (!item.ipOrg) { - // fileLogger.error(`The ipOrg field is absent or not provided: ${JSON.stringify(item)}}`); - throw new Error("The ipOrg field is absent or not provided."); - } - const params: RegisterRelationshipTypeRequest = { - ipOrgId: item.ipOrg, - relType: item.relType, - relatedElements: { - src: item.allowedElements.src, - dst: item.allowedElements.dst, - }, - allowedSrcIpAssetTypes: item.allowedSrcs, - allowedDstIpAssetTypes: item.allowedDsts, - preHooksConfig: [], - postHooksConfig: [], - txOptions: { - waitForTransaction: true, - }, - }; - console.log(`params: ${JSON.stringify(params)}`); - return this.client.relationshipType.register(params); - } - - public createIPAsset( - item: RegisterIPAssetParams, - ): Promise { - const params: CreateIpAssetRequest = { - name: item.name, - typeIndex: item.ipAssetType, - ipOrgId: item.orgAddress, - owner: this.accountAddress, - mediaUrl: item.mediaUrl, - contentHash: item.hash, - txOptions: { - waitForTransaction: true, - }, - }; - console.log(`params: ${JSON.stringify(params)}`); - return this.client.ipAsset.create(params); - } - - public createRelationship( - item: RelationshipParams, - ): Promise { - const params: RegisterRelationshipRequest = { - ipOrgId: item.orgAddress, - relType: item.relType, - srcContract: item.srcAddress, - srcTokenId: item.srcId, - dstContract: item.dstAddress, - dstTokenId: item.dstId, - preHookData: [], - postHookData: [], - txOptions: { - waitForTransaction: true, - }, - }; - return this.client.relationship.register(params); - } - - public async uploadMetadata(content: string): Promise { - const file = Buffer.from(content); - const { uri } = await this.client.platform.uploadFile(file, "text/plain"); - return uri; - } -} diff --git a/src/app/api/upload/service/upload.ts b/src/app/api/upload/service/upload.ts deleted file mode 100644 index 9932d51..0000000 --- a/src/app/api/upload/service/upload.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { sepolia } from "viem/chains"; -import { Hex, http, keccak256, toHex, isAddress } from "viem"; -import { - queryIPAsset, - updateAsset, - queryRelationship, - updateRelationship, -} from "../../model"; -import { SDKTool } from "./SDKTool"; - -if (!process.env.PRIVATE_KEY || !process.env.RPC_URL) - throw new Error("No PRIVATE_KEY or RPC_URL found in environment variables"); - -if (!process.env.IP_ORG_ID) - throw new Error("No IP_ORG_ID found in environment variables"); -const ipOrg = process.env.IP_ORG_ID; - -if (!process.env.NEXT_PUBLIC_IP_ASSET_REGISTRY_CONTRACT) - throw new Error( - "No NEXT_PUBLIC_IP_ASSET_REGISTRY_CONTRACT found in environment variables", - ); -const registryAddress = process.env.NEXT_PUBLIC_IP_ASSET_REGISTRY_CONTRACT; - -const sdkTool = new SDKTool( - process.env.PRIVATE_KEY as Hex, - sepolia, - http(process.env.RPC_URL), -); - -export async function uploadChapter(num: number): Promise { - const chapters = await queryIPAsset(num, 1); - if (chapters.length === 0) return 0; - - console.log(`Uploading Chapters : ${chapters.length}`); - - for (const chapter of chapters) { - const metadata_raw = { - name: chapter.name, - description: chapter.description, - author: chapter.belong_to || "Anonymous", - }; - const metadata = JSON.stringify(metadata_raw); - const metadata_url = await sdkTool.uploadMetadata(metadata); - console.log(`Metadata URL: ${metadata_url}`); - const contentHash = keccak256(toHex(metadata)); - console.log(`Content Hash: ${contentHash}`); - const response = await sdkTool.createIPAsset({ - name: chapter.name, - ipAssetType: chapter.asset_type, - orgAddress: ipOrg, - // owner: isAddress(chapter.belong_to || "") ? chapter.belong_to : undefined, // the owner must be the sender - hash: contentHash, - mediaUrl: metadata_url, - }); - console.log(`IP Asset ${chapter.id} Response: ${JSON.stringify(response)}`); - await updateAsset({ - ...chapter, - status: 1, - tx_hash: response.txHash, - asset_seq_id: response.ipAssetId, - metadata_url: metadata_url, - }); - } - - return chapters.length; -} - -export async function uploadRelationship( - num: number, - relationshipType: string = "PREVIOUS", -): Promise { - const relationships = await queryRelationship(num, relationshipType); - if (relationships.length === 0) return 0; - - const finalRelationships = relationships.filter( - (relationship) => relationship.src_asset && relationship.dst_asset, - ); - if (finalRelationships.length === 0) return 0; - - console.log( - `Found relationships ${relationships.length}, valid relationships: ${finalRelationships.length}`, - ); - - for (const relationship of finalRelationships) { - const response = await sdkTool.createRelationship({ - orgAddress: ipOrg, - relType: relationship.relationship_type, - srcAddress: registryAddress, - srcId: relationship.src_asset ? relationship.src_asset.toString() : "", - dstAddress: registryAddress, - dstId: relationship.dst_asset ? relationship.dst_asset.toString() : "", - }); - console.log( - `Relationship ${relationship.id} Response: ${JSON.stringify(response)}`, - ); - await updateRelationship({ - ...relationship, - status: 1, - tx_hash: response.txHash, - relationship_seq_id: response.relationshipId, - }); - } - return finalRelationships.length; -} diff --git a/src/app/chapters/[chapter_id]/ChapterList.tsx b/src/app/chapters/[chapter_id]/ChapterList.tsx deleted file mode 100644 index eaefb91..0000000 --- a/src/app/chapters/[chapter_id]/ChapterList.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import ChapterSkeleton from "@/components/pages/ChapterSkeleton"; -import ChapterItem from "@/components/pages/ChapterItem"; -import { Chapter } from "@/interface/chapter"; - -export default function ChapterList({ - isLoading, - chapterListData, - isHighLight, -}: { - isLoading: boolean; - chapterListData: Chapter[]; - isHighLight?: boolean; -}) { - return isLoading ? ( - - ) : ( - <> - {chapterListData.slice(0, chapterListData.length - 1).map((chapter) => ( - - ))} - {chapterListData.slice(-1).map((chapter) => ( - - ))} - - ); -} diff --git a/src/app/chapters/[chapter_id]/EnterWalletAddress.tsx b/src/app/chapters/[chapter_id]/EnterWalletAddress.tsx deleted file mode 100644 index 7b4261d..0000000 --- a/src/app/chapters/[chapter_id]/EnterWalletAddress.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { Button } from "@/components/ui/button"; -import TextareaAutosize from "react-textarea-autosize"; -import Image from "next/image"; -import arrowRightBlack from "@/assets/common/arrow_right_black.svg"; -import { useEffect, useRef, useState } from "react"; -import { - cn, - temporaryRepairIosKeyboard, - temporaryRepairIosKeyboardFocus, -} from "@/lib/utils"; -import { createPublicClient, http, isAddress } from "viem"; -import { mainnet } from "viem/chains"; -import { ReloadIcon } from "@radix-ui/react-icons"; - -const client = createPublicClient({ - chain: mainnet, - transport: http(), -}); - -export default function EnterWalletAddress({ - walletOrEns, - setWalletAddress, - setRealWalletAddress, - onSubmit, -}: { - walletOrEns: string; - setWalletAddress: (walletAddress: string) => void; - setRealWalletAddress: (walletAddress: string) => void; - onSubmit: () => void; -}) { - const [isValid, setIsValid] = useState(false); - const [isResolving, setIsResolving] = useState(false); - const walletAddressRef = useRef(null); - - useEffect(() => { - let isCanceled = false; - - async function getRealAddress(walletOrEnsAddress: string) { - if (walletOrEnsAddress.endsWith(".eth")) { - return await client.getEnsAddress({ name: walletOrEnsAddress }); - } else { - return walletOrEnsAddress; - } - } - - setIsResolving(true); - getRealAddress(walletOrEns).then( - (realAddress) => { - if (isCanceled) { - return; - } - setRealWalletAddress(realAddress as string); - setIsValid(isAddress(realAddress as string)); - setIsResolving(false); - }, - (e) => { - if (isCanceled) { - return; - } - setRealWalletAddress(""); - setIsValid(false); - setIsResolving(false); - }, - ); - - return () => { - isCanceled = true; - }; - }, [setRealWalletAddress, walletOrEns]); - - return ( -
-

- Enter the wallet address you would like to use for both story - attribution and receipt of your commemorative NFT. -

- -
- - { - const current = walletAddressRef.current; - if (current) { - current.scrollTop = current?.scrollHeight || 0; - } - setWalletAddress(e.target.value); - }} - onBlur={() => temporaryRepairIosKeyboard()} - onFocus={() => temporaryRepairIosKeyboardFocus()} - /> -
- {isResolving ? ( - - ) : ( - !!walletOrEns && - !isValid && ( - Enter a valid address - ) - )} - - -
-
-
- ); -} diff --git a/src/app/chapters/[chapter_id]/NewChapterTextarea.tsx b/src/app/chapters/[chapter_id]/NewChapterTextarea.tsx deleted file mode 100644 index 2c78bab..0000000 --- a/src/app/chapters/[chapter_id]/NewChapterTextarea.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Button } from "@/components/ui/button"; -import Image from "next/image"; -import TextareaAutosize from "react-textarea-autosize"; -import arrowRightBlack from "@/assets/common/arrow_right_black.svg"; -import { useState } from "react"; -import { - cn, - temporaryRepairIosKeyboard, - temporaryRepairIosKeyboardFocus, -} from "@/lib/utils"; - -export default function NewChapterTextarea({ - isLoading, - onSubmit, - maxLength = 280, -}: { - isLoading: boolean; - onSubmit: (context: string) => void; - maxLength?: number; -}) { - const [newContent, setNewContent] = useState(""); - - if (isLoading) { - return null; - } - - const length = newContent.length; - const isOverLimit = length > maxLength; - - return ( - <> -
- continue the story... -
- -
- setNewContent(e.target.value)} - onBlur={() => temporaryRepairIosKeyboard()} - onFocus={() => temporaryRepairIosKeyboardFocus()} - /> -
- {maxLength && ( - - {length}/{maxLength} - - )} - -
-
- - ); -} diff --git a/src/app/chapters/[chapter_id]/SubmitMethodChoose.tsx b/src/app/chapters/[chapter_id]/SubmitMethodChoose.tsx deleted file mode 100644 index 1dbfd53..0000000 --- a/src/app/chapters/[chapter_id]/SubmitMethodChoose.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Button } from "@/components/ui/button"; - -export default function SubmitMethodChoose({ - toWallet, - toAnonymously, - isSubmitting, -}: { - toWallet: () => void; - toAnonymously: () => void; - isSubmitting?: boolean; -}) { - return ( -
-

- Would you like credit for your addition? -
-
- In addition getting attribution for your addition, we’ll airdrop you a - commemorative NFT for participating. -

-
- -
-
- -
-
- ); -} diff --git a/src/app/chapters/[chapter_id]/SubmitSheet.tsx b/src/app/chapters/[chapter_id]/SubmitSheet.tsx deleted file mode 100644 index 47f6273..0000000 --- a/src/app/chapters/[chapter_id]/SubmitSheet.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import SubmitMethodChoose from "@/app/chapters/[chapter_id]/SubmitMethodChoose"; -import { useEffect, useState } from "react"; -import EnterWalletAddress from "@/app/chapters/[chapter_id]/EnterWalletAddress"; -import { useRouter } from "next/navigation"; -import { Sheet, SheetContent } from "@/components/ui/sheet"; -import FooterLogo from "@/components/pages/FooterLogo"; -import { CreateChapterRequest } from "@/interface/createChapterRequest"; -import { CreateChapterResponse } from "@/interface/createChapterResponse"; -import Spinner from "@/components/pages/Spinner"; -import { X } from "lucide-react"; -import NetworkErrorAlert from "@/components/pages/NetworkErrorAlert"; -import axios from "axios"; -import { ErrorResponse } from "@/interface/errorResponse"; -import { formatError } from "@/lib/fetcher"; -import OnchainChronicles from "@/components/pages/OnchainChronicles"; - -export default function SubmitSheet({ - open, - onOpenChange, - chapterId, - storyId, - content, -}: { - open: boolean; - onOpenChange: (open: boolean) => void; - chapterId: string; - storyId: string; - content: string; -}) { - const router = useRouter(); - const [isSubmitting, setIsSubmitting] = useState(false); - const [showWallet, setShowWallet] = useState(false); - const [error, setError] = useState(null); - const [walletOrEnsAddress, setWalletOrEnsAddress] = useState(""); - const [realWalletAddress, setRealWalletAddress] = useState(""); - - useEffect(() => { - if (!open) { - setShowWallet(false); - } - }, [open]); - - const submitNewChapter = async ( - parentId: string, - content: string, - walletAddress?: string, - ) => { - const requestBody: CreateChapterRequest = { - story_id: Number(storyId), - is_anonymous: !walletAddress, - parent_id: Number(parentId), - wallet_address: walletAddress || undefined, - content: content, - }; - setIsSubmitting(true); - try { - const response = await axios.post( - `/api/chapters`, - requestBody, - ); - sessionStorage.setItem("isSubmit", "true"); - /** - * Redirect to the graph page need times when the network is slow - * So we didn't setIsSubmitting(false) to keep the loading spinner - */ - router.push( - `/graph?highlight_id=${response.data.id}×tamp=${new Date().getTime()}`, - ); - } catch (e) { - console.error("Failed to create chapter", e); - setIsSubmitting(false); - setError(formatError(e)); - } - }; - - const closeSheet = () => { - if (showWallet) { - setShowWallet(false); - return; - } - - onOpenChange(false); - }; - - if (open && !storyId) { - return ; - } - - return ( - - -
-
- -
- -
- {isSubmitting && } - - {showWallet ? ( - { - await submitNewChapter(chapterId, content, realWalletAddress); - }} - /> - ) : ( - { - setShowWallet(true); - }} - toAnonymously={async () => { - await submitNewChapter(chapterId, content); - }} - /> - )} - -
-
- - {error && ( -
- { - await submitNewChapter(chapterId, content, realWalletAddress); - }} - isValidating={isSubmitting} - /> -
- )} - -
- - Close -
-
-
- ); -} diff --git a/src/app/chapters/[chapter_id]/page.tsx b/src/app/chapters/[chapter_id]/page.tsx deleted file mode 100644 index a8d9c29..0000000 --- a/src/app/chapters/[chapter_id]/page.tsx +++ /dev/null @@ -1,67 +0,0 @@ -"use client"; - -import Link from "next/link"; -import arrowLeftIcon from "@/assets/common/arrow_left.svg"; -import Image from "next/image"; -import useSWR from "swr"; -import { ChapterListResponse } from "@/interface/chapterListResponse"; -import ChapterList from "./ChapterList"; -import NewChapterTextarea from "./NewChapterTextarea"; -import SubmitSheet from "./SubmitSheet"; -import { useState } from "react"; -import { ErrorResponse } from "@/lib/fetcher"; -import NetworkErrorAlert from "@/components/pages/NetworkErrorAlert"; -import ClearGraphPage from "@/components/pages/ClearGraphPage"; - -export default function Page({ params }: { params: { chapter_id: string } }) { - const chapterId = params.chapter_id; - const [open, setOpen] = useState(false); - const [preparedContent, setPreparedContent] = useState(""); - - const { data, isLoading, isValidating, error, mutate } = useSWR< - ChapterListResponse, - ErrorResponse - >(`/api/chapters/${chapterId}/up`); - - const chapterListData = data?.chapters || []; - chapterListData.sort((a, b) => a.id - b.id); - const storyId = chapterListData[0]?.story_id?.toString() || ""; - - const onSubmit = (newContent: string) => { - setPreparedContent(newContent); - setOpen(true); - }; - - return ( -
-
- - {"back"} - Back to Selection - - - - - - - - - -
- -
- ); -} diff --git a/src/app/chapters/page.tsx b/src/app/chapters/page.tsx deleted file mode 100644 index 7e8ae26..0000000 --- a/src/app/chapters/page.tsx +++ /dev/null @@ -1,74 +0,0 @@ -"use client"; - -import useSWR from "swr"; -import { ChapterListResponse } from "@/interface/chapterListResponse"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import ChapterItem from "@/components/pages/ChapterItem"; -import { Button } from "@/components/ui/button"; -import Image from "next/image"; -import shuffleIcon from "@/assets/chapter/shuffle_icon.svg"; -import ChapterSkeleton from "@/components/pages/ChapterSkeleton"; -import Spinner from "@/components/pages/Spinner"; -import React from "react"; -import NetworkErrorAlert from "@/components/pages/NetworkErrorAlert"; -import arrowLeftIcon from "@/assets/common/arrow_left.svg"; - -export default function Page() { - const router = useRouter(); - const { data, isLoading, isValidating, error, mutate } = - useSWR("/api/chapters/random", { - revalidateOnFocus: false, - }); - const chaptersListData = data?.chapters || []; - - return ( -
-
-
{ - if (sessionStorage.getItem("isGraphPage") === "true") { - router.push(`/graph?timestamp=${new Date().getTime()}`); - } else { - router.push(`/`); - } - }} - > - {"back"} - Back -
-
Choose a story to continue...
- - - - {isLoading ? ( - - ) : ( - chaptersListData.map((chapter) => ( - - - - )) - )} - - {!isLoading && isValidating && } - -
- -
-
-
- ); -} diff --git a/src/app/graph/GraphChapters.tsx b/src/app/graph/GraphChapters.tsx deleted file mode 100644 index 17e79a1..0000000 --- a/src/app/graph/GraphChapters.tsx +++ /dev/null @@ -1,69 +0,0 @@ -"use client"; - -import NetworkErrorAlert from "@/components/pages/NetworkErrorAlert"; -import { ChapterListResponse } from "@/interface/chapterListResponse"; -import { ErrorResponse } from "@/lib/fetcher"; -import useSWR from "swr"; -import ChapterList from "../chapters/[chapter_id]/ChapterList"; -import SuccessAlert from "@/components/pages/SuccessAlert"; - -export default function GraphChapters({ - chapterId, - className, -}: { - chapterId?: string; - className?: string; -}) { - const { data, isLoading, isValidating, error, mutate } = useSWR< - ChapterListResponse, - ErrorResponse - >(`/api/chapters/${chapterId}/up?depth=1000`); - - const chapterListData = data?.chapters || []; - chapterListData.sort((a, b) => a.id - b.id); - - if (!isLoading) { - setTimeout(() => { - sessionStorage.setItem("isSubmit", ""); - }, 2000); - } - - return ( -
- {chapterId ? ( - <> - - {!error && - !isValidating && - sessionStorage.getItem("isSubmit") === "true" ? ( - - ) : ( - <> - )} - {!isValidating ? ( -
The story so far...
- ) : ( - <> - )} - - - ) : ( - <> - )} -
- ); -} diff --git a/src/app/og/graph/[highlight_id]/route.tsx b/src/app/og/graph/[highlight_id]/route.tsx deleted file mode 100644 index f30094a..0000000 --- a/src/app/og/graph/[highlight_id]/route.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { init } from "echarts"; -import { ImageResponse } from "next/og"; -import { queryChaptersAfterID } from "@/app/api/chapters/relationship/server"; -import { generateChartData, generateChartOption } from "@/lib/chartUtils"; -import { NextRequest } from "next/server"; -import { createCanvas, registerFont } from "canvas"; -import path from "path"; - -export const dynamic = "force-dynamic"; -export const maxDuration = 60; - -export async function GET( - request: NextRequest, - { - params, - }: { - params: { - highlight_id: string; - }; - }, -) { - const { width, height } = { width: 1200, height: 630 }; - const highlightId = params.highlight_id; - const response = await queryChaptersAfterID({ - from_chapter_id: 0, - limit: 100000, - }); - - /** - * There are two ways to generate Echarts images on the server-side. - * - * By default, Echarts generates images in SVG format. However, when - * converting SVG to PNG using ImageResponse, the text inside the SVG is not - * supported. This results in the "You" tag not being displayed correctly. - * - * Another option is to use canvas to render Echarts(What we used currently). - * It works fine in local testing, but when deploying to Vercel, which is a - * serverless hosting platform, there is an issue with fonts. Since the - * serverless server does not include any font files, we need to manually - * register the corresponding font files definitely. - */ - const canvas = createCanvas(width, height); - const file = path.resolve( - process.cwd(), - "src/assets/fonts/Roboto-Regular.ttf", - ); - - registerFont(file, { - family: "Roboto", - }); - const chart = init(canvas as unknown as HTMLElement); - const chartData = generateChartData( - response.chapters.slice(0, 250).concat(response.chapters.slice(-250)), - ); - const chartOptions = generateChartOption({ - chartData, - highlightId, - isMediumDevice: true, - }); - - /** - * Disable animation to avoid the "You" tag not being displayed correctly. - */ - chartOptions.animation = false; - chartOptions.series.forEach((item) => { - item.animation = false; - item.force.layoutAnimation = false; - }); - - chart.setOption(chartOptions); - const dataURL = canvas.toDataURL("image/png"); - chart.dispose(); - - return new ImageResponse( - ( -
- {/* eslint-disable-next-line @next/next/no-img-element */} - {""} - {/* eslint-disable-next-line @next/next/no-img-element */} - -
- ), - { - width: width, - height: height, - }, - ); -} diff --git a/src/app/tv/page.tsx b/src/app/tv/page.tsx deleted file mode 100644 index c2127b6..0000000 --- a/src/app/tv/page.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import GraphChart from "@/components/pages/GraphChart"; -import QRCode from "react-qr-code"; -import { envConfig } from "@/lib/envConfig"; - -export default async function Page() { - const getHostname = (url: string) => { - try { - const urlObj = new URL(url); - return `${urlObj.hostname}${urlObj.pathname}`; - } catch { - return ""; - } - }; - return ( -
-
-
-
- Continue the story at -
-
- {getHostname(envConfig.QR_CODE_TV || "")} -
- {envConfig.QR_CODE_TV ? ( - - ) : ( - <> - Please set the QR code address environment variable: - NEXT_PUBLIC_QR_CODE_TV - - )} -
-
- -
- ); -} diff --git a/src/components/pages/GraphDesktopRender.tsx b/src/components/pages/GraphDesktopRender.tsx index d0d6751..e3ea436 100644 --- a/src/components/pages/GraphDesktopRender.tsx +++ b/src/components/pages/GraphDesktopRender.tsx @@ -1,4 +1,3 @@ -import GraphChapters from "@/app/graph/GraphChapters"; import GraphChart from "./GraphChart"; import OnchainChronicles from "./OnchainChronicles"; import ShareStory from "./ShareStory"; @@ -32,7 +31,6 @@ export default function GraphDesktopRender(props: GraphDesktopRenderProps) { />
-