diff --git a/src/typescript/frontend/src/app/launch/page.tsx b/src/typescript/frontend/src/app/launch/page.tsx index ba7c4ad61..4714e39eb 100644 --- a/src/typescript/frontend/src/app/launch/page.tsx +++ b/src/typescript/frontend/src/app/launch/page.tsx @@ -2,11 +2,13 @@ import { REVALIDATION_TIME } from "lib/server-env"; import ClientLaunchEmojicoinPage from "../../components/pages/launch-emojicoin/ClientLaunchEmojicoinPage"; import { isUserGeoblocked } from "utils/geolocation"; import { headers } from "next/headers"; +import { fetchRandomNames } from "@/queries/launch"; export const revalidate = REVALIDATION_TIME; export const dynamic = "force-static"; export default async function LaunchEmojicoinPage() { + const randomNames = await fetchRandomNames({}); const geoblocked = await isUserGeoblocked(headers().get("x-real-ip")); - return ; + return ; } diff --git a/src/typescript/frontend/src/components/pages/launch-emojicoin/ClientLaunchEmojicoinPage.tsx b/src/typescript/frontend/src/components/pages/launch-emojicoin/ClientLaunchEmojicoinPage.tsx index 84371040e..c3d208828 100644 --- a/src/typescript/frontend/src/components/pages/launch-emojicoin/ClientLaunchEmojicoinPage.tsx +++ b/src/typescript/frontend/src/components/pages/launch-emojicoin/ClientLaunchEmojicoinPage.tsx @@ -19,6 +19,7 @@ import { } from "@aptos-labs/ts-sdk"; import { symbolBytesToEmojis } from "@sdk/emoji_data"; import MemoizedLaunchAnimation from "./memoized-launch"; +import { EmojiRain } from "./EmojiRain"; const LOADING_TIME = 2000; type Stage = "initial" | "loading" | "coding"; @@ -32,7 +33,10 @@ const lastMarketRegistration = ( return undefined; }; -const ClientLaunchEmojicoinPage: React.FC<{ geoblocked: boolean }> = ({ geoblocked }) => { +const ClientLaunchEmojicoinPage: React.FC<{ + geoblocked: boolean; + randomNames: ReturnType[]; +}> = ({ geoblocked, randomNames }) => { const searchParams = useSearchParams(); const emojiParams = searchParams.get("emojis"); const setEmojis = useEmojiPicker((state) => state.setEmojis); @@ -137,7 +141,11 @@ const ClientLaunchEmojicoinPage: React.FC<{ geoblocked: boolean }> = ({ geoblock }, [status]); return ( - + + setEmojis(name.emojis.map((e) => e.emoji))} + /> @@ -145,6 +153,12 @@ const ClientLaunchEmojicoinPage: React.FC<{ geoblocked: boolean }> = ({ geoblock + ); }; diff --git a/src/typescript/frontend/src/components/pages/launch-emojicoin/EmojiRain.tsx b/src/typescript/frontend/src/components/pages/launch-emojicoin/EmojiRain.tsx new file mode 100644 index 000000000..603613578 --- /dev/null +++ b/src/typescript/frontend/src/components/pages/launch-emojicoin/EmojiRain.tsx @@ -0,0 +1,69 @@ +import { type symbolBytesToEmojis } from "@sdk/emoji_data"; +import { animate, motion, stagger } from "framer-motion"; +import { useEffect, useMemo } from "react"; +import { useWindowSize } from "react-use"; + +export function EmojiRainDrop({ + name, + onClick, +}: { + name: ReturnType; + onClick?: (data: ReturnType) => void; +}) { + const { width } = useWindowSize(); + const initialX = useMemo(() => -10 - 100, []); + const y = useMemo(() => Math.random() * (width - 20) + 10, [width]); + + return ( + onClick && onClick(name)} + className="absolute emoji-rain-drop z-10 flex flex-col select-none cursor-pointer" + style={{ + left: y, + fontSize: "2em", + top: initialX, + }} + > + {name.emojis.map((e) => ( + {e.emoji} + ))} + + ); +} + +export function EmojiRain({ + randomNames, + onClick, +}: { + randomNames: ReturnType[]; + onClick?: (symbol: ReturnType) => void; +}) { + const { height } = useWindowSize(); + useEffect(() => { + const staggeredItems = stagger(5, { startDelay: 1 }); + animate( + ".emoji-rain-drop", + { + top: height + 100, + }, + { + duration: 30, + delay: staggeredItems, + ease: [], + } + ); + }, [height]); + return ( + <> + {randomNames.map((name) => { + return ( + e.hex).reduce((a, b) => `${a}-${b}`, "")}`} + name={name} + onClick={onClick} + /> + ); + })} + > + ); +} diff --git a/src/typescript/sdk/src/indexer-v2/queries/app/index.ts b/src/typescript/sdk/src/indexer-v2/queries/app/index.ts index 0009eab6e..b9ecb514e 100644 --- a/src/typescript/sdk/src/indexer-v2/queries/app/index.ts +++ b/src/typescript/sdk/src/indexer-v2/queries/app/index.ts @@ -2,3 +2,4 @@ export * from "./home"; export * from "./market"; export * from "./pools"; export * from "./candlesticks"; +export * from "./launch"; diff --git a/src/typescript/sdk/src/indexer-v2/queries/app/launch.ts b/src/typescript/sdk/src/indexer-v2/queries/app/launch.ts new file mode 100644 index 000000000..a3e527682 --- /dev/null +++ b/src/typescript/sdk/src/indexer-v2/queries/app/launch.ts @@ -0,0 +1,13 @@ +import "server-only"; + +import { DatabaseRpc } from "../../types/json-types"; +import { postgrest } from "../client"; +import { queryHelper } from "../utils"; +import { DatabaseTypeConverter } from "../../types"; + +const selectRandomNames = () => postgrest.rpc(DatabaseRpc.RandomNames, undefined, { get: true }); + +export const fetchRandomNames = queryHelper( + selectRandomNames, + DatabaseTypeConverter[DatabaseRpc.RandomNames] +); diff --git a/src/typescript/sdk/src/indexer-v2/types/index.ts b/src/typescript/sdk/src/indexer-v2/types/index.ts index 540e1ec6b..e1c5960a0 100644 --- a/src/typescript/sdk/src/indexer-v2/types/index.ts +++ b/src/typescript/sdk/src/indexer-v2/types/index.ts @@ -22,7 +22,12 @@ import { type ProcessedFields, DatabaseRpc, } from "./json-types"; -import { type MarketEmojiData, type SymbolEmoji, toMarketEmojiData } from "../../emoji_data"; +import { + type MarketEmojiData, + symbolBytesToEmojis, + type SymbolEmoji, + toMarketEmojiData, +} from "../../emoji_data"; import { toPeriod, toTrigger, type Period, type Trigger } from "../../const"; import { toAccountAddressString } from "../../utils"; import Big from "big.js"; @@ -598,6 +603,9 @@ export const toPriceFeedRPCResponse = (data: DatabaseJsonType["price_feed"]) => ), }); +export const toRandomNamesRPCResponse = (data: DatabaseJsonType["random_names"]) => + symbolBytesToEmojis("0" + data.emojis.substring(1)); + export const DatabaseTypeConverter = { [TableName.GlobalStateEvents]: toGlobalStateEventModel, [TableName.PeriodicStateEvents]: toPeriodicStateEventModel, @@ -613,6 +621,7 @@ export const DatabaseTypeConverter = { [TableName.ProcessorStatus]: toProcessorStatus, [DatabaseRpc.UserPools]: toUserPoolsRPCResponse, [DatabaseRpc.PriceFeed]: toPriceFeedRPCResponse, + [DatabaseRpc.RandomNames]: toRandomNamesRPCResponse, }; export type DatabaseModels = { diff --git a/src/typescript/sdk/src/indexer-v2/types/json-types.ts b/src/typescript/sdk/src/indexer-v2/types/json-types.ts index 1f53c292f..44943ce46 100644 --- a/src/typescript/sdk/src/indexer-v2/types/json-types.ts +++ b/src/typescript/sdk/src/indexer-v2/types/json-types.ts @@ -287,6 +287,7 @@ export enum TableName { export enum DatabaseRpc { UserPools = "user_pools", PriceFeed = "price_feed", + RandomNames = "random_names", } // Fields that only exist after being processed by a processor. @@ -364,6 +365,7 @@ export type DatabaseJsonType = { close_price_q64: Uint64String; } >; + [DatabaseRpc.RandomNames]: { emojis: string }; }; type Columns = DatabaseJsonType[TableName.GlobalStateEvents] & @@ -378,6 +380,7 @@ type Columns = DatabaseJsonType[TableName.GlobalStateEvents] & DatabaseJsonType[TableName.Market1MPeriodsInLastDay] & DatabaseJsonType[TableName.MarketState] & DatabaseJsonType[TableName.ProcessorStatus] & - DatabaseJsonType[DatabaseRpc.UserPools]; + DatabaseJsonType[DatabaseRpc.UserPools] & + DatabaseJsonType[DatabaseRpc.RandomNames]; export type AnyColumnName = keyof Columns;