Skip to content

Token website integration #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions app/landing/[pageSlug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';

import useTokenActions from '@/store/token/actions';
import { TokenLandingPageView } from '@/views';
import { useEffect } from 'react';

interface TokenLandingPageProps {
params: {
pageSlug: string;
};
}

const TokenLandingPage = ({ params: { pageSlug } }: TokenLandingPageProps) => {
const { getToken } = useTokenActions();

useEffect(() => {
getToken(pageSlug);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pageSlug]);
return <TokenLandingPageView />;
};

export default TokenLandingPage;
2 changes: 1 addition & 1 deletion components/landing/faq.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const FAQ = ({ faqDescription, faqTitle, faqs, isBuilder, isDesktop, isMobile }:
'': isBuilder && isDesktop,
'': isBuilder && isMobile,
})}>
{faqs.map((faq, index) => (
{faqs?.map((faq, index) => (
<Faq key={index} {...faq} current={current === index} onClick={() => setCurrent(index)} isBuilder={isBuilder} isDesktop={isDesktop} isMobile={isMobile} />
))}
</div>
Expand Down
8 changes: 4 additions & 4 deletions components/landing/tokenomics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ const Tokenomics = ({ tokenDistributions, tokenSymbol, tokenTotalSupply, isBuild
const colors = ['#CAC2FF', '#C2EFFF', '#FBEDB1'];

const data = {
labels: tokenDistributions.map((d) => d.title),
labels: tokenDistributions?.map((d) => d.title),
datasets: [
{
label: `${tokenSymbol} Distribution`,
data: tokenDistributions.map((d) => d.percentage),
data: tokenDistributions?.map((d) => d.percentage),
backgroundColor: ['#CAC2FF', '#C2EFFF', '#FBEDB1'],
hoverBackgroundColor: colors,
borderWidth: 6,
Expand Down Expand Up @@ -124,7 +124,7 @@ const Tokenomics = ({ tokenDistributions, tokenSymbol, tokenTotalSupply, isBuild
'text-[17.839px] leading-[26.758px] lg:text-[24px] lg:leading-[36px]': !isBuilder,
'text-[15.033px] leading-[22.55px]': isBuilder && isParentDesktop,
})}>
{tokenSymbol} {tokenTotalSupply.toLocaleString()}
{tokenSymbol} {tokenTotalSupply?.toLocaleString()}
</span>
</div>
</div>
Expand All @@ -142,7 +142,7 @@ const Tokenomics = ({ tokenDistributions, tokenSymbol, tokenTotalSupply, isBuild
'flex items-stretch justify-start gap-[6.65px] flex-wrap max-w-[259px]': isBuilder && isParentDesktop,
'flex flex-col items-stretch gap-[10.62px] w-full': isBuilder && isParentMobile,
})}>
{tokenDistributions.map(({ percentage, title }, index) => (
{tokenDistributions?.map(({ percentage, title }, index) => (
<DistributionCard color={colors[index]} key={index} percentage={percentage} title={title} isBuilder={isBuilder} isDesktop={isParentDesktop} isMobile={isParentMobile} />
))}
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const LBNavigation = () => {

const isDynamicBuilderPath = /^\/[a-zA-Z0-9-]+\/builder$/.test(pathname);

if (isDynamicBuilderPath || pathname.includes('/leaderboard') || pathname === '/landing') return null;
if (isDynamicBuilderPath || pathname.includes('/leaderboard') || pathname.includes('/landing')) return null;

return (
<>
Expand Down
4 changes: 2 additions & 2 deletions components/switch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ const SwitchIcon = ({ switched, onClick }: ISwitchIcon) => {
);
};

const LBSwitch = ({ instruction, onClick, switched, title, hasBorder = true }: ILBSwitch) => {
const LBSwitch = ({ instruction, onClick, switched, title, hasBorder = true, disabled }: ILBSwitch) => {
return (
<div className={classNames('self-stretch flex flex-col items-start justify-center gap-1', { 'px-6 -mx-6 pb-3 border-b border-b-primary-50': hasBorder })}>
<div className="flex items-center justify-center gap-2">
<div className={classNames('flex items-center justify-center gap-2', { 'pointer-events-none opacity-50': disabled })}>
<SwitchIcon switched={switched} onClick={onClick} />
<span className="text-primary-150 text-sm font-medium tracking-[-0.084px]">{title}</span>
</div>
Expand Down
1 change: 1 addition & 0 deletions components/switch/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ interface ILBSwitch {
title: string;
instruction: string;
hasBorder?: boolean;
disabled?: boolean;
}
27 changes: 27 additions & 0 deletions store/token/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
setOneHourAnalytics,
setOneMonthAnalytics,
setOneWeekAnalytics,
setSlugVerificationLoading,
} from '.';
import { CallbackProps } from '..';
import api from './api';
Expand Down Expand Up @@ -110,6 +111,19 @@ const useTokenActions = () => {
}
};

const verifyTokenSlug = async (slug: string, callback?: CallbackProps) => {
try {
dispatch(setSlugVerificationLoading(true));
const token = await api.fetchToken(slug);

return callback?.onSuccess?.(token);
} catch (error: any) {
return callback?.onError?.(error);
} finally {
dispatch(setSlugVerificationLoading(false));
}
};

const createToken = async (data: TokenData, callback?: CallbackProps) => {
try {
dispatch(setLoadingCreate(true));
Expand Down Expand Up @@ -337,6 +351,18 @@ const useTokenActions = () => {
formData.append('socials', channel);
}

if (deployData?.twitter_url) {
formData.append('twitter_url', deployData?.twitter_url!);
}

if (deployData?.telegram_url) {
formData.append('telegram_url', deployData?.telegram_url!);
}

if (deployData?.create_token_page_slug) {
formData.append('create_token_page_slug', deployData?.create_token_page_slug!);
}

let chain = {
id: chainId,
name: 'base',
Expand Down Expand Up @@ -452,6 +478,7 @@ const useTokenActions = () => {
sellTokens,
getCoinPrice,
getAnalytics,
verifyTokenSlug,
};
};

Expand Down
7 changes: 7 additions & 0 deletions store/token/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface TokenState {
oneDayAnalytics?: Analytics;
oneWeekAnalytics?: Analytics;
oneMonthAnalytics?: Analytics;
slugVerificationLoading?: boolean;
}

const initialState: TokenState = {
Expand All @@ -39,6 +40,7 @@ const initialState: TokenState = {
oneWeekAnalytics: undefined,
oneMonthAnalytics: undefined,
loadingAnalytics: true,
slugVerificationLoading: false,
};

export const tokenReducer = createSlice({
Expand Down Expand Up @@ -172,6 +174,10 @@ export const tokenReducer = createSlice({
state.oneWeekAnalytics = undefined;
state.oneMonthAnalytics = undefined;
},

setSlugVerificationLoading: (state, action: PayloadAction<boolean>) => {
state.slugVerificationLoading = action.payload;
},
},
});

Expand All @@ -195,6 +201,7 @@ export const {
setUserTokensLoading,
setUserTokensMeta,
resetAnalytics,
setSlugVerificationLoading,
} = tokenReducer.actions;

export default tokenReducer.reducer;
45 changes: 45 additions & 0 deletions store/token/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,46 @@
import { Address } from 'viem';
import { FarcaterChannel } from '../social/types';

type WebsiteBuilder = {
hero_section: {
title: string;
description: string;
image_url: string;
};
about_section: {
title: string;
description: string;
image_url: string;
};
appearance: {
primary_color: string;
secondary_color: string;
};
navigation: {
buy_url: string;
logo_url: string;
};
tokenomics: {
'Launchbox fee': string;
'Community Incentives': string;
'Fair Launch': string;
};
faq: {
title: string;
description: string;
questions: {
title: string;
answer: string;
}[];
};
footer: {
twitter_url: string;
farcaster_url: string;
telegram_url: string;
chain_explorer_url: string;
};
};

type Token = {
id: string;
token_name: string;
Expand All @@ -10,6 +50,7 @@ type Token = {
token_total_supply: number;
token_logo_url: string;
create_token_page: boolean;
create_token_page_slug: string;
warpcast_channel_link: string;
website_url: string;
twitter_url: string;
Expand All @@ -26,6 +67,7 @@ type Token = {
};
};
is_active: boolean;
website_builder: WebsiteBuilder;
created_at: string;
updated_at: string;
market_cap: number;
Expand All @@ -45,6 +87,9 @@ type TokenData = {
warpcast_channel_link?: string;
website_url?: string;
socials?: FarcaterChannel;
twitter_url?: string;
telegram_url?: string;
create_token_page_slug?: string;
};

type Meta = {
Expand Down
4 changes: 2 additions & 2 deletions views/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import NewTokenView from './new-token';
import TokenView from './token';
import LandingView from './landing';
import TokenLandingPageView from './landing';
import BuilderView from './builder';
import TokenDetailsView from './token-detail';
import FAQView from './faq';
import HomeView from './home';

export { NewTokenView, TokenView, LandingView, BuilderView, TokenDetailsView, FAQView, HomeView };
export { NewTokenView, TokenView, TokenLandingPageView, BuilderView, TokenDetailsView, FAQView, HomeView };
58 changes: 53 additions & 5 deletions views/landing/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use client';
import { useLayoutEffect, useState } from 'react';
import { useEffect, useState } from 'react';

import { LBLandingPageComponent } from '@/components';
import { ILBLandingPageComponent } from '@/components/landing/types';
import useSystemFunctions from '@/hooks/useSystemFunctions';
import Skeleton from './skeleton';

export const defaultData: ILBLandingPageComponent = {
logoURL: 'https://res.cloudinary.com/dxnd4k222/image/upload/fl_preserve_transparency/v1717454050/lb-logo_npdu7q.jpg',
Expand Down Expand Up @@ -53,14 +55,60 @@ export const defaultData: ILBLandingPageComponent = {
],
};

const LandingView = () => {
const [data] = useState<ILBLandingPageComponent>(defaultData);
const TokenLandingPageView = () => {
const [data, setData] = useState<ILBLandingPageComponent>();
const { tokenState } = useSystemFunctions();

useLayoutEffect(() => {
const loading = !data || tokenState?.loading;

useEffect(() => {
document.body.style.backgroundColor = 'white';
}, []);

useEffect(() => {
const data = tokenState.token?.website_builder;
if (!data) return;
const websiteBuilderData: ILBLandingPageComponent = {
aboutDescription: data?.about_section?.description!,
aboutImageURL: data?.about_section?.image_url!,
aboutTitle: data?.about_section?.title!,
buyLink: data?.navigation?.buy_url!,
chainExplorerLink: data?.footer?.chain_explorer_url!,
faqDescription: data?.faq?.description!,
faqTitle: data?.faq?.title!,
faqs: data?.faq?.questions!.map((faq) => ({
question: faq.title!,
answer: faq.answer!,
}))!,
heroDescription: data?.hero_section?.description!,
heroImageURL: data?.hero_section?.image_url!,
heroPrimaryButtonText: 'Buy Now',
heroSecondaryButtonText: 'Learn More',
heroTitle: data?.hero_section?.title!,
logoURL: data?.navigation?.logo_url!,
navButtonText: 'Buy Now',
primaryColor: data?.appearance?.primary_color!,
secondaryColor: data?.appearance?.secondary_color!,
telegramLink: data?.footer?.telegram_url!,
farcasterLink: data?.footer?.farcaster_url!,
tokenSymbol: tokenState.token?.token_symbol!,
tokenDistributions: data?.tokenomics
? Object.entries(data?.tokenomics!)?.map(([title, percentage]) => ({
title,
percentage: Number(percentage),
}))
: [],
tokenTotalSupply: tokenState.token?.token_total_supply!,
tokenomicsSummary: 'This is this is the total distribution of the token',
xLink: data?.footer?.twitter_url!,
};

setData(websiteBuilderData);
}, [tokenState.token]);

if (loading) return <Skeleton />;

return <LBLandingPageComponent {...data} />;
};

export default LandingView;
export default TokenLandingPageView;
Loading