diff --git a/searching-front/app/core/components/Footer/Footer.tsx b/searching-front/app/core/components/Footer/Footer.tsx index 6303e2b..cfd690c 100644 --- a/searching-front/app/core/components/Footer/Footer.tsx +++ b/searching-front/app/core/components/Footer/Footer.tsx @@ -34,8 +34,8 @@ const Footer = () => { return (
- +
) diff --git a/searching-front/app/core/components/Link/styles.module.css b/searching-front/app/core/components/Link/styles.module.css index 1b1b213..85513cd 100644 --- a/searching-front/app/core/components/Link/styles.module.css +++ b/searching-front/app/core/components/Link/styles.module.css @@ -1,6 +1,6 @@ .root { text-decoration: none; - display: inline-block; + display: inline-flex; /* size */ font-size: 18px; @@ -8,6 +8,9 @@ } .root a { text-decoration: none; + display: inline-flex; + justify-content: center; + align-items: center; } .root a.wide::before { diff --git a/searching-front/app/core/helpers/common.ts b/searching-front/app/core/helpers/common.ts index a28330c..c04324e 100644 --- a/searching-front/app/core/helpers/common.ts +++ b/searching-front/app/core/helpers/common.ts @@ -9,4 +9,7 @@ export const isNode = () => { return typeof window !== "object" } -export const getDomainFromUrl = (url: string) => url.match(/http:\/\/(.*).ton/)?.[1] \ No newline at end of file +export const getDomainFromUrl = (url: string) => url.match(/http:\/\/(.*).ton/)?.[1] + +export const getObserverUrlByAddress = (address: string) => `https://tonscan.org/address/${address}` + diff --git a/searching-front/app/core/icons/TonLogoWithoutBg.tsx b/searching-front/app/core/icons/TonLogoWithoutBg.tsx new file mode 100644 index 0000000..c0a1e93 --- /dev/null +++ b/searching-front/app/core/icons/TonLogoWithoutBg.tsx @@ -0,0 +1,12 @@ +const TonLogoWithoutBg = () => ( + + + +) + +export default TonLogoWithoutBg diff --git a/searching-front/app/core/pages/State/State.tsx b/searching-front/app/core/pages/State/State.tsx index 4585e5d..ab2106e 100644 --- a/searching-front/app/core/pages/State/State.tsx +++ b/searching-front/app/core/pages/State/State.tsx @@ -9,13 +9,14 @@ import "chart.js/auto" import getActualSitesState from "app/stateSites/queries/getActualSitesState" import getHistoryOfSitesState from "app/stateSites/queries/getHistoryOfSitesState" import { InfluxPeriod } from "services/modules/influxdb/types" -import { cn, getDomainFromUrl } from "app/core/helpers/common" +import { cn, getDomainFromUrl, getObserverUrlByAddress } from "app/core/helpers/common" import s from "./styles.module.css" import { NftDomain } from "@prisma/client" import Button from "app/auth/components/Button" import Link from "app/core/components/Link" import { count } from "app/core/helpers/metrika" +import TonLogoWithoutBg from "app/core/icons/TonLogoWithoutBg" interface HistoryOfStateItem { value: number @@ -89,7 +90,7 @@ const State = ({ historyOfState: historyOfStatePreloaded, lastWeekNewSites, }: StatePageProps) => { - const nowDate = format(new Date(),'d MMMM').toLowerCase(); + const nowDate = format(new Date(), "d MMMM").toLowerCase() const [historyPeriod, setHistoryPeriod] = useState(InfluxPeriod.D) const { t } = useTranslation() const [historyOfState] = useQuery(getHistoryOfSitesState, historyPeriod, { @@ -115,19 +116,43 @@ const State = ({
{lastWeekNewSites.map((i) => ( - count('from_state_page_to_site')} - > - {getDomainFromUrl(i.address)} - - +
+ count("from_state_page_to_site")} + wide + title="Open tonsite" + > + {getDomainFromUrl(i.address)} + + + + {i.walletAddress && i.tonBalance && ( + count("from_state_page_to_tonscan")} + title="Open wallet in tonscan" + wide + > + ~ + {new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }) + .format(+i.tonBalance) + .replace("$", "") + .replace(",", " ")} +
+ +
+ + )} +
))}
diff --git a/searching-front/app/core/pages/State/styles.module.css b/searching-front/app/core/pages/State/styles.module.css index 56d9981..d9244ff 100644 --- a/searching-front/app/core/pages/State/styles.module.css +++ b/searching-front/app/core/pages/State/styles.module.css @@ -64,16 +64,15 @@ flex-direction: column; } .newestListItem { - padding: 24px 34px; border-radius: var(--border_radius_base); border: 1px solid var(--border_color_main); text-transform: capitalize; font-weight: 700; font-size: 16px; line-height: 20px; - cursor: pointer; position: relative; box-sizing: border-box; + display: flex; } .siteButton.siteButton { @@ -82,16 +81,12 @@ font-size: 20px; line-height: 25px; border-radius: 16px; - transition: opacity 0.2s ease-in-out; padding: 0; background-color: var(--background_secondary); margin-left: 8px; - } -.newestListItem:hover .siteButton.siteButton { - background-color: var(--button_primary); -} + .button { position: absolute; @@ -146,3 +141,49 @@ background: var(--button_primary); color: white; } + +.newestListItemLeft { + position: relative; + padding: 24px 0 24px 34px; + flex: 1 1 70%; +} + +.newestListItemRight { + padding: 24px 34px 24px 0px; + flex: 1 1 30%; + position: relative; + display: flex; + align-items: center; + border-left: 1px solid var(--border_color_main); + justify-content: flex-end; + white-space: nowrap; + font-size: 12px !important; + background: inherit; +} + +.newestListItemLeft:hover .siteButton.siteButton { + background-color: var(--button_primary); +} + +.newestListItemRight:hover .tonScanIcon{ + color: white; + background: var(--button_primary); + transition: all .3s ease-in-out; +} + +.tonScanIcon{ + width: 24px; + height: 24px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + color: var(--button_primary); + margin-left: 4px; +} + + + +.siteButton, .tonScanIcon { + transition: background-color .2s ease-in-out; +} diff --git a/searching-front/package-lock.json b/searching-front/package-lock.json index bf01a79..a9b8482 100644 --- a/searching-front/package-lock.json +++ b/searching-front/package-lock.json @@ -45,7 +45,7 @@ "sanitize-html": "2.7.1", "textversionjs": "1.1.3", "tonapi-sdk-js": "0.18.0", - "tonweb": "0.0.55", + "tonweb": "0.0.57", "ts-node": "10.9.1", "zod": "3.17.3" }, @@ -15585,9 +15585,9 @@ } }, "node_modules/tonweb": { - "version": "0.0.55", - "resolved": "https://registry.npmjs.org/tonweb/-/tonweb-0.0.55.tgz", - "integrity": "sha512-C6YUTmHEzAHayUZMh7TWkoPr5lFAuetAO/7CmIumRQm85aeFcTY86TeCsJz0rmf2vmKPlJE2hqjByN5cYFKQfA==", + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/tonweb/-/tonweb-0.0.57.tgz", + "integrity": "sha512-/kqRn3/H1nw2bJ68uOtvwkOj6/9EgYaYpMYAXs93I2pLdJZxVKNwTuZ7weGKVmrn9tOt/nCNooq3OAZDSAVUSg==", "dependencies": { "@ledgerhq/hw-transport-web-ble": "5.48.0", "@ledgerhq/hw-transport-webhid": "5.48.0", @@ -27855,9 +27855,9 @@ } }, "tonweb": { - "version": "0.0.55", - "resolved": "https://registry.npmjs.org/tonweb/-/tonweb-0.0.55.tgz", - "integrity": "sha512-C6YUTmHEzAHayUZMh7TWkoPr5lFAuetAO/7CmIumRQm85aeFcTY86TeCsJz0rmf2vmKPlJE2hqjByN5cYFKQfA==", + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/tonweb/-/tonweb-0.0.57.tgz", + "integrity": "sha512-/kqRn3/H1nw2bJ68uOtvwkOj6/9EgYaYpMYAXs93I2pLdJZxVKNwTuZ7weGKVmrn9tOt/nCNooq3OAZDSAVUSg==", "requires": { "@ledgerhq/hw-transport-web-ble": "5.48.0", "@ledgerhq/hw-transport-webhid": "5.48.0", diff --git a/searching-front/package.json b/searching-front/package.json index a82b552..b70db67 100644 --- a/searching-front/package.json +++ b/searching-front/package.json @@ -64,7 +64,7 @@ "sanitize-html": "2.7.1", "textversionjs": "1.1.3", "tonapi-sdk-js": "0.18.0", - "tonweb": "0.0.55", + "tonweb": "0.0.57", "ts-node": "10.9.1", "zod": "3.17.3" }, diff --git a/searching-front/services/domain-watcher.ts b/searching-front/services/domain-watcher.ts index 3941848..1f2ad95 100644 --- a/searching-front/services/domain-watcher.ts +++ b/searching-front/services/domain-watcher.ts @@ -1,4 +1,4 @@ -import tonweb from "tonweb" +import TonWeb from "tonweb" import { JettonApi, DNSApi, @@ -13,19 +13,30 @@ import db from "../db/index" import axios from "axios" import { getTonProxy } from "./helpers" +const dnsApi = new DNSApi() interface SearchNFTItemsParams { limit: number offset: number } const getFullUrl = (dmn: string) => `http://${dmn}` -const upsertDmn = async (dmn: string, available: boolean) => { - const domainFromDB = await db.nftDomain.findFirst({where:{address: getFullUrl(dmn)}}) - const shouldUpdateFirstAvailableDate = !domainFromDB?.firstAvailableDate && available; - const upsertObj = { available, address: getFullUrl(dmn) }; - if(shouldUpdateFirstAvailableDate){ - upsertObj.firstAvailableDate = new Date(); +interface UpsertDmnParams { + available: boolean + walletAddress?: string + tonBalance?: number +} +const upsertDmn = async ( + dmn: string, + { available, tonBalance, walletAddress }: UpsertDmnParams +) => { + const domainFromDB = await db.nftDomain.findFirst({ where: { address: getFullUrl(dmn) } }) + const shouldUpdateFirstAvailableDate = !domainFromDB?.firstAvailableDate && available + + const upsertObj = { available, address: getFullUrl(dmn), domainName: dmn, walletAddress, tonBalance } + + if (shouldUpdateFirstAvailableDate) { + upsertObj.firstAvailableDate = new Date() } return await db.nftDomain.upsert({ where: { @@ -36,7 +47,6 @@ const upsertDmn = async (dmn: string, available: boolean) => { }) } - const wait = (time: number) => new Promise((resolve) => setTimeout(() => resolve(true), time)) const searchNFTItems = async ({ limit, offset }: SearchNFTItemsParams) => { @@ -53,6 +63,7 @@ const searchNFTItems = async ({ limit, offset }: SearchNFTItemsParams) => { ) return data.nft_items } catch (e) { + console.log("error fetch items", e) return searchNFTItems({ limit, offset }) } } @@ -71,12 +82,40 @@ const fetchTonSite = async (url: string) => { } return url } catch (e) { + // console.log('restart fetch domains',e) throw url } } +const tonweb = new TonWeb( + new TonWeb.HttpProvider("https://toncenter.com/api/v2/jsonRPC", { + apiKey: "2594e0a460095b81258b639950a16d9718fa3cbb1ba8a2eb87fbb4586a529b8f", + }) +) + +const fetchDomainInfo = async (url: string) => { + try { + await wait(1) + + const address = (await tonweb.dns.getWalletAddress(url))?.toString(true, true, true) + + let balance + if (address) { + balance = tonweb.utils.fromNano(await tonweb.getBalance(address)) + return { + balance, + address, + } + } + return null + } catch (e) { + return null + } +} + const main = async () => new Promise(async (resolve) => { + // const result = await tonweb.dns.getWalletAddress('just-for-test.ton') // Receive typed array of owner nfts let count = 0 while (true) { @@ -86,26 +125,25 @@ const main = async () => offset: count * portion, }) if (nftItems.length) { - console.time('fetchDomain') const promises1: Promise[] = [] for (let i = 0; i < nftItems.length; i++) { const nftDomainItem = nftItems[i] if (nftDomainItem.dns) { - - promises1.push(fetchTonSite(nftDomainItem.dns) - .then(async (dmn) => { - console.log("success dmn", dmn) - upsertDmn(dmn, true) - }) - .catch((dmn) => { - upsertDmn(dmn,false) - })) - + promises1.push( + fetchTonSite(nftDomainItem.dns) + .then(async (dmn) => { + const domainInfo = await fetchDomainInfo(dmn) + console.log("success dmn", dmn) + upsertDmn(dmn, {available: true, walletAddress:domainInfo?.address,tonBalance:domainInfo?.balance}) + }) + .catch((dmn) => { + upsertDmn(dmn, {available: false}) + }) + ) } } count++ await Promise.all(promises1) - console.timeEnd('fetchDomain') continue } break diff --git a/searching-front/services/helpers.ts b/searching-front/services/helpers.ts index a948c09..61f99c4 100644 --- a/searching-front/services/helpers.ts +++ b/searching-front/services/helpers.ts @@ -1,4 +1,4 @@ export const getTonProxy = () => ({ - host: "in2.ton.org", + host: "in3.ton.org", port: 8080, }) \ No newline at end of file diff --git a/searching-front/services/main.ts b/searching-front/services/main.ts index a887bbb..441967d 100644 --- a/searching-front/services/main.ts +++ b/searching-front/services/main.ts @@ -10,11 +10,11 @@ const run = async()=>{ console.time('watcher') await domainWatcher(); console.timeEnd('watcher') - influx() - console.log('Start parser'); - console.time('watcher'); - await parser(); - console.timeEnd('watcher'); + // influx() + // console.log('Start parser'); + // console.time('watcher'); + // await parser(); + // console.timeEnd('watcher'); }