From 6056b98aef927826d190dec761e86f59d3307e13 Mon Sep 17 00:00:00 2001 From: Roberto Lucas Date: Tue, 27 Aug 2024 18:55:51 -0600 Subject: [PATCH] chore: useSession cleanup + bl project status texts (#346) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: add @types/uuid * chore: add @types/uuid * fix(app-lib): tsconfig pkg extends * fix: missing encoding dep * feat: sitemap (#290) * feat: add sitemap * fix: error handling * fix: move common types * fix: update base url in sitemap * Update apps/webapp/app/(routes)/[lang]/blog/[category]/sitemap.ts Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * Update apps/webapp/app/(routes)/[lang]/wallet/sitemap.ts Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * Update apps/webapp/app/(routes)/[lang]/whitepaper/sitemap.ts Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * fix: build error * fix: remove unnecessary async declarative * vendor: add @types/uuid * fix: remove console log for debug * fix: add 'async' to all sitemaps * fix: make ProjectPageParams extends CommonPageParams --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * fix(webapp): UI/UX tweaks and upts from final v1 landing designs (#291) * (webapp)fix:FAQ border radi + muted color * (webapp)fix:newsletter spacing * (webapp)fix:participate spacing and font family * (webapp)fix:header spacing + bitlauncher logo size * (webapp)fix:blog section 4 per row + purple link + gap * (webapp)fix:hero-card spacing * (webapp)fix:auction-card spaces * (webapp)fix:Upcoming grid gap * (webapp)fix:article card - text-left * (webapp)fix:media-card text-start * (webapp)fix:media-section purple link + space * (webapp)fix:participate gap + section font and padding * (webapp)fix:footer links padding + other spacing fix * (webapp)fix:upcoming background circle * (webapp)fix:footer margin-10 * (webapp)fix:upcoming bg shape * (webapp)-andler-changes-request * (webapp)-debug-toggle navigation icon * (webapp)-create-mobile-navigation-context * (webapp)-create-mobile-navigation-context * (webapp)-fix navigation bug - add key * (webapp)-Andler-changes * (webapp)-responsive - upcoming * (webapp)-fix-responsive-whychooseUs * (webapp)-fix-responsive-participate * (webapp)-fix-responsive-media * (webapp)-fix-responsive-articles * (webapp)-responsive-project-header+info+sharebtn * (webapp)-feat-about-base * (webapp)-feat-about-landing-complete * (webapp)-feat-security-updated * (webapp)-fix-steps-padding * fix typo * fix bgHeader type * fix bgHeader type * impr(webapp): layout tweaks * impr(webapp): info pages img asset + css class * fix: bun.lockb --------- Co-authored-by: Roberto Lucas * feat: multichain indexer ( part 1 ) (#293) * chore: update app-contracts * feat: multichain indexer * feat: prod chains * feat: presale wallet * feat: blpl token * feat: blpl token * chore: update bunlock * feat: blpl token * feat: presale evm contribs * feat: blpl token * wip: presale indexer * chore(indexer): fix dockerfile * feat: presale transaction indexing (#296) * feat: report transaction id * feat: save deposits data * feat: save deposits data * feat: read presale transactions * chore: disable view all * feat: update presale deposits ui * feat: display amount raised and contributors * chore: environment chains and tokens * fix(webapp): desktop padding (#297) * feat: multichain presale deposits (#298) * chore: environment chains and tokens * fix: chain switch * fix: chain switch * feat: update nav links (#299) * chore: environment chains and tokens * feat: update nav links * chore: renable swaps service, index token from latest block * feat(webapp): wallet ui updates (#300) * fix: wagmi config * feat(webapp): presale contribution report * feat: realtime presale data * feat: realtime presale data * feat: update dropdown menu * feat(supabase): update schema and types * chore: debug presale token issuance * feat: show issuance trx link on table * impr(webapp): upt mob ver of more info cards (#294) * styles: update mobile version for information cards of home page * styles: use tailwind css variables * styles: add font family futura pt * styles, config: add cornflowerblue variables on tailwind config and update information cards' background * config: update font importation * chore: replace BC with BL * chore: replace bc files with bl files * chore: replace bc files with bl files --------- Co-authored-by: Roberto Lucas * impr(webapp): upt mob ver of more info cards (#294) (#305) * styles: update mobile version for information cards of home page * styles: use tailwind css variables * styles: add font family futura pt * styles, config: add cornflowerblue variables on tailwind config and update information cards' background * config: update font importation * chore: replace BC with BL * chore: replace bc files with bl files * chore: replace bc files with bl files --------- Co-authored-by: Leandro Gavidia Santamaria <93232139+leandrogavidia@users.noreply.github.com> * fix(impr): verify font-style and text wording across landing (#309) * fix(impr): verify font-style across landing * fix(webapp): lufga bold font config * fix(webapp): investor wording to contributor on texts * fix(webapp): investors wording to contributors on texts (plural) * chore(webapp): text, invest wording upt to contribute * config: add multibase custom hook (#310) * config: add multibase custom hook * chore: update multibase hook and session hook * chore: change inverted params * impr(fix): multibase init call --------- Co-authored-by: Roberto Lucas * feat: referral section ui - ver 0.1a (#311) * chore(webapp): update gitignore * chore: update cursor agent rules * fix: action example on cursor rules * fix: action example on cursor rules * fix: action example on cursor rules * feat(webapp): use dynamic loading in homepage (#313) * feat: token issuance with trigger.dev and alchemy hooks - part 1 (#312) * feat: alchemy transfer hooks * feat(trigger): listen token transfers * feat(app-lib): add pino logger * feat(trigger): address activity handler * feat(indexer): security updates and alchemy proxy * fix(webapp): logger bug * chore(indexer): sentry middleware and app config * chore(indexer): cleanup * chore: update bunlock * docs: update readme Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * feat(indexer): trigger address activity job (#316) * impr(webapp): check short link gen (#301) * fix(webapp): desktop padding * wip(imp): check user share link * fix(webapp): error var name scope * chore: updating supabase schema & types * feat(webapp): user table short link + session upsert * chore: use biome 🚀 (#317) * chore: use biome * chore: use biome * chore(indexer): verify call with alchemy signing key (#318) * devops(indexer): update dockerfile * chore(indexer): cleanup * chore: update gitignore * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * fix(trigger): install right trigger.dev dep * chore: august 2nd release [at TEST] (#315) * impr(webapp): upt mob ver of more info cards (#294) * styles: update mobile version for information cards of home page * styles: use tailwind css variables * styles: add font family futura pt * styles, config: add cornflowerblue variables on tailwind config and update information cards' background * config: update font importation * chore: replace BC with BL * chore: replace bc files with bl files * chore: replace bc files with bl files --------- Co-authored-by: Roberto Lucas * fix(impr): verify font-style and text wording across landing (#309) * fix(impr): verify font-style across landing * fix(webapp): lufga bold font config * fix(webapp): investor wording to contributor on texts * fix(webapp): investors wording to contributors on texts (plural) * chore(webapp): text, invest wording upt to contribute * config: add multibase custom hook (#310) * config: add multibase custom hook * chore: update multibase hook and session hook * chore: change inverted params * impr(fix): multibase init call --------- Co-authored-by: Roberto Lucas * feat: referral section ui - ver 0.1a (#311) * chore(webapp): update gitignore * chore: update cursor agent rules * fix: action example on cursor rules * fix: action example on cursor rules * fix: action example on cursor rules * feat(webapp): use dynamic loading in homepage (#313) * feat: token issuance with trigger.dev and alchemy hooks - part 1 (#312) * feat: alchemy transfer hooks * feat(trigger): listen token transfers * feat(app-lib): add pino logger * feat(trigger): address activity handler * feat(indexer): security updates and alchemy proxy * fix(webapp): logger bug * chore(indexer): sentry middleware and app config * chore(indexer): cleanup * chore: update bunlock * docs: update readme Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * feat(indexer): trigger address activity job (#316) * impr(webapp): check short link gen (#301) * fix(webapp): desktop padding * wip(imp): check user share link * fix(webapp): error var name scope * chore: updating supabase schema & types * feat(webapp): user table short link + session upsert * chore: use biome 🚀 (#317) * chore: use biome * chore: use biome * chore(indexer): verify call with alchemy signing key (#318) * devops(indexer): update dockerfile * chore(indexer): cleanup * chore: update gitignore * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * fix(trigger): install right trigger.dev dep --------- Co-authored-by: Leandro Gavidia Santamaria <93232139+leandrogavidia@users.noreply.github.com> Co-authored-by: Gabo Esquivel Co-authored-by: Gabo Esquivel Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * fix: merge typo * fix: tailwind font config * fix(indexer): trust proxy * feat: token issuance trigger part 2 (#321) * chore(alchemy): use gcloud endpoint * docs(alchemy): update readme file * docs(indexer): update readme file * debug(indexer): gcloud automated deployment * chore(alchemy): env values validation * chore(indexer): improve logging * chore(indexer): improve logging * chore(indexer): stringify all logs * debug(indexer): disable alchemy signature validation * debug(indexer): disable alchemy signature validation * chore(indexer): validate env and use trigger secret * debug(faucet): save dist/ empty folder in git * chore: update deps * chore: improve env validations * fix(alchemy): wrong import * chore(indexer): improve logging * debug(indexer): alchemy webhook handler * debug(indexer): disable helmet * debug(indexer): alchemy hook handler * debug(indexer): alchemy hook handler * debug(indexer): alchemy hook handler * debug(indexer): alchemy hook handler * feat(indexer): alchemy signature middleware * feat(indexer): validate alchemy signature * chore(indexer): security improvements (#323) * chore(indexer): disable alchemy validation * feat: presale token issuance part 3 (#325) * chore(alchemy): export types * chore(indexer): log process event id * chore(indexer): log process event id * chore: prod network conig, validate networks * wip(indexer): validate before triggering * chore: add try catch Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: clean up * devops(indexer): update dockerfile * chore: format code * devops: remove lhci reports * fix(indexer): wrong import * feat(trigger): transfer blpl token (#327) * feat(trigger): transfer blpl token * docs(trigger): token issuance jsdocs Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * devops(indexer): update dockerfile * chore: remove type:module (#329) * chore: remove type:module * chore: remove type:module * devops(indexer): test deployment * devops(indexer): test deployment * chore(supabase): use module * feat(trigger): presale token issuance * chore: format * chore: use type:module for monorepo * impr(webapp): add multibase provider (#326) * config: create multibase provider * chore: update multibase env variable * impr(webapp): UI Update (#314) * (wepapp)impr:landing distribution + filenames * (wepapp)impr:auction card badge * (wepapp)impr:steps pading + new text-size * (wepapp)impr:text-size * (wepapp)impr:refactored about us section * (wepapp)impr:new tittles learning section * (wepapp)impr:security section * (wepapp)impr:tittle style and fonts * (wepapp)impr:responsive impr * fix:about section text-18 instead of text-sm * fix:security responsive * fix:hero padding * fix:Final Mobil Tweaks * impr(webapp): landing heros + mob-nav spacing * impr(webapp): landing learn section updated blog links * fix(webapp): info text foreground color * impr(webapp): landing responsiveness * imp(webapp): 3 steps needed responsiveness * chore(webapp): rm duplicate component --------- Co-authored-by: Roberto Lucas * feat: security updates (#331) * feat(indexer): validate right usdt,usdc address * feat(indexer): wait for finality and trx log * fix(indexer): wrong import * chore(indexer): fix build * chore(webapp): format * feat(webapp): bitlauncher blog category + blog tweaks (#324) * wip: static blog files upt * fix(webapp): blog article file gen + article ui tweaks * chore(webapp): app ver upt + cms gen script * docs: upt cms-ql.sh Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * impr(webapp): upt /services/datocms/datocms-blog.service.ts coderabbitai suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * impr(webapp): upt /services/datocms/datocms-blog.service.ts coderabbitai suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(webapp): app build, missing file --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: format files * fix(webapp): cached files error catch * impr(webapp): static blog file error catch * fix(webapp): static cached file chk * feat: supabase schema and webapp updates (#335) * feat(indexer): add address registration validation * feat: update database schema to support presales * feat: repo/tokens (#336) * chore: update repo packages (#338) * feat: stable coin selector * feat: presale ux ui * chore: repo/contracts pkg * chore: repo/utils pkg * chore: repo/tsconfig pkg * chore: repo/alchemy pkg * chore: repo/jobs pkg * chore: repo/supabase pkg * docs: update readme * chore: update bunlock * chore(indexer): alchemy webhook Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * docs: update readme Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * docs: update readme Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * chore(alchemy): invert ternary Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * chore: not nullable values, format code * chore: update node:crypto Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat(indexer): alchemy signature validation Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: fix build (#339) * feat: validate user registration on event proxy (#340) * chore: fix imports * feat(indexer): validate user is registered * feat: add presale deposit checks (#341) * feat(indexer): is registered address * feat(indexer): validate amount and timing * wip(webapp): update project, presale and auction pages * chore(webapp): improve error handling Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat: realtime presale data (#342) * feat: real time presale data * feat: real time presale data * fix(webapp): header margin (#343) * webapp:fix margin top * webapp:add header tag * webapp:fix margin top * webapp:add md top * webapp:add md top * webapp:fix project tittle + pills responsive * chore: august 3rd release [pre-prod] (#334) * impr(webapp): upt mob ver of more info cards (#294) * styles: update mobile version for information cards of home page * styles: use tailwind css variables * styles: add font family futura pt * styles, config: add cornflowerblue variables on tailwind config and update information cards' background * config: update font importation * chore: replace BC with BL * chore: replace bc files with bl files * chore: replace bc files with bl files --------- Co-authored-by: Roberto Lucas * fix(impr): verify font-style and text wording across landing (#309) * fix(impr): verify font-style across landing * fix(webapp): lufga bold font config * fix(webapp): investor wording to contributor on texts * fix(webapp): investors wording to contributors on texts (plural) * chore(webapp): text, invest wording upt to contribute * config: add multibase custom hook (#310) * config: add multibase custom hook * chore: update multibase hook and session hook * chore: change inverted params * impr(fix): multibase init call --------- Co-authored-by: Roberto Lucas * feat: referral section ui - ver 0.1a (#311) * chore(webapp): update gitignore * chore: update cursor agent rules * fix: action example on cursor rules * fix: action example on cursor rules * fix: action example on cursor rules * feat(webapp): use dynamic loading in homepage (#313) * feat: token issuance with trigger.dev and alchemy hooks - part 1 (#312) * feat: alchemy transfer hooks * feat(trigger): listen token transfers * feat(app-lib): add pino logger * feat(trigger): address activity handler * feat(indexer): security updates and alchemy proxy * fix(webapp): logger bug * chore(indexer): sentry middleware and app config * chore(indexer): cleanup * chore: update bunlock * docs: update readme Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * feat(indexer): trigger address activity job (#316) * impr(webapp): check short link gen (#301) * fix(webapp): desktop padding * wip(imp): check user share link * fix(webapp): error var name scope * chore: updating supabase schema & types * feat(webapp): user table short link + session upsert * chore: use biome 🚀 (#317) * chore: use biome * chore: use biome * chore(indexer): verify call with alchemy signing key (#318) * devops(indexer): update dockerfile * chore(indexer): cleanup * chore: update gitignore * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * debug(indexer): gcloud deployment * fix(trigger): install right trigger.dev dep * fix(indexer): trust proxy * feat: token issuance trigger part 2 (#321) * chore(alchemy): use gcloud endpoint * docs(alchemy): update readme file * docs(indexer): update readme file * debug(indexer): gcloud automated deployment * chore(alchemy): env values validation * chore(indexer): improve logging * chore(indexer): improve logging * chore(indexer): stringify all logs * debug(indexer): disable alchemy signature validation * debug(indexer): disable alchemy signature validation * chore(indexer): validate env and use trigger secret * debug(faucet): save dist/ empty folder in git * chore: update deps * chore: improve env validations * fix(alchemy): wrong import * chore(indexer): improve logging * debug(indexer): alchemy webhook handler * debug(indexer): disable helmet * debug(indexer): alchemy hook handler * debug(indexer): alchemy hook handler * debug(indexer): alchemy hook handler * debug(indexer): alchemy hook handler * feat(indexer): alchemy signature middleware * feat(indexer): validate alchemy signature * chore(indexer): security improvements (#323) * chore(indexer): disable alchemy validation * feat: presale token issuance part 3 (#325) * chore(alchemy): export types * chore(indexer): log process event id * chore(indexer): log process event id * chore: prod network conig, validate networks * wip(indexer): validate before triggering * chore: add try catch Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: clean up * devops(indexer): update dockerfile * chore: format code * devops: remove lhci reports * fix(indexer): wrong import * feat(trigger): transfer blpl token (#327) * feat(trigger): transfer blpl token * docs(trigger): token issuance jsdocs Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * devops(indexer): update dockerfile * chore: remove type:module (#329) * chore: remove type:module * chore: remove type:module * devops(indexer): test deployment * devops(indexer): test deployment * chore(supabase): use module * feat(trigger): presale token issuance * chore: format * chore: use type:module for monorepo * impr(webapp): add multibase provider (#326) * config: create multibase provider * chore: update multibase env variable * impr(webapp): UI Update (#314) * (wepapp)impr:landing distribution + filenames * (wepapp)impr:auction card badge * (wepapp)impr:steps pading + new text-size * (wepapp)impr:text-size * (wepapp)impr:refactored about us section * (wepapp)impr:new tittles learning section * (wepapp)impr:security section * (wepapp)impr:tittle style and fonts * (wepapp)impr:responsive impr * fix:about section text-18 instead of text-sm * fix:security responsive * fix:hero padding * fix:Final Mobil Tweaks * impr(webapp): landing heros + mob-nav spacing * impr(webapp): landing learn section updated blog links * fix(webapp): info text foreground color * impr(webapp): landing responsiveness * imp(webapp): 3 steps needed responsiveness * chore(webapp): rm duplicate component --------- Co-authored-by: Roberto Lucas * feat: security updates (#331) * feat(indexer): validate right usdt,usdc address * feat(indexer): wait for finality and trx log * fix(indexer): wrong import * chore(indexer): fix build * chore(webapp): format * feat(webapp): bitlauncher blog category + blog tweaks (#324) * wip: static blog files upt * fix(webapp): blog article file gen + article ui tweaks * chore(webapp): app ver upt + cms gen script * docs: upt cms-ql.sh Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * impr(webapp): upt /services/datocms/datocms-blog.service.ts coderabbitai suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * impr(webapp): upt /services/datocms/datocms-blog.service.ts coderabbitai suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(webapp): app build, missing file --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: format files * fix(webapp): cached files error catch * impr(webapp): static blog file error catch * fix(webapp): static cached file chk * feat: supabase schema and webapp updates (#335) * feat(indexer): add address registration validation * feat: update database schema to support presales * feat: repo/tokens (#336) * chore: update repo packages (#338) * feat: stable coin selector * feat: presale ux ui * chore: repo/contracts pkg * chore: repo/utils pkg * chore: repo/tsconfig pkg * chore: repo/alchemy pkg * chore: repo/jobs pkg * chore: repo/supabase pkg * docs: update readme * chore: update bunlock * chore(indexer): alchemy webhook Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * docs: update readme Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * docs: update readme Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * chore(alchemy): invert ternary Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * chore: not nullable values, format code * chore: update node:crypto Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat(indexer): alchemy signature validation Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: fix build (#339) * feat: validate user registration on event proxy (#340) * chore: fix imports * feat(indexer): validate user is registered * feat: add presale deposit checks (#341) * feat(indexer): is registered address * feat(indexer): validate amount and timing * wip(webapp): update project, presale and auction pages * chore(webapp): improve error handling Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat: realtime presale data (#342) * feat: real time presale data * feat: real time presale data * fix(webapp): header margin (#343) * webapp:fix margin top * webapp:add header tag * webapp:fix margin top * webapp:add md top * webapp:add md top * webapp:fix project tittle + pills responsive --------- Co-authored-by: Leandro Gavidia Santamaria <93232139+leandrogavidia@users.noreply.github.com> Co-authored-by: Gabo Esquivel Co-authored-by: Gabo Esquivel Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> * chore(fix): update apps/trigger package.json dep * fix: cms gen merged files + use-session table upt + trigger/tsconfig upt * fix: registration logic and indexer checks (#347) * feat(indexer): check if address already bought * fix(webapp): registration logic * chore: update bunlock * fix(webapp): arrow icon * fix(webapp): arrow icon * feat: upsert accounts table on login * fix(webapp): move accounts to session hook * feat: webapp/hotfix bl project status tag (#348) * fix(webapp): tablet/small-screen header breakpoint * impr(webapp): project page hero + blog links upt * fix(webapp): project badge text upt --------- Co-authored-by: Gabo Esquivel Co-authored-by: Nathanael Liu Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> Co-authored-by: Leandro Gavidia Santamaria <93232139+leandrogavidia@users.noreply.github.com> Co-authored-by: Gabo Esquivel Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- apps/alchemy/.gitignore | 175 -------- apps/alchemy/README.md | 34 -- apps/alchemy/package.json | 15 - apps/alchemy/src/index.ts | 28 -- apps/alchemy/tsconfig.json | 16 - apps/indexer/Dockerfile | 1 - apps/indexer/package.json | 1 - apps/indexer/src/api/alchemy.ts | 14 +- apps/indexer/src/lib/supabase-client.ts | 21 +- apps/indexer/src/routes/alchemy.ts | 29 -- apps/indexer/src/routes/index.ts | 71 ---- apps/trigger/.gitignore | 1 - apps/trigger/README.md | 23 -- apps/trigger/package.json | 18 - apps/trigger/src/config.ts | 9 - apps/trigger/src/index.ts | 1 - apps/trigger/src/trigger/activity.ts | 15 - apps/trigger/src/trigger/example.ts | 14 - apps/trigger/trigger.config.ts | 16 - apps/trigger/tsconfig.json | 16 - .../app/(routes)/[lang]/[project]/page.tsx | 14 +- .../[lang]/[project]/presale/page.tsx | 3 +- .../[lang]/blog/[category]/[slug]/page.tsx | 2 +- apps/webapp/app/(routes)/[lang]/layout.tsx | 2 +- .../(routes)/[lang]/learn/security/page.tsx | 4 +- apps/webapp/app/(routes)/[lang]/page.tsx | 77 ++-- apps/webapp/app/actions/actions.d.ts | 25 ++ .../{actions.ts => app/actions/general.ts} | 0 apps/webapp/app/actions/upsert-account.ts | 32 ++ apps/webapp/app/globals.css | 2 +- apps/webapp/components/dialogs/login.tsx | 54 --- apps/webapp/components/dialogs/register.tsx | 84 ---- .../session/login-dialog-content.tsx | 2 +- .../session/register-dialog-content.tsx | 25 +- .../session/session-button.tsx | 11 +- .../session/session-dialog.tsx | 7 +- .../dialogs/session/session-dialog.type.ts | 1 + .../components/layout/footer/newsletter.tsx | 2 +- .../layout/header/bitcash-access.tsx | 114 ------ .../webapp/components/layout/header/index.tsx | 15 +- .../layout/header/lang-selector/index.tsx | 7 +- .../layout/section/article-section.tsx | 2 - .../layout/section/short-video-section.tsx | 2 +- .../layout/section/steps-section.tsx | 22 +- .../routes/about/about-bitlauncher/index.tsx | 4 +- .../routes/home/section/faq-section.tsx | 39 ++ .../routes/home/section/learn-section.tsx | 119 ++++++ .../routes/home/section/recent-articles.tsx | 377 ++++++++++++++++++ .../home/section/short-video-section.tsx | 63 +++ .../routes/home/section/steps-section.tsx | 76 ++++ .../routes/project/copy-shorlink.tsx | 6 +- .../routes/project/project-header.tsx | 2 +- .../routes/project/project-info.tsx | 10 +- .../routes/project/register-address-form.tsx | 2 +- ...cher-presale-starting-september-15th.json} | 108 +++-- apps/webapp/hooks/use-referral.ts | 25 ++ apps/webapp/hooks/use-session.tsx | 142 +++---- apps/webapp/lib/projects.ts | 7 +- apps/webapp/package.json | 3 +- .../datocms/graphql/generated/cms/schema.ts | 2 + bun.lockb | Bin 836344 -> 834672 bytes packages/jobs/package.json | 2 + packages/jobs/tsconfig.json | 2 +- 63 files changed, 1051 insertions(+), 965 deletions(-) delete mode 100644 apps/alchemy/.gitignore delete mode 100644 apps/alchemy/README.md delete mode 100644 apps/alchemy/package.json delete mode 100644 apps/alchemy/src/index.ts delete mode 100644 apps/alchemy/tsconfig.json delete mode 100644 apps/indexer/src/routes/alchemy.ts delete mode 100644 apps/indexer/src/routes/index.ts delete mode 100644 apps/trigger/.gitignore delete mode 100644 apps/trigger/README.md delete mode 100644 apps/trigger/package.json delete mode 100644 apps/trigger/src/config.ts delete mode 100644 apps/trigger/src/index.ts delete mode 100644 apps/trigger/src/trigger/activity.ts delete mode 100644 apps/trigger/src/trigger/example.ts delete mode 100644 apps/trigger/trigger.config.ts delete mode 100644 apps/trigger/tsconfig.json create mode 100644 apps/webapp/app/actions/actions.d.ts rename apps/webapp/{actions.ts => app/actions/general.ts} (100%) create mode 100644 apps/webapp/app/actions/upsert-account.ts delete mode 100644 apps/webapp/components/dialogs/login.tsx delete mode 100644 apps/webapp/components/dialogs/register.tsx rename apps/webapp/components/{layout => dialogs}/session/login-dialog-content.tsx (93%) rename apps/webapp/components/{layout => dialogs}/session/register-dialog-content.tsx (76%) rename apps/webapp/components/{layout => dialogs}/session/session-button.tsx (89%) rename apps/webapp/components/{layout => dialogs}/session/session-dialog.tsx (79%) create mode 100644 apps/webapp/components/dialogs/session/session-dialog.type.ts delete mode 100644 apps/webapp/components/layout/header/bitcash-access.tsx create mode 100644 apps/webapp/components/routes/home/section/faq-section.tsx create mode 100644 apps/webapp/components/routes/home/section/learn-section.tsx create mode 100644 apps/webapp/components/routes/home/section/recent-articles.tsx create mode 100644 apps/webapp/components/routes/home/section/short-video-section.tsx create mode 100644 apps/webapp/components/routes/home/section/steps-section.tsx rename apps/webapp/dictionaries/en/blog/bitlauncher/{welcome-to-the-bitlauncher-presale-starting-august-31st.json => welcome-to-the-bitlauncher-presale-starting-september-15th.json} (87%) create mode 100644 apps/webapp/hooks/use-referral.ts diff --git a/apps/alchemy/.gitignore b/apps/alchemy/.gitignore deleted file mode 100644 index 9b1ee42e8..000000000 --- a/apps/alchemy/.gitignore +++ /dev/null @@ -1,175 +0,0 @@ -# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore - -# Logs - -logs -_.log -npm-debug.log_ -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Caches - -.cache - -# Diagnostic reports (https://nodejs.org/api/report.html) - -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json - -# Runtime data - -pids -_.pid -_.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover - -lib-cov - -# Coverage directory used by tools like istanbul - -coverage -*.lcov - -# nyc test coverage - -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) - -.grunt - -# Bower dependency directory (https://bower.io/) - -bower_components - -# node-waf configuration - -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) - -build/Release - -# Dependency directories - -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) - -web_modules/ - -# TypeScript cache - -*.tsbuildinfo - -# Optional npm cache directory - -.npm - -# Optional eslint cache - -.eslintcache - -# Optional stylelint cache - -.stylelintcache - -# Microbundle cache - -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history - -.node_repl_history - -# Output of 'npm pack' - -*.tgz - -# Yarn Integrity file - -.yarn-integrity - -# dotenv environment variable files - -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) - -.parcel-cache - -# Next.js build output - -.next -out - -# Nuxt.js build / generate output - -.nuxt -dist - -# Gatsby files - -# Comment in the public line in if your project uses Gatsby and not Next.js - -# https://nextjs.org/blog/next-9-1#public-directory-support - -# public - -# vuepress build output - -.vuepress/dist - -# vuepress v2.x temp and cache directory - -.temp - -# Docusaurus cache and generated files - -.docusaurus - -# Serverless directories - -.serverless/ - -# FuseBox cache - -.fusebox/ - -# DynamoDB Local files - -.dynamodb/ - -# TernJS port file - -.tern-port - -# Stores VSCode versions used for testing VSCode extensions - -.vscode-test - -# yarn v2 - -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# IntelliJ based IDEs -.idea - -# Finder (MacOS) folder config -.DS_Store diff --git a/apps/alchemy/README.md b/apps/alchemy/README.md deleted file mode 100644 index 40c6c6b3c..000000000 --- a/apps/alchemy/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Alchemy Hooks - -This project sets up Alchemy webhooks to listen for blockchain events. -These hooks invoke Trigger.dev jobs that process the events using Viem. - - -## Dependencies - - [Alchemy SDK](https://www.npmjs.com/package/alchemy-sdk): Used for interacting with Alchemy's API and setting up webhooks. - [Trigger.dev](https://www.npmjs.com/package/@trigger.dev/sdk): Used for creating and managing serverless functions and workflows. - [Viem](https://www.npmjs.com/package/viem): Ethereum JavaScript library for interacting with the Ethereum blockchain. - -## Documentation - -For more information on how to use Alchemy's services and set up webhooks, refer to the [Alchemy Documentation](https://docs.alchemy.com/). - -## Related Projects - -For details on how these webhooks are processed and used in our Trigger.dev jobs, please see the [Trigger App README](../trigger/README.md). - - -To install dependencies: - -```bash -bun install -``` - -To run: - -```bash -bun run src/index.ts -``` - -This project was created using `bun init` in bun v1.1.24. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/apps/alchemy/package.json b/apps/alchemy/package.json deleted file mode 100644 index 1c4b90e24..000000000 --- a/apps/alchemy/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "alchemy-hooks", - "module": "src/index.ts", - "type": "module", - "devDependencies": { - "@types/bun": "latest" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "alchemy-sdk": "^3.4.1", - "dotenv": "^16.4.5" - } -} diff --git a/apps/alchemy/src/index.ts b/apps/alchemy/src/index.ts deleted file mode 100644 index 3b4cac2f1..000000000 --- a/apps/alchemy/src/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -require('dotenv').config() -import { Alchemy, Network, WebhookType } from 'alchemy-sdk' - -// authToken is required to use Notify APIs. Found on the top right corner of -// https://dashboard.alchemy.com/notify. -async function createAddressActivityNotification() { - const settings = { - authToken: process.env.ALCHEMY_NOTIFY_TOKEN, - network: Network.MATIC_MAINNET, // Replace with your network. - } - - const alchemy = new Alchemy(settings) - const addressActivityWebhook = await alchemy.notify.createWebhook( - // TO DO: You will replace this URL in Step #3 of this guide! - 'https://webhook.site/f18c0350-6479-4686-b48a-3d16aa238b7b', - WebhookType.ADDRESS_ACTIVITY, - { - // use any address you want to monitor activity on! - addresses: ['0x6F76670A66e7909Af9B76f0D84E39317FCc0B2e1'], - network: Network.MATIC_MAINNET, - }, - ) - console.log( - 'Alchemy Notify address activity notification created, go to https://dashboard.alchemy.com/notify to see details of your custom hook.', - ) -} - -createAddressActivityNotification() diff --git a/apps/alchemy/tsconfig.json b/apps/alchemy/tsconfig.json deleted file mode 100644 index d14168838..000000000 --- a/apps/alchemy/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../packages/config-typescript/node16.json", - "include": ["./src/**/*", "src/lib/utils.ts"], - "exclude": ["node_modules"], - "compilerOptions": { - "sourceMap": true, - "inlineSources": true, - "sourceRoot": "/", - "outDir": "dist", - "baseUrl": "./src", - "paths": { - "~/*": ["./*"], - "@/*": ["/*"] - } - } -} diff --git a/apps/indexer/Dockerfile b/apps/indexer/Dockerfile index 47987fd71..9fd70036d 100644 --- a/apps/indexer/Dockerfile +++ b/apps/indexer/Dockerfile @@ -26,7 +26,6 @@ RUN bun install # Copy the specific workspaces COPY apps/indexer ./apps/indexer -COPY apps/trigger ./apps/trigger COPY packages/ ./packages/ # Set the working directory to your specific workspace diff --git a/apps/indexer/package.json b/apps/indexer/package.json index 21b6828a5..0fd98b309 100644 --- a/apps/indexer/package.json +++ b/apps/indexer/package.json @@ -18,7 +18,6 @@ "@repo/jobs": "workspace:*", "@repo/alchemy": "workspace:*", "@repo/tokens": "workspace:*", - "@repo/trigger": "workspace:*", "@sentry/integrations": "^7.114.0", "@sentry/node": "^8.19.0", "@sentry/profiling-node": "^8.26.0", diff --git a/apps/indexer/src/api/alchemy.ts b/apps/indexer/src/api/alchemy.ts index 51de3c1ea..91c5bbc19 100644 --- a/apps/indexer/src/api/alchemy.ts +++ b/apps/indexer/src/api/alchemy.ts @@ -15,6 +15,7 @@ import { appConfig } from '~/config' import { logger } from '~/lib/logger' import { getPresaleData, + getPresaleDeposits, isAddressRegisteredForPresale, } from '~/lib/supabase-client' // import {isAddressRegisteredForPresale} from '~/src/lib/supabase-client'; @@ -92,7 +93,18 @@ export async function alchemyWebhook(req: Request, res: Response) { // Get presale data and validate amount and timing const presaleData = await getPresaleData(1) - const isValidAmount = txn.value <= presaleData.max_allocation + + // Check if account already bought + const deposits = await getPresaleDeposits({ + address: getAddress(txn.fromAddress), + projectId: 1, + }) + const totalDeposits = deposits.reduce( + (acc, deposit) => acc + Number(deposit.amount), + 0, + ) + const isValidAmount = + txn.value + totalDeposits <= presaleData.max_allocation const currentTimestamp = Math.floor(Date.now() / 1000) // Current time in seconds const isWithinPresalePeriod = currentTimestamp >= Number(presaleData.start_timestamptz) && diff --git a/apps/indexer/src/lib/supabase-client.ts b/apps/indexer/src/lib/supabase-client.ts index bf588c328..5ecd11076 100644 --- a/apps/indexer/src/lib/supabase-client.ts +++ b/apps/indexer/src/lib/supabase-client.ts @@ -1,5 +1,6 @@ import type { Database, TablesInsert } from '@repo/supabase' import { createClient } from '@supabase/supabase-js' +import { Address } from 'viem' import { appConfig } from '~/config' // Initialize Supabase client @@ -91,7 +92,25 @@ export async function getPresaleData(projectId: number) { .single() if (error) { - console.error('Error checking presale data:', error) + console.error('Error getting presale data:', error) + throw error + } + + return data +} + +export async function getPresaleDeposits({ + address, + projectId, +}: { address: Address; projectId: number }) { + const { data, error } = await supabase + .from('presale_deposit') + .select('*') + .eq('project_id', projectId) + .eq('address', address) + + if (error) { + console.error('Error getting presale deposits data:', error) throw error } diff --git a/apps/indexer/src/routes/alchemy.ts b/apps/indexer/src/routes/alchemy.ts deleted file mode 100644 index 8b481cefc..000000000 --- a/apps/indexer/src/routes/alchemy.ts +++ /dev/null @@ -1,29 +0,0 @@ -import crypto from 'crypto' -import { addressActivityTask } from '@repo/trigger' -import type { Request, Response } from 'express' -import { logger } from '~/lib/logger' -import { appConfig } from '../config' - -export function alchemyWebhook(req: Request, res: Response) { - if (!validateAlchemySignature(req)) - return res.status(401).send('Unauthorized') - - logger.info(req.body) - - // TODO: validate user is whitelisted - - addressActivityTask.trigger(req.body) - - res.status(200).send('Webhook processed') -} - -function validateAlchemySignature(req: Request): boolean { - const alchemySignature = req.headers['x-alchemy-signature'] as string - const payload = JSON.stringify(req.body) - const hmac = crypto.createHmac( - 'sha256', - appConfig.evm.alchemy.activitySigningKey, - ) - hmac.update(payload) - return alchemySignature === hmac.digest('hex') -} diff --git a/apps/indexer/src/routes/index.ts b/apps/indexer/src/routes/index.ts deleted file mode 100644 index e980af921..000000000 --- a/apps/indexer/src/routes/index.ts +++ /dev/null @@ -1,71 +0,0 @@ -import express, { - type NextFunction, - type Response, - type Request, -} from 'express' -import rateLimit from 'express-rate-limit' -import helmet from 'helmet' -import pinoHttp from 'pino-http' -import { logger } from '~/lib/logger' -import { setupSentryErrorHandler } from '~/lib/sentry' -import { alchemyWebhook } from './alchemy' -import { healthcheck } from './healthcheck' - -export function startExpress() { - const app = express() - const port = 8080 - - // Sentry error handler - setupSentryErrorHandler(app) - - // Security Middlewares - app.use(helmet()) - - app.use( - rateLimit({ - windowMs: 60 * 1000, // 1 minute - max: 100, // limit each IP to 100 requests per windowMs - }), - ) - - // Logging middleware - app.use(pinoHttp({ logger })) - - // Routes - app.get('/', healthcheck) - app.post('/alchemy', alchemyWebhook) - - // Error handling middleware - app.use((err: Error, req: Request, res: Response, next: NextFunction) => { - logger.error(err, 'Unhandled error') - res.status(500).json({ error: 'Internal Server Error' }) - }) - - // Start the server - const server = app.listen(port, () => { - logger.info(`Server running at http://localhost:${port}`) - }) - - // Handle unhandled promise rejections - process.on('unhandledRejection', (reason: any, promise: Promise) => { - logger.error({ reason, promise }, 'Unhandled Rejection') - // Optionally, you can choose to exit the process - // process.exit(1) - }) - - // Handle uncaught exceptions - process.on('uncaughtException', (error: Error) => { - logger.error(error, 'Uncaught Exception') - // It's generally recommended to exit the process on uncaught exceptions - process.exit(1) - }) - - // Graceful shutdown - process.on('SIGTERM', () => { - logger.info('SIGTERM signal received: closing HTTP server') - server.close(() => { - logger.info('HTTP server closed') - process.exit(0) - }) - }) -} diff --git a/apps/trigger/.gitignore b/apps/trigger/.gitignore deleted file mode 100644 index 6524f048d..000000000 --- a/apps/trigger/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.trigger \ No newline at end of file diff --git a/apps/trigger/README.md b/apps/trigger/README.md deleted file mode 100644 index 826636969..000000000 --- a/apps/trigger/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Trigger.dev Background Jobs - -This directory contains the configuration and implementation of background jobs using Trigger.dev for the Basilica project. - -## Overview - -Trigger.dev is an open-source job scheduling and execution platform that allows us to create, manage, and monitor background jobs efficiently. We use it for various issuance-related tasks and to handle webhook events from services like Moralis and Alchemy. - -## Key Features - -- **Webhook Integration**: Trigger.dev provides URLs that can be called from external webhooks, allowing us to process events from Moralis and Alchemy Web3 hooks. -- **Job Scheduling**: Easily schedule and manage recurring or one-time jobs. -- **Open Source**: Trigger.dev is open-source, providing flexibility and the option for self-hosting in the future if needed. -- **Cost-Effective**: Offers a robust feature set at a competitive price point. - -## Usage - -For detailed instructions on setting up and using Trigger.dev jobs, please refer to the official Trigger.dev documentation: - -[Trigger.dev Documentation](https://trigger.dev/docs) - -This comprehensive guide covers everything from creating your first job to advanced usage and best practices. - diff --git a/apps/trigger/package.json b/apps/trigger/package.json deleted file mode 100644 index 8ed853c01..000000000 --- a/apps/trigger/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@repo/trigger", - "version": "0.0.1", - "private": true, - "main": "src/index.ts", - "scripts": { - "dev": "bunx trigger.dev@beta dev", - "deploy:test": "bunx trigger.dev@beta deploy --env test", - "deploy:prod": "bunx trigger.dev@beta deploy --env prod" - }, - "dependencies": { - "@repo/alchemy": "workspace:*", - "app-env": "workspace:*", - "@repo/utils": "workspace:*", - "@trigger.dev/sdk": "3.0.0-beta.55", - "viem": "latest" - } -} diff --git a/apps/trigger/src/config.ts b/apps/trigger/src/config.ts deleted file mode 100644 index 575b2efed..000000000 --- a/apps/trigger/src/config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Address } from 'viem' -import { privateKeyToAccount } from 'viem/accounts' - -export const appenv = { - eosEvmApi: 'https://api.testnet.evm.eosnetwork.com', - issuerKey: process.env.ISSUER_KEY || '', - issuerAddress: (process.env.ISSUER_ADDRESS || '') as Address, - issuerAccount: privateKeyToAccount(`0x${process.env.ISSUER_KEY}`), -} diff --git a/apps/trigger/src/index.ts b/apps/trigger/src/index.ts deleted file mode 100644 index 813c48b07..000000000 --- a/apps/trigger/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './trigger/activity' diff --git a/apps/trigger/src/trigger/activity.ts b/apps/trigger/src/trigger/activity.ts deleted file mode 100644 index 700734dac..000000000 --- a/apps/trigger/src/trigger/activity.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { logger, task } from '@trigger.dev/sdk/v3' - -export const addressActivityTask = task({ - id: 'address-activity', - run: async (payload: any, { ctx }) => { - try { - logger.log('Address activity', { payload, ctx }) - } catch (error) { - logger.error('Error processing address activity', { - error: (error as Error).message, - }) - throw error - } - }, -}) diff --git a/apps/trigger/src/trigger/example.ts b/apps/trigger/src/trigger/example.ts deleted file mode 100644 index 0529c873f..000000000 --- a/apps/trigger/src/trigger/example.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { logger, task, wait } from '@trigger.dev/sdk/v3' - -export const helloWorldTask = task({ - id: 'hello-world', - run: async (payload: any, { ctx }) => { - logger.log('Hello, world!', { payload, ctx }) - - await wait.for({ seconds: 5 }) - - return { - message: 'Hello, world!', - } - }, -}) diff --git a/apps/trigger/trigger.config.ts b/apps/trigger/trigger.config.ts deleted file mode 100644 index 191907b0b..000000000 --- a/apps/trigger/trigger.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { TriggerConfig } from '@trigger.dev/sdk/v3' - -export const config: TriggerConfig = { - project: 'proj_uefmifhkitjdldujpocd', - logLevel: 'log', - retries: { - enabledInDev: true, - default: { - maxAttempts: 3, - minTimeoutInMs: 1000, - maxTimeoutInMs: 10000, - factor: 2, - randomize: true, - }, - }, -} diff --git a/apps/trigger/tsconfig.json b/apps/trigger/tsconfig.json deleted file mode 100644 index c24fa5e65..000000000 --- a/apps/trigger/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@repo/tsconfig/node16.json", - "include": ["./src/**/*", "src/lib/utils.ts", "trigger.config.ts"], - "exclude": ["node_modules"], - "compilerOptions": { - "sourceMap": true, - "inlineSources": true, - "sourceRoot": "/", - "outDir": "dist", - "baseUrl": "./src", - "paths": { - "~/*": ["./*"], - "@/*": ["./*"] - } - } -} diff --git a/apps/webapp/app/(routes)/[lang]/[project]/page.tsx b/apps/webapp/app/(routes)/[lang]/[project]/page.tsx index feb8992e4..9bef49369 100644 --- a/apps/webapp/app/(routes)/[lang]/[project]/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/[project]/page.tsx @@ -8,6 +8,8 @@ import { locales } from '@/dictionaries/locales' import { appConfig } from '@/lib/config' import { getProjectBySlug, getProjects } from '@/lib/projects' import { cn } from '@/lib/utils' +import { createSupabaseServerClient } from '@/services/supabase' +import { getPresaleData } from '@/services/supabase/service' import type { ProjectPageParams, ProjectPageProps } from '@/types/routing.type' import dynamic from 'next/dynamic' import Image from 'next/image' @@ -21,17 +23,18 @@ export default async function ProjectPage({ params }: ProjectPageProps) { const projectContentObjectKeys = Object.keys(project.content) const projectContent = project.content - - // is presale upcoming - // const isPresaleUpcoming = new Date(project.presaleData.start_timestamptz) > new Date() - + const supabase = await createSupabaseServerClient() + const presaleData = await getPresaleData({ projectId: project.id, supabase }) + const presaleDataStartDate = new Date(presaleData.start_timestamptz) + const presaleDataEndDate = new Date(presaleData.end_timestamptz) + return ( <>
- +
@@ -43,6 +46,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
+ {/* // TODO: Update project table to add bitlauncher project. */}
diff --git a/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx b/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx index 954d95250..e4d955791 100644 --- a/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx @@ -17,11 +17,12 @@ export default async function ProjectPage({ params }: ProjectPageProps) { params.project, dict, )) as ProjectWithAuction + if (!project) redirect('/') + const supabase = await createSupabaseServerClient() const presaleData = await getPresaleData({ projectId: project.id, supabase }) const projectData = await getProjectData({ projectId: project.id, supabase }) - if (!project) redirect('/') return (
diff --git a/apps/webapp/app/(routes)/[lang]/blog/[category]/[slug]/page.tsx b/apps/webapp/app/(routes)/[lang]/blog/[category]/[slug]/page.tsx index 33e0c9888..6b56de0e9 100644 --- a/apps/webapp/app/(routes)/[lang]/blog/[category]/[slug]/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/blog/[category]/[slug]/page.tsx @@ -1,4 +1,4 @@ -import { generateShortLink } from '@/actions' +import { generateShortLink } from '@/app/actions/general' import { BlogPage } from '@/components/routes/blog/article' import { type Lang, locales } from '@/dictionaries/locales' import { generateMetadataFromSEO } from '@/lib/seo' diff --git a/apps/webapp/app/(routes)/[lang]/layout.tsx b/apps/webapp/app/(routes)/[lang]/layout.tsx index 8e8ef5982..95da635f9 100644 --- a/apps/webapp/app/(routes)/[lang]/layout.tsx +++ b/apps/webapp/app/(routes)/[lang]/layout.tsx @@ -103,7 +103,7 @@ export async function generateStaticParams() { const DynamicSessionDialog = dynamic( () => - import('../../../components/layout/session/session-dialog').then( + import('../../../components/dialogs/session/session-dialog').then( (mod) => mod.SessionDialog, ), { diff --git a/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx b/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx index 5355e5685..c9d943224 100644 --- a/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx @@ -1,5 +1,5 @@ -import { LearnSection } from '@/components/layout/section/learn-section' -import StepsSection from '@/components/layout/section/steps-section' +import { LearnSection } from '@/components/routes/home/section/learn-section' +import StepsSection from '@/components/routes/home/section/steps-section' import { BgHeader } from '@/components/shared/bg-header' import { PageContent } from '@/components/shared/content' import { getDictionary } from '@/dictionaries' diff --git a/apps/webapp/app/(routes)/[lang]/page.tsx b/apps/webapp/app/(routes)/[lang]/page.tsx index 20821ff56..024b5ab15 100644 --- a/apps/webapp/app/(routes)/[lang]/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/page.tsx @@ -3,10 +3,6 @@ import { Categories } from '@/components/_wip/categories' import { FeatureOne } from '@/components/_wip/feature-one' import { FeatureThree } from '@/components/_wip/feature-three' import { FeatureTwo } from '@/components/_wip/feature-two' -import { RecentArticles } from '@/components/layout/section/article-section' -import { FAQ } from '@/components/layout/section/faq-section' -import { LearnSection } from '@/components/layout/section/learn-section' -import StepsSection from '@/components/layout/section/steps-section' import { NewHomeHero } from '@/components/routes/home/hero/index' import { getDictionary } from '@/dictionaries' import type { Lang } from '@/dictionaries/locales' @@ -14,24 +10,6 @@ import { appConfig } from '@/lib/config' import { getProjects } from '@/lib/projects' import dynamic from 'next/dynamic' -const DynamicFeatures = dynamic( - () => import('@/components/routes/home/features').then((mod) => mod.Features), - { ssr: false }, -) - -const DynamicUpcoming = dynamic( - () => import('@/components/routes/home/upcoming').then((mod) => mod.Upcoming), - { ssr: false }, -) - -const DynamicWhyChooseUs = dynamic( - () => - import('@/components/routes/home/why-choose-us').then( - (mod) => mod.WhyChooseUs, - ), - { ssr: false }, -) - export default async function IndexPage({ params: { lang } }: IndexPageProps) { const dict = await getDictionary(lang) const projects = getProjects(dict) @@ -44,10 +22,10 @@ export default async function IndexPage({ params: { lang } }: IndexPageProps) {
- - - - + + + + {appConfig.features.explorations ? ( <> @@ -66,3 +44,50 @@ export default async function IndexPage({ params: { lang } }: IndexPageProps) { interface IndexPageProps { params: { lang: Lang } } + +const DynamicFeatures = dynamic( + () => import('@/components/routes/home/features').then((mod) => mod.Features), + { ssr: false }, +) + +const DynamicUpcoming = dynamic( + () => import('@/components/routes/home/upcoming').then((mod) => mod.Upcoming), + { ssr: false }, +) + +const DynamicWhyChooseUs = dynamic( + () => + import('@/components/routes/home/why-choose-us').then( + (mod) => mod.WhyChooseUs, + ), + { ssr: false }, +) + +const DynamicStepsSection = dynamic( + () => import('@/components/routes/home/section/steps-section'), + { ssr: false }, +) + +const DynamicLearnSection = dynamic( + () => + import('@/components/routes/home/section/learn-section').then( + (mod) => mod.LearnSection, + ), + { ssr: false }, +) + +const DynamicRecentArticles = dynamic( + () => + import('@/components/routes/home/section/recent-articles').then( + (mod) => mod.RecentArticles, + ), + { ssr: false }, +) + +const DynamicFAQ = dynamic( + () => + import('@/components/routes/home/section/faq-section').then( + (mod) => mod.FAQ, + ), + { ssr: false }, +) diff --git a/apps/webapp/app/actions/actions.d.ts b/apps/webapp/app/actions/actions.d.ts new file mode 100644 index 000000000..b0e0fb30e --- /dev/null +++ b/apps/webapp/app/actions/actions.d.ts @@ -0,0 +1,25 @@ +/** + * Represents a standardized response structure for actions. + * This pattern is useful for several reasons: + * 1. Consistency: Provides a uniform structure for all action responses. + * 2. Type safety: Allows for type-checking of the response data. + * 3. Error handling: Includes a field for user-friendly error messages. + * 4. Flexibility: The generic type T allows for different data structures. + * + * When success is true: + * - message and data are optional + * When success is false: + * - error is required and should contain a user-friendly error message + * + * Note: It's important to always return user-friendly error messages + * that are clear and actionable for the end-user. + */ + +import type { AppErrorData } from '@/lib/app-errors/errors' + +export interface ActionResponse { + success: boolean + message?: string + data?: T + error?: AppErrorData +} diff --git a/apps/webapp/actions.ts b/apps/webapp/app/actions/general.ts similarity index 100% rename from apps/webapp/actions.ts rename to apps/webapp/app/actions/general.ts diff --git a/apps/webapp/app/actions/upsert-account.ts b/apps/webapp/app/actions/upsert-account.ts new file mode 100644 index 000000000..2cf9069b1 --- /dev/null +++ b/apps/webapp/app/actions/upsert-account.ts @@ -0,0 +1,32 @@ +'use server' + +import { createSupabaseServerClient } from '@/services/supabase' +import { createSafeActionClient } from 'next-safe-action' +import { z } from 'zod' +import type { ActionResponse } from './actions' + +const schema = z.object({ + account: z.string().min(1, 'Account is required'), +}) + +export const upsertAccount = createSafeActionClient() + .schema(schema) + .action(async (input): Promise => { + const { account } = input.parsedInput + const supabase = await createSupabaseServerClient() + + const { data, error } = await supabase + .from('account') + .upsert({ account }) + .select('*') + .single() + + if (error) { + return { + success: false, + error: new Error(`Error upserting account: ${error.message}`), + } + } + + return { success: true, data } + }) diff --git a/apps/webapp/app/globals.css b/apps/webapp/app/globals.css index 491bd1b2a..ebdbeaebc 100644 --- a/apps/webapp/app/globals.css +++ b/apps/webapp/app/globals.css @@ -309,7 +309,7 @@ iframe[title="reCAPTCHA"], /* Heading in About - Security - Whitepaper */ .sectionsHeading { - @apply text-[4.188rem] font-normal leading-normal md:text-[4.3504rem] lg:text-[5.438rem]; + @apply text-[4.188rem] font-normal leading-tight md:text-[4.3504rem] lg:text-[5.438rem]; } /* Subheading in About - Security - Whitepaper */ diff --git a/apps/webapp/components/dialogs/login.tsx b/apps/webapp/components/dialogs/login.tsx deleted file mode 100644 index d7f0b1725..000000000 --- a/apps/webapp/components/dialogs/login.tsx +++ /dev/null @@ -1,54 +0,0 @@ -'use client' - -import type { BitcashAccessContentType } from '@/components/layout/header/bitcash-access' -import { Button } from '@/components/ui/button' -import { - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { useSession } from '@/hooks/use-session' -import QRCode from 'react-qr-code' - -export function LoginDialogContent({ - updateDialogContent, -}: { - updateDialogContent: (dialog: BitcashAccessContentType) => void -}) { - const { loginUri } = useSession() - return ( - <> - - {/* @ts-ignore */} - Connect bitcash Wallet - {/* @ts-ignore */} - - Scan this QR code with the bitcash wallet QR reader and sign to log - in. - - - {loginUri ? ( -
- -
- ) : null} - - - - - - ) -} diff --git a/apps/webapp/components/dialogs/register.tsx b/apps/webapp/components/dialogs/register.tsx deleted file mode 100644 index 854fac523..000000000 --- a/apps/webapp/components/dialogs/register.tsx +++ /dev/null @@ -1,84 +0,0 @@ -'use client' - -import type { BitcashAccessContentType } from '@/components/layout/header/bitcash-access' -import { Button } from '@/components/ui/button' -import { - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { useSession } from '@/hooks/use-session' -import { runtimeEnv } from '@repo/utils' -import { useRouter } from 'next/navigation' -import QRCode from 'react-qr-code' -import { useEffectOnce } from 'react-use' - -export function RegisterDialogContent({ - updateDialogContent, -}: { - updateDialogContent: (dialog: BitcashAccessContentType) => void -}) { - const { session, registerUri } = useSession() - const router = useRouter() - - useEffectOnce(() => { - const compatibleDevice = runtimeEnv.isMobile || runtimeEnv.isIpad - - if (compatibleDevice) { - router.push(registerUri) - } - }) - - const isUserLoggedIn = Boolean(session?.account) - const buttonText = isUserLoggedIn - ? `You're already logged in with ${session?.account} account.` - : 'Already have an account? Log in!' - - return ( - <> - - {/* @ts-ignore */} - Register to Bitcash Wallet - {/* @ts-ignore */} - - Scan this QR code with your smartphone camera or a QR reader to create - a bitcash account. - - - -
- - {/* bitcash app registration */} -
- -

- On your phone you can also register at bitcash.to/reg! -

- -
- - ) -} diff --git a/apps/webapp/components/layout/session/login-dialog-content.tsx b/apps/webapp/components/dialogs/session/login-dialog-content.tsx similarity index 93% rename from apps/webapp/components/layout/session/login-dialog-content.tsx rename to apps/webapp/components/dialogs/session/login-dialog-content.tsx index 11c6c98ba..61d8221a8 100644 --- a/apps/webapp/components/layout/session/login-dialog-content.tsx +++ b/apps/webapp/components/dialogs/session/login-dialog-content.tsx @@ -1,6 +1,5 @@ 'use client' -import type { BitcashAccessContentType } from '@/components/layout/session/session-dialog' import { Button } from '@/components/ui/button' import { DialogDescription, @@ -10,6 +9,7 @@ import { } from '@/components/ui/dialog' import { useSession } from '@/hooks/use-session' import QRCode from 'react-qr-code' +import type { BitcashAccessContentType } from './session-dialog.type' export function SessionDialogContent({ updateDialogContent, diff --git a/apps/webapp/components/layout/session/register-dialog-content.tsx b/apps/webapp/components/dialogs/session/register-dialog-content.tsx similarity index 76% rename from apps/webapp/components/layout/session/register-dialog-content.tsx rename to apps/webapp/components/dialogs/session/register-dialog-content.tsx index 08f2bea79..b5494f061 100644 --- a/apps/webapp/components/layout/session/register-dialog-content.tsx +++ b/apps/webapp/components/dialogs/session/register-dialog-content.tsx @@ -1,6 +1,5 @@ 'use client' -import type { BitcashAccessContentType } from '@/components/layout/session/session-dialog' import { Button } from '@/components/ui/button' import { DialogDescription, @@ -8,36 +7,26 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog' +import { useReferral } from '@/hooks/use-referral' import { useSession } from '@/hooks/use-session' -import { runtimeEnv } from '@repo/utils' -import { useRouter } from 'next/navigation' import QRCode from 'react-qr-code' -import { useEffectOnce } from 'react-use' +import type { BitcashAccessContentType } from './session-dialog.type' export function RegisterDialogContent({ updateDialogContent, }: { updateDialogContent: (dialog: BitcashAccessContentType) => void }) { - const { session, registerUri } = useSession() - const router = useRouter() - - useEffectOnce(() => { - const compatibleDevice = runtimeEnv.isMobile || runtimeEnv.isIpad - - if (compatibleDevice) { - router.push(registerUri) - } - }) - + const { session } = useSession() const isUserLoggedIn = Boolean(session?.account) + const { bitcashRegisterUri } = useReferral() const buttonText = isUserLoggedIn ? `You're already logged in with ${session?.account} account.` : 'Already have an account? Log in!' return ( <> - + {/* @ts-ignore */} Register to Bitcash Wallet {/* @ts-ignore */} @@ -56,8 +45,8 @@ export function RegisterDialogContent({ width: '100%', borderRadius: 4, }} - value={registerUri} - viewBox={`0 0 256 256`} + value={bitcashRegisterUri} + viewBox={'0 0 256 256'} /> {/* +
{hasSession && ( @@ -73,9 +72,7 @@ export function SessionButton() { className="w-44 border-[#845BBF] bg-background text-center" >
    - {/*
  • - Wallet -
  • */} + {/* biome-ignore lint/a11y/useKeyWithClickEvents: not needed rn */}
  • Sign Out
  • diff --git a/apps/webapp/components/layout/session/session-dialog.tsx b/apps/webapp/components/dialogs/session/session-dialog.tsx similarity index 79% rename from apps/webapp/components/layout/session/session-dialog.tsx rename to apps/webapp/components/dialogs/session/session-dialog.tsx index b047f4474..7a8fed287 100644 --- a/apps/webapp/components/layout/session/session-dialog.tsx +++ b/apps/webapp/components/dialogs/session/session-dialog.tsx @@ -1,9 +1,10 @@ 'use client' -import { SessionDialogContent } from '@/components/layout/session/login-dialog-content' -import { RegisterDialogContent } from '@/components/layout/session/register-dialog-content' +import { RegisterDialogContent } from '@/components/dialogs/session/register-dialog-content' import { Dialog, DialogContent } from '@/components/ui/dialog' import { useSession } from '@/hooks/use-session' import { useState } from 'react' +import { SessionDialogContent } from './login-dialog-content' +import type { BitcashAccessContentType } from './session-dialog.type' export function SessionDialog({ defaultContent = 'login', @@ -30,5 +31,3 @@ export function SessionDialog({ interface BitcashAccessProps { defaultContent?: BitcashAccessContentType } - -export type BitcashAccessContentType = 'login' | 'register' diff --git a/apps/webapp/components/dialogs/session/session-dialog.type.ts b/apps/webapp/components/dialogs/session/session-dialog.type.ts new file mode 100644 index 000000000..66cae081d --- /dev/null +++ b/apps/webapp/components/dialogs/session/session-dialog.type.ts @@ -0,0 +1 @@ +export type BitcashAccessContentType = 'login' | 'register' diff --git a/apps/webapp/components/layout/footer/newsletter.tsx b/apps/webapp/components/layout/footer/newsletter.tsx index cdb8e6ce6..4b0f69209 100644 --- a/apps/webapp/components/layout/footer/newsletter.tsx +++ b/apps/webapp/components/layout/footer/newsletter.tsx @@ -1,5 +1,5 @@ 'use client' -import { subscribeToNewsletter } from '@/actions' +import { subscribeToNewsletter } from '@/app/actions/general' import { Button, buttonVariants } from '@/components/ui/button' import { IconDiscord, IconDownRightArrow } from '@/components/ui/icons' import { cn, motionProps } from '@/lib/utils' diff --git a/apps/webapp/components/layout/header/bitcash-access.tsx b/apps/webapp/components/layout/header/bitcash-access.tsx deleted file mode 100644 index 70da8027e..000000000 --- a/apps/webapp/components/layout/header/bitcash-access.tsx +++ /dev/null @@ -1,114 +0,0 @@ -'use client' -import { LoginDialogContent } from '@/components/dialogs/login' -import { RegisterDialogContent } from '@/components/dialogs/register' -import { Button, type buttonVariants } from '@/components/ui/button' -import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog' -import { IconDownRightArrow } from '@/components/ui/icons' -import { useErc20Balance } from '@/hooks/use-balance' -import { useSession } from '@/hooks/use-session' -import { cn } from '@/lib/utils' -import { TestnetUSDCred } from '@repo/contracts' -import { runtimeEnv } from '@repo/utils' -import type { VariantProps } from 'class-variance-authority' -import { LucideWallet } from 'lucide-react' -import { useRouter, useSearchParams } from 'next/navigation' -import { useEffect, useState } from 'react' -// import { bitcashLogin } from '@/lib/esr' -import { useToggle } from 'react-use' -import { useAccount } from 'wagmi' - -export function BitcashAccessButton({ - defaultContent = 'login', - buttonLabel = 'Log In', - buttonClassName, - buttonStyle, -}: BitcashAccessProps) { - const [open, toggleOpen] = useToggle(false) - const [dialogContent, setDialogContent] = - useState(defaultContent) - const { session, loginUri, newSessionId } = useSession() - const { address } = useAccount() - const searchParams = useSearchParams() - const balance = useErc20Balance({ - abi: TestnetUSDCred.abi, - contract: TestnetUSDCred.address, - address: address || '0x', - chainId: TestnetUSDCred.chainId, - }) - const isLogin = dialogContent === 'login' - const router = useRouter() - - useEffect(() => { - !searchParams.has('bitcash_explorer') && isLogin && toggleOpen(false) - }, [session, searchParams]) - - useEffect(() => { - if (!loginUri || !open || !isLogin) return - // post request to parent if present - window.parent && - window.parent.postMessage({ eventType: 'esr', code: loginUri }, '*') - - // redirect with esr and callback on mobile - if (runtimeEnv.isMobile && !searchParams.has('bitcash_explorer')) { - const params = new URLSearchParams() - params.append('esr_code', loginUri.replace('esr://', '')) - const callbackUrl = `${window.location.href}?session_id=${newSessionId}` - console.log('💥 callbackUrl', callbackUrl) - const encodedCallbackUrl = encodeURIComponent(callbackUrl) - params.append('callback', encodedCallbackUrl) - router.push(`https://app.bitcash.org/login?${params.toString()}`) - } - }, [open, loginUri, searchParams]) - - if (session && isLogin) - return ( - - ) - - // never show the qr on mobile or bitcash explorer - const hideQr = runtimeEnv.isMobile || searchParams.has('bitcash_explorer') - - return ( - - - - - - {/* @ts-ignore */} - - {!hideQr && isLogin && ( - - )} - {!isLogin && ( - - )} - - - ) -} - -interface BitcashAccessProps { - buttonClassName?: string - defaultContent?: BitcashAccessContentType - buttonLabel?: string - buttonStyle?: VariantProps -} - -export type BitcashAccessContentType = 'login' | 'register' diff --git a/apps/webapp/components/layout/header/index.tsx b/apps/webapp/components/layout/header/index.tsx index bdb2ecddd..c316d552c 100644 --- a/apps/webapp/components/layout/header/index.tsx +++ b/apps/webapp/components/layout/header/index.tsx @@ -7,7 +7,7 @@ import { appConfig } from '@/lib/config' import type { LangProp } from '@/types/routing.type' import dynamic from 'next/dynamic' import { Suspense } from 'react' -import { SessionButtonLoader } from '../session/session-button' +import { SessionButtonLoader } from '../../dialogs/session/session-button' import { LangSelector } from './lang-selector' import { MobileNavLoader } from './mobile-nav' import { Navigation } from './new-nav' @@ -24,24 +24,24 @@ export function Header({ lang, dict }: HeaderProps) {
{/* Center Section (Navigation Links) */} -
+
+ {/* Right Section (Buttons/Language Selector) */} -
-
+
+
Login}>
{appConfig.features.i18n ? : null} -
+
@@ -59,7 +59,8 @@ const DynamicMobileNav = dynamic( ) const DynamicSessionButton = dynamic( - () => import('../session/session-button').then((c) => c.SessionButton), + () => + import('../../dialogs/session/session-button').then((c) => c.SessionButton), { loading: SessionButtonLoader, ssr: false, diff --git a/apps/webapp/components/layout/header/lang-selector/index.tsx b/apps/webapp/components/layout/header/lang-selector/index.tsx index eedc72ce2..8f88ebe0b 100644 --- a/apps/webapp/components/layout/header/lang-selector/index.tsx +++ b/apps/webapp/components/layout/header/lang-selector/index.tsx @@ -3,10 +3,7 @@ import { Button } from '@/components/ui/button' import { DropdownMenu, DropdownMenuContent, - // DropdownMenuLabel, - // DropdownMenuSeparator, - DropdownMenuItem, - DropdownMenuTrigger, + DropdownMenuTrigger } from '@/components/ui/dropdown-menu' import type { LangProp } from '@/types/routing.type' import { ChevronDownIcon } from 'lucide-react' @@ -19,7 +16,7 @@ export function LangSelector({ lang }: LangProp) {
diff --git a/apps/webapp/components/routes/about/about-bitlauncher/index.tsx b/apps/webapp/components/routes/about/about-bitlauncher/index.tsx index 97dff2723..949ffc99a 100644 --- a/apps/webapp/components/routes/about/about-bitlauncher/index.tsx +++ b/apps/webapp/components/routes/about/about-bitlauncher/index.tsx @@ -1,5 +1,5 @@ -import { LearnSection } from '@/components/layout/section/learn-section' -import StepsSection from '@/components/layout/section/steps-section' +import { LearnSection } from '@/components/routes/home/section/learn-section' +import StepsSection from '@/components/routes/home/section/steps-section' import { Banner } from '@/components/shared/banner' import { CommunityCard } from '@/components/shared/community-card' import { getDictionary } from '@/dictionaries' diff --git a/apps/webapp/components/routes/home/section/faq-section.tsx b/apps/webapp/components/routes/home/section/faq-section.tsx new file mode 100644 index 000000000..ad8dc1409 --- /dev/null +++ b/apps/webapp/components/routes/home/section/faq-section.tsx @@ -0,0 +1,39 @@ +import { Section } from '@/components/shared/section'; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from '@/components/ui/accordion'; +import type { LangProp } from '@/types/routing.type'; + +export function FAQ({ lang, dict }: FAQProps) { + return ( +
+
+ + {dict.faq.questions.map( + (item: { question: string; answer: string }, index: number) => ( + + + {item.question} + + + {item.answer} + + + ), + )} + +
+
+ ) +} + +export interface FAQProps extends LangProp { + dict: any +} diff --git a/apps/webapp/components/routes/home/section/learn-section.tsx b/apps/webapp/components/routes/home/section/learn-section.tsx new file mode 100644 index 000000000..ad31546a0 --- /dev/null +++ b/apps/webapp/components/routes/home/section/learn-section.tsx @@ -0,0 +1,119 @@ +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import Image from 'next/image' +import Link from 'next/link' +import { Section } from '../../../shared/section' + +export function LearnSection() { + const mainCard = content.cards[0] + const secondaryCards = content.cards.filter((_, i) => i > 0) + return ( +
+
+ + +
+ + + + {mainCard.title} + + + + {mainCard.title} + +
+ + +
+ {mainCard.paragraphs.map((p, i) => ( +

+ {p} +

+ ))} +
+
+
+ + + +
+ {secondaryCards.map((card, i) => ( + + +
+ + + {card.title} + +
+ + + + + {card.title} + +
+ + + ))} +
+
+
+ ) +} + +const content = { + sectionTitle: 'Learn More About Bitlauncher', + cards: [ + { + title: 'How to Partcipate in the Bitlauncher Presale?', + paragraphs: [ + "A good place to start is: what is Bitlauncher? (We'll give you the brief version). Bitlauncher is a platform that connects young projects with early community members through initial decentralized offerings (IDOS). It provides a unique opportunity for contributors to engage with up-and-coming tech innovations.", + 'By participating in an IDO on Bitlauncher, users can gain early access to tokens from new blockchain projects. This early access can potentially lead to significant benefits if the projects grow in value and popularity. Bitlauncher aims to democratize the investment process, making it accessible to a broader audience.', + ], + images: [ + '/images/home/platform-circles.webp', + '/images/home/platform-circles.png', + ], + articleLink: + '/blog/bitlauncher/welcome-to-the-bitlauncher-presale-starting-september-15th', + }, + { + title: 'What is the Bitlauncher ($BL) Token?', + paragraphs: [], + images: ['/images/home/bl-coins.webp', '/images/home/bl-coins.png'], + articleLink: '/blog/bitlauncher/what-is-the-bitlauncher-bl-token', + }, + { + title: 'What is a Public Token Presale?', + paragraphs: [], + images: ['/images/home/glass.webp', '/images/home/glass.png'], + articleLink: '/blog/bitlauncher/what-is-a-public-token-presale', + }, + ], +} diff --git a/apps/webapp/components/routes/home/section/recent-articles.tsx b/apps/webapp/components/routes/home/section/recent-articles.tsx new file mode 100644 index 000000000..cd8a4e036 --- /dev/null +++ b/apps/webapp/components/routes/home/section/recent-articles.tsx @@ -0,0 +1,377 @@ +import { BlogSections } from '@/components/routes/blog/blog-sections' +import { + type MediaSection, + MediaSections, +} from '@/components/shared/media-sections' +import { Section } from '@/components/shared/section' +import type { ArticlesSection } from '@/services/datocms' +import type { LangProp } from '@/types/routing.type' + +export async function RecentArticles({ lang }: LangProp) { + const recentMedia: MediaSection[] = [ + { + title: 'Shorts', + videos: latestShorts, + link: { + href: 'https://www.youtube.com/@bitlauncher', + label: 'More Shorts', + }, + }, + ] + + const recentArcticles = [ + { + name: 'Recent Articles', + slug: 'ai', + articles: [ + { + id: 'SpdLuuYEQgW8rwSHNzhmxA', + topics: ['Apps'], + title: + 'Masterbots: Elevating AI Beyond ChatGPT with Social Sharing and User-Friendly Innovation', + slug: 'masterbots-elevating-ai-beyond-chatgpt-with-social-sharing-and-user-friendly-inno', + authorName: 'Jun Dam', + authorPicture: { + url: 'https://www.datocms-assets.com/101962/1686758812-jdamx170-removebg-preview.png', + }, + _publishedAt: '2024-04-04T23:48:35+01:00', + description: + 'The blog introduces Masterbots, a platform revolutionizing AI interaction with user-friendly, domain-specific chatbots and a unique social sharing feature, inviting collaborators to join its open-source, community-driven development.', + thumbnail: { + url: 'https://www.datocms-assets.com/101962/1712270604-screenshot-2024-04-04-at-3-43-11-pm.png', + }, + contentBlock: [], + seo: null, + }, + { + id: '190259319', + topics: ['Summary', 'LLM', 'Training'], + title: + 'Latent Space Podcast 8-16-23 Summary: The Mathematics of Training LLMs with Quentin Anthony', + slug: 'latent-space-podcast-8-16-23-summary-the-mathematics-of-training-llms-with-que', + authorName: 'Prof. Otto Nomos', + authorPicture: { + url: 'https://www.datocms-assets.com/101962/1692842125-profottonomosheadshot.png', + }, + _publishedAt: '2023-10-05T09:19:45+01:00', + description: + 'Explore the math behind training LLMs with Quentin Anthony from Eleuther AI. Dive into the Transformers Math 101 article & master distributed training techniques for peak GPU performance.', + thumbnail: { + url: 'https://www.datocms-assets.com/101962/1692324088-screenshot-2023-08-17-at-9-59-17-pm.png', + }, + contentBlock: [], + seo: null, + }, + { + id: '190259129', + topics: ['LLM', 'Hardware', 'Summary', 'Edge'], + title: + 'Latent Space Podcast 8-10-23 Summary: LLMs Everywhere - Running 70B Models in Browsers', + slug: 'latent-space-podcast-8-10-23-summary-llms-everywhere-running-70b-models-in-browse', + authorName: 'Prof. Otto Nomos', + authorPicture: { + url: 'https://www.datocms-assets.com/101962/1692842125-profottonomosheadshot.png', + }, + _publishedAt: '2023-10-05T09:18:37+01:00', + description: + "Explore the magic of MLC with Tianqi Chen: deploying 70B models on browsers & iPhones. Dive into XGBoost, TVM's creation, & the future of universal AI deployments. ", + thumbnail: { + url: 'https://www.datocms-assets.com/101962/1691894611-screenshot-2023-08-12-at-10-42-43-pm.png', + }, + contentBlock: [], + seo: null, + }, + { + id: '190259087', + topics: ['Summary', 'LLM', 'Code', 'Open Source', 'Small Models'], + title: + 'Latent Space Podcast 8-4-23 Summary: Latent Space x AI Breakdown - Crossover Podcast', + slug: 'latent-space-podcast-8-4-23-summary-latent-space-x-ai-breakdown-crossover-pod', + authorName: 'Prof. Otto Nomos', + authorPicture: { + url: 'https://www.datocms-assets.com/101962/1692842125-profottonomosheadshot.png', + }, + _publishedAt: '2023-10-05T09:16:33+01:00', + description: + 'Join AI Breakdown & Latent Space for the summer AI tech roundup: Dive into GPT4.5, Llama 2, AI tools, the rising AI engineer, and more!', + thumbnail: { + url: 'https://www.datocms-assets.com/101962/1691539617-screenshot-2023-08-08-at-8-02-52-pm.png', + }, + contentBlock: [], + seo: null, + }, + { + id: '190259087', + topics: ['Summary', 'LLM', 'Code', 'Open Source', 'Small Models'], + title: + 'Latent Space Podcast 8-4-23 Summary: Latent Space x AI Breakdown - Crossover Podcast', + slug: 'latent-space-podcast-8-4-23-summary-latent-space-x-ai-breakdown-crossover-pod', + authorName: 'Prof. Otto Nomos', + authorPicture: { + url: 'https://www.datocms-assets.com/101962/1692842125-profottonomosheadshot.png', + }, + _publishedAt: '2023-10-05T09:16:33+01:00', + description: + 'Join AI Breakdown & Latent Space for the summer AI tech roundup: Dive into GPT4.5, Llama 2, AI tools, the rising AI engineer, and more!', + thumbnail: { + url: 'https://www.datocms-assets.com/101962/1691539617-screenshot-2023-08-08-at-8-02-52-pm.png', + }, + contentBlock: [], + seo: null, + }, + ], + }, + ] + + return ( +
+ + +
+ ) +} + +const latestShorts = [ + { + kind: 'youtube#playlistItem', + etag: 'gNlGgzV_GELSlM0eMgLN2ESUYm0', + id: 'UEw2QktHVnFla2hCXzNPaEZZX3pwSndtYWFWNnNMeEx3Si4xRDJGOTc4RkUxMzUwMUFG', + snippet: { + publishedAt: '2024-05-20T04:55:10Z', + channelId: 'UChzuWZjo_PvOrRTDfkojp3w', + title: + 'From Prison to Bitcoin A Journey to Freedom #bitcoin #crypto #liberty', + description: 'Full video here: https://youtu.be/IXhECniE6-4', + thumbnails: { + default: { + url: 'https://i.ytimg.com/vi/OlrfEz5dqv0/default.jpg', + width: 120, + height: 90, + }, + medium: { + url: 'https://i.ytimg.com/vi/OlrfEz5dqv0/mqdefault.jpg', + width: 320, + height: 180, + }, + high: { + url: 'https://i.ytimg.com/vi/OlrfEz5dqv0/hqdefault.jpg', + width: 480, + height: 360, + }, + standard: { + url: 'https://i.ytimg.com/vi/OlrfEz5dqv0/sddefault.jpg', + width: 640, + height: 480, + }, + maxres: { + url: 'https://i.ytimg.com/vi/OlrfEz5dqv0/maxresdefault.jpg', + width: 1280, + height: 720, + }, + }, + channelTitle: 'Bitlauncher | Bitcash', + playlistId: 'PL6BKGVqekhB_3OhFY_zpJwmaaV6sLxLwJ', + position: 0, + resourceId: { + kind: 'youtube#video', + videoId: 'OlrfEz5dqv0', + }, + videoOwnerChannelTitle: 'Bitlauncher | Bitcash', + videoOwnerChannelId: 'UChzuWZjo_PvOrRTDfkojp3w', + }, + }, + { + kind: 'youtube#playlistItem', + etag: 'rsf4xjYzsvYXGtBJB4U6LtE9J74', + id: 'UEw2QktHVnFla2hCXzNPaEZZX3pwSndtYWFWNnNMeEx3Si44NzQ1OTI1OUFFM0NFRTc5', + snippet: { + publishedAt: '2024-05-20T05:20:57Z', + channelId: 'UChzuWZjo_PvOrRTDfkojp3w', + title: 'My First Bitcoin: A Journey Begins #bitcoin #crypto', + description: 'Full video here: https://youtu.be/O0ZMs_UccMY', + thumbnails: { + default: { + url: 'https://i.ytimg.com/vi/z-dKmcv_L-M/default.jpg', + width: 120, + height: 90, + }, + medium: { + url: 'https://i.ytimg.com/vi/z-dKmcv_L-M/mqdefault.jpg', + width: 320, + height: 180, + }, + high: { + url: 'https://i.ytimg.com/vi/z-dKmcv_L-M/hqdefault.jpg', + width: 480, + height: 360, + }, + standard: { + url: 'https://i.ytimg.com/vi/z-dKmcv_L-M/sddefault.jpg', + width: 640, + height: 480, + }, + maxres: { + url: 'https://i.ytimg.com/vi/z-dKmcv_L-M/maxresdefault.jpg', + width: 1280, + height: 720, + }, + }, + channelTitle: 'Bitlauncher | Bitcash', + playlistId: 'PL6BKGVqekhB_3OhFY_zpJwmaaV6sLxLwJ', + position: 1, + resourceId: { + kind: 'youtube#video', + videoId: 'z-dKmcv_L-M', + }, + videoOwnerChannelTitle: 'Bitlauncher | Bitcash', + videoOwnerChannelId: 'UChzuWZjo_PvOrRTDfkojp3w', + }, + }, + { + kind: 'youtube#playlistItem', + etag: '-ZQffBSEpAK6_lpTkVvdNpYnp7s', + id: 'UEw2QktHVnFla2hCXzNPaEZZX3pwSndtYWFWNnNMeEx3Si5ENjg3MEUyQ0IzODMzQThB', + snippet: { + publishedAt: '2024-05-20T05:07:26Z', + channelId: 'UChzuWZjo_PvOrRTDfkojp3w', + title: + 'Protect Your Privacy in the Digital Age #crypto #bitcoin #privacy', + description: 'Full video here: https://youtu.be/IXhECniE6-4', + thumbnails: { + default: { + url: 'https://i.ytimg.com/vi/PRXAO31uC8c/default.jpg', + width: 120, + height: 90, + }, + medium: { + url: 'https://i.ytimg.com/vi/PRXAO31uC8c/mqdefault.jpg', + width: 320, + height: 180, + }, + high: { + url: 'https://i.ytimg.com/vi/PRXAO31uC8c/hqdefault.jpg', + width: 480, + height: 360, + }, + standard: { + url: 'https://i.ytimg.com/vi/PRXAO31uC8c/sddefault.jpg', + width: 640, + height: 480, + }, + maxres: { + url: 'https://i.ytimg.com/vi/PRXAO31uC8c/maxresdefault.jpg', + width: 1280, + height: 720, + }, + }, + channelTitle: 'Bitlauncher | Bitcash', + playlistId: 'PL6BKGVqekhB_3OhFY_zpJwmaaV6sLxLwJ', + position: 2, + resourceId: { + kind: 'youtube#video', + videoId: 'PRXAO31uC8c', + }, + videoOwnerChannelTitle: 'Bitlauncher | Bitcash', + videoOwnerChannelId: 'UChzuWZjo_PvOrRTDfkojp3w', + }, + }, + { + kind: 'youtube#playlistItem', + etag: 'UqFm-kVdmHh0tYBqG2Kxn3pcPLU', + id: 'UEw2QktHVnFla2hCXzNPaEZZX3pwSndtYWFWNnNMeEx3Si42MzE1QTJBMEI3NjI4Rjk5', + snippet: { + publishedAt: '2024-06-25T02:54:26Z', + channelId: 'UChzuWZjo_PvOrRTDfkojp3w', + title: + 'Trust is Key in Crypto Market Making #crypto #bitcoin #investing #trading', + description: 'Watch full video at: https://youtu.be/Kfk6T4QCUMI', + thumbnails: { + default: { + url: 'https://i.ytimg.com/vi/2q2MGoGdnlI/default.jpg', + width: 120, + height: 90, + }, + medium: { + url: 'https://i.ytimg.com/vi/2q2MGoGdnlI/mqdefault.jpg', + width: 320, + height: 180, + }, + high: { + url: 'https://i.ytimg.com/vi/2q2MGoGdnlI/hqdefault.jpg', + width: 480, + height: 360, + }, + standard: { + url: 'https://i.ytimg.com/vi/2q2MGoGdnlI/sddefault.jpg', + width: 640, + height: 480, + }, + maxres: { + url: 'https://i.ytimg.com/vi/2q2MGoGdnlI/maxresdefault.jpg', + width: 1280, + height: 720, + }, + }, + channelTitle: 'Bitlauncher | Bitcash', + playlistId: 'PL6BKGVqekhB_3OhFY_zpJwmaaV6sLxLwJ', + position: 3, + resourceId: { + kind: 'youtube#video', + videoId: '2q2MGoGdnlI', + }, + videoOwnerChannelTitle: 'Bitlauncher | Bitcash', + videoOwnerChannelId: 'UChzuWZjo_PvOrRTDfkojp3w', + }, + }, + { + kind: 'youtube#playlistItem', + etag: 'AWv0QCB9nrKPlsxW7xj5onixZCw', + id: 'UEw2QktHVnFla2hCXzNPaEZZX3pwSndtYWFWNnNMeEx3Si5CMUM0NzY5NzdEQzlGRjAx', + snippet: { + publishedAt: '2024-05-16T03:07:47Z', + channelId: 'UChzuWZjo_PvOrRTDfkojp3w', + title: "From NASA to Crypto: Chjango's Journey #crypto #bitcoin #cosmos", + description: 'Full video here: https://youtu.be/bH8Z80gspGM', + thumbnails: { + default: { + url: 'https://i.ytimg.com/vi/uqh9zkJI_Tk/default.jpg', + width: 120, + height: 90, + }, + medium: { + url: 'https://i.ytimg.com/vi/uqh9zkJI_Tk/mqdefault.jpg', + width: 320, + height: 180, + }, + high: { + url: 'https://i.ytimg.com/vi/uqh9zkJI_Tk/hqdefault.jpg', + width: 480, + height: 360, + }, + standard: { + url: 'https://i.ytimg.com/vi/uqh9zkJI_Tk/sddefault.jpg', + width: 640, + height: 480, + }, + maxres: { + url: 'https://i.ytimg.com/vi/uqh9zkJI_Tk/maxresdefault.jpg', + width: 1280, + height: 720, + }, + }, + channelTitle: 'Bitlauncher | Bitcash', + playlistId: 'PL6BKGVqekhB_3OhFY_zpJwmaaV6sLxLwJ', + position: 4, + resourceId: { + kind: 'youtube#video', + videoId: 'uqh9zkJI_Tk', + }, + videoOwnerChannelTitle: 'Bitlauncher | Bitcash', + videoOwnerChannelId: 'UChzuWZjo_PvOrRTDfkojp3w', + }, + }, +] diff --git a/apps/webapp/components/routes/home/section/short-video-section.tsx b/apps/webapp/components/routes/home/section/short-video-section.tsx new file mode 100644 index 000000000..d6c738aa0 --- /dev/null +++ b/apps/webapp/components/routes/home/section/short-video-section.tsx @@ -0,0 +1,63 @@ +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' +import type { YouTubePlaylistItem } from '@/services/youtube/index' +import Image from 'next/image' +import { Card } from '../../../ui/card' + +export function ShortVideo({ video }: { video: YouTubePlaylistItem }) { + return ( + + + + {video.snippet.title} + + + + + {video.snippet.title} + {video.snippet.description} + + +
+