From b6c46e9064bc0f6cd8d2da3a6bd9362e42457d8f Mon Sep 17 00:00:00 2001
From: dimakorzhovnik
Date: Sat, 21 Sep 2024 03:08:30 +0300
Subject: [PATCH 1/2] fix(inference): added standard inference page
---
src/features/Inference/Inference.tsx | 50 +++++++++++++++++++
.../ActionBar/ActionBar.module.scss | 9 ++++
.../components/ActionBar/ActionBar.tsx | 33 ++++++++++++
.../components/RowItems/RowItems.module.scss | 11 ++++
.../components/RowItems/RowItems.tsx | 43 ++++++++++++++++
src/features/Inference/hooks/useInference.ts | 29 +++++++++++
src/features/Inference/type.d.ts | 6 +++
src/router.tsx | 3 ++
src/routes.ts | 4 ++
9 files changed, 188 insertions(+)
create mode 100644 src/features/Inference/Inference.tsx
create mode 100644 src/features/Inference/components/ActionBar/ActionBar.module.scss
create mode 100644 src/features/Inference/components/ActionBar/ActionBar.tsx
create mode 100644 src/features/Inference/components/RowItems/RowItems.module.scss
create mode 100644 src/features/Inference/components/RowItems/RowItems.tsx
create mode 100644 src/features/Inference/hooks/useInference.ts
create mode 100644 src/features/Inference/type.d.ts
diff --git a/src/features/Inference/Inference.tsx b/src/features/Inference/Inference.tsx
new file mode 100644
index 000000000..9a7b02466
--- /dev/null
+++ b/src/features/Inference/Inference.tsx
@@ -0,0 +1,50 @@
+import { useEffect, useState } from 'react';
+import { Display, MainContainer } from 'src/components';
+import { getSearchQuery } from 'src/utils/search/utils';
+import { useParams } from 'react-router-dom';
+import Loader2 from 'src/components/ui/Loader2';
+import useInference from './hooks/useInference';
+import RowItems from './components/RowItems/RowItems';
+import ActionBarContainer from './components/ActionBar/ActionBar';
+
+function Inference() {
+ const { query } = useParams();
+
+ const [keywordHash, setKeywordHash] = useState('');
+
+ const { data, isFetching, error } = useInference(keywordHash);
+
+ useEffect(() => {
+ (async () => {
+ const keywordHash = await getSearchQuery(query || '');
+
+ setKeywordHash(keywordHash);
+ })();
+ }, [query]);
+
+ return (
+ <>
+
+ {isFetching && !data ? (
+
+ ) : data && data.result.length > 0 ? (
+
+ ) : error ? (
+
+ {error.message}
+
+ ) : (
+
+
+ there are no answers or questions to this particle
be the
+ first and create one
+
+
+ )}
+
+
+ >
+ );
+}
+
+export default Inference;
diff --git a/src/features/Inference/components/ActionBar/ActionBar.module.scss b/src/features/Inference/components/ActionBar/ActionBar.module.scss
new file mode 100644
index 000000000..7a92828d5
--- /dev/null
+++ b/src/features/Inference/components/ActionBar/ActionBar.module.scss
@@ -0,0 +1,9 @@
+.inputContainer {
+ width: 80%;
+ text-align: center;
+}
+
+.input {
+ text-align: center !important;
+ font-size: 20px !important;
+}
diff --git a/src/features/Inference/components/ActionBar/ActionBar.tsx b/src/features/Inference/components/ActionBar/ActionBar.tsx
new file mode 100644
index 000000000..7b9200e03
--- /dev/null
+++ b/src/features/Inference/components/ActionBar/ActionBar.tsx
@@ -0,0 +1,33 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { ActionBar, Color, Input } from 'src/components';
+import { routes } from 'src/routes';
+import { replaceSlash } from 'src/utils/utils';
+import styles from './ActionBar.module.scss';
+
+function ActionBarContainer() {
+ const navigate = useNavigate();
+ const [valueInput, setValueInput] = useState('');
+
+ function submit(event: React.FormEvent) {
+ event.preventDefault();
+
+ navigate(routes.inference.getLink(replaceSlash(valueInput)));
+ }
+
+ return (
+
+
+
+ );
+}
+
+export default ActionBarContainer;
diff --git a/src/features/Inference/components/RowItems/RowItems.module.scss b/src/features/Inference/components/RowItems/RowItems.module.scss
new file mode 100644
index 000000000..14f4e3b7c
--- /dev/null
+++ b/src/features/Inference/components/RowItems/RowItems.module.scss
@@ -0,0 +1,11 @@
+.infiniteScroll {
+ margin-top: 12px;
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ > * {
+ width: 100%;
+ }
+}
diff --git a/src/features/Inference/components/RowItems/RowItems.tsx b/src/features/Inference/components/RowItems/RowItems.tsx
new file mode 100644
index 000000000..5123fdada
--- /dev/null
+++ b/src/features/Inference/components/RowItems/RowItems.tsx
@@ -0,0 +1,43 @@
+import { useMemo, useState } from 'react';
+import InfiniteScroll from 'react-infinite-scroll-component';
+import Spark from 'src/components/search/Spark/Spark';
+import { Dots } from 'src/components';
+import styles from './RowItems.module.scss';
+import { InferenceItem } from '../../type';
+
+const LOAD_COUNT = 10;
+
+function RowItems({ dataItem }: { dataItem: InferenceItem[] }) {
+ const [itemsToShow, setItemsToShow] = useState(20);
+
+ const loadMore = () => {
+ setTimeout(() => {
+ setItemsToShow((i) => i + LOAD_COUNT);
+ }, 2000);
+ };
+
+ const displayedPalettes = useMemo(
+ () =>
+ dataItem.slice(0, itemsToShow).map((item) => {
+ return (
+
+ );
+ }),
+ [itemsToShow, dataItem]
+ );
+
+ return (
+ all loaded
}
+ hasMore={dataItem.length > itemsToShow}
+ loader={}
+ className={styles.infiniteScroll}
+ >
+ {displayedPalettes}
+
+ );
+}
+
+export default RowItems;
diff --git a/src/features/Inference/hooks/useInference.ts b/src/features/Inference/hooks/useInference.ts
new file mode 100644
index 000000000..c8e672ebe
--- /dev/null
+++ b/src/features/Inference/hooks/useInference.ts
@@ -0,0 +1,29 @@
+import { useQuery } from '@tanstack/react-query';
+import axios from 'axios';
+import { InferenceItem } from '../type';
+
+export type InferenceResponse = {
+ result: InferenceItem[];
+ time: number;
+};
+
+const inferenceFetcher = async (hash: string) => {
+ return axios({
+ method: 'get',
+ url: `https://st-inference.cybernode.ai/standard_inference?particle=${hash}`,
+ })
+ .then((response) => response.data as InferenceResponse)
+ .catch((e) => console.error(e));
+};
+
+function useInference(hash: string) {
+ const { data, isFetching, error } = useQuery(
+ ['useInference', hash],
+ () => inferenceFetcher(hash),
+ { enabled: Boolean(hash.length) }
+ );
+
+ return { data, isFetching, error };
+}
+
+export default useInference;
diff --git a/src/features/Inference/type.d.ts b/src/features/Inference/type.d.ts
new file mode 100644
index 000000000..d4052309e
--- /dev/null
+++ b/src/features/Inference/type.d.ts
@@ -0,0 +1,6 @@
+export type InferenceItem = {
+ particle: string;
+ balance: number;
+ rank: number;
+ inference: number;
+};
diff --git a/src/router.tsx b/src/router.tsx
index 8f73a59ae..023c3ea54 100644
--- a/src/router.tsx
+++ b/src/router.tsx
@@ -59,6 +59,7 @@ import Cybernet from './features/cybernet/ui/Cybernet';
import Settings from './pages/Settings/Settings';
import FreestyleIde from './pages/robot/Soul/RuneEditor/FreestyleIde/FreestyleIde';
import Map from './pages/Portal/Map/Map';
+import Inference from './features/Inference/Inference';
type WrappedRouterProps = {
children: React.ReactNode;
@@ -147,6 +148,8 @@ function AppRouter() {
/>
} />
+ } />
+
} />
`/oracle/ask/${search}`,
},
+ inference: {
+ path: '/inference',
+ getLink: (search: string) => `/oracle/inference/${search}`,
+ },
teleport: {
path: '/teleport',
send: {
From e1c9997a87e2730bcd6229e770104cf6c8efc23e Mon Sep 17 00:00:00 2001
From: dimakorzhovnik
Date: Wed, 25 Sep 2024 23:12:41 +0300
Subject: [PATCH 2/2] fix(inference): sorting by inference, rank, balance
---
src/features/Inference/Inference.tsx | 23 +++++++-
.../components/Filters/Filters.module.scss | 25 +++++++++
.../Inference/components/Filters/Filters.tsx | 56 +++++++++++++++++++
.../components/RowItems/RowItems.tsx | 10 +++-
src/features/Inference/hooks/useInference.ts | 12 +++-
src/features/Inference/{type.d.ts => type.ts} | 6 ++
src/features/Inference/utils/sortByKey.ts | 20 +++++++
7 files changed, 143 insertions(+), 9 deletions(-)
create mode 100644 src/features/Inference/components/Filters/Filters.module.scss
create mode 100644 src/features/Inference/components/Filters/Filters.tsx
rename src/features/Inference/{type.d.ts => type.ts} (54%)
create mode 100644 src/features/Inference/utils/sortByKey.ts
diff --git a/src/features/Inference/Inference.tsx b/src/features/Inference/Inference.tsx
index 9a7b02466..413e83c26 100644
--- a/src/features/Inference/Inference.tsx
+++ b/src/features/Inference/Inference.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { Display, MainContainer } from 'src/components';
import { getSearchQuery } from 'src/utils/search/utils';
import { useParams } from 'react-router-dom';
@@ -6,11 +6,15 @@ import Loader2 from 'src/components/ui/Loader2';
import useInference from './hooks/useInference';
import RowItems from './components/RowItems/RowItems';
import ActionBarContainer from './components/ActionBar/ActionBar';
+import Filters from './components/Filters/Filters';
+import { SortBy } from './type';
+import sortByKey from './utils/sortByKey';
function Inference() {
const { query } = useParams();
const [keywordHash, setKeywordHash] = useState('');
+ const [sortBy, setSortBy] = useState(SortBy.inference);
const { data, isFetching, error } = useInference(keywordHash);
@@ -22,16 +26,29 @@ function Inference() {
})();
}, [query]);
+ const dataSortByKey = useMemo(() => {
+ if (!data) {
+ return [];
+ }
+
+ return sortByKey(data.result, sortBy);
+ }, [data, sortBy]);
+
return (
<>
+
{isFetching && !data ? (
) : data && data.result.length > 0 ? (
-
+
) : error ? (
- {error.message}
+ {error.toString()}
) : (
diff --git a/src/features/Inference/components/Filters/Filters.module.scss b/src/features/Inference/components/Filters/Filters.module.scss
new file mode 100644
index 000000000..ccf84fd94
--- /dev/null
+++ b/src/features/Inference/components/Filters/Filters.module.scss
@@ -0,0 +1,25 @@
+@import '../../../../components/containerGradient/saber/index.module.scss';
+
+.header {
+ margin: 10px 0 -5px;
+ padding: 17px 12px 20px;
+
+ display: flex;
+ justify-content: space-between;
+ align-content: center;
+
+ @include saber('blue', top);
+
+ @media (max-width: 680px) {
+ gap: 40px 0;
+ flex-wrap: wrap;
+ }
+}
+
+.total {
+ color: rgba(221, 255, 255, 0.38);
+
+ span {
+ color: rgba(255, 255, 255, 0.78);
+ }
+}
\ No newline at end of file
diff --git a/src/features/Inference/components/Filters/Filters.tsx b/src/features/Inference/components/Filters/Filters.tsx
new file mode 100644
index 000000000..e663775b4
--- /dev/null
+++ b/src/features/Inference/components/Filters/Filters.tsx
@@ -0,0 +1,56 @@
+import ButtonsGroup from 'src/components/buttons/ButtonsGroup/ButtonsGroup';
+import AdviserHoverWrapper from 'src/features/adviser/AdviserHoverWrapper/AdviserHoverWrapper';
+import { SortBy } from '../../type';
+import styles from './Filters.module.scss';
+
+const sortConfig = {
+ [SortBy.rank]: {
+ label: '⭐',
+ tooltip: 'sort particles by cyberrank',
+ },
+ [SortBy.inference]: {
+ label: '🔥',
+ tooltip: 'sort particles by inference',
+ },
+ [SortBy.balance]: {
+ label: '⚡️',
+ tooltip: 'sort particles by balance of volt',
+ },
+};
+
+type Props = {
+ filter: SortBy;
+ setFilter: (item: SortBy) => void;
+ total?: number;
+};
+
+function Filters({ filter, setFilter, total }: Props) {
+ return (
+
+ {
+ return {
+ label: sortConfig[sortType].label,
+ name: sortType,
+ checked: filter === sortType,
+ tooltip: sortConfig[sortType].tooltip,
+ };
+ })}
+ onChange={(sortType: SortBy) => {
+ setFilter(sortType);
+ }}
+ />
+
+ {total && (
+
+
+ {total} particles
+
+
+ )}
+
+ );
+}
+
+export default Filters;
diff --git a/src/features/Inference/components/RowItems/RowItems.tsx b/src/features/Inference/components/RowItems/RowItems.tsx
index 5123fdada..4f6731b50 100644
--- a/src/features/Inference/components/RowItems/RowItems.tsx
+++ b/src/features/Inference/components/RowItems/RowItems.tsx
@@ -7,7 +7,7 @@ import { InferenceItem } from '../../type';
const LOAD_COUNT = 10;
-function RowItems({ dataItem }: { dataItem: InferenceItem[] }) {
+function RowItems({ dataItem, sortBy }: { dataItem: InferenceItem[]; sortBy: string }) {
const [itemsToShow, setItemsToShow] = useState(20);
const loadMore = () => {
@@ -20,10 +20,14 @@ function RowItems({ dataItem }: { dataItem: InferenceItem[] }) {
() =>
dataItem.slice(0, itemsToShow).map((item) => {
return (
-
+
);
}),
- [itemsToShow, dataItem]
+ [itemsToShow, dataItem, sortBy]
);
return (
diff --git a/src/features/Inference/hooks/useInference.ts b/src/features/Inference/hooks/useInference.ts
index c8e672ebe..0c9c58ec2 100644
--- a/src/features/Inference/hooks/useInference.ts
+++ b/src/features/Inference/hooks/useInference.ts
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
-import { InferenceItem } from '../type';
+import { InferenceItem, SortBy } from '../type';
export type InferenceResponse = {
result: InferenceItem[];
@@ -13,7 +13,9 @@ const inferenceFetcher = async (hash: string) => {
url: `https://st-inference.cybernode.ai/standard_inference?particle=${hash}`,
})
.then((response) => response.data as InferenceResponse)
- .catch((e) => console.error(e));
+ .catch((e) => {
+ throw new Error(`useInference: ${e}`);
+ });
};
function useInference(hash: string) {
@@ -23,7 +25,11 @@ function useInference(hash: string) {
{ enabled: Boolean(hash.length) }
);
- return { data, isFetching, error };
+ return {
+ data,
+ isFetching,
+ error,
+ };
}
export default useInference;
diff --git a/src/features/Inference/type.d.ts b/src/features/Inference/type.ts
similarity index 54%
rename from src/features/Inference/type.d.ts
rename to src/features/Inference/type.ts
index d4052309e..50750d715 100644
--- a/src/features/Inference/type.d.ts
+++ b/src/features/Inference/type.ts
@@ -4,3 +4,9 @@ export type InferenceItem = {
rank: number;
inference: number;
};
+
+export enum SortBy {
+ inference = 'inference',
+ rank = 'rank',
+ balance = 'balance',
+}
diff --git a/src/features/Inference/utils/sortByKey.ts b/src/features/Inference/utils/sortByKey.ts
new file mode 100644
index 000000000..62a28543a
--- /dev/null
+++ b/src/features/Inference/utils/sortByKey.ts
@@ -0,0 +1,20 @@
+import { InferenceItem, SortBy } from '../type';
+
+const sortByKey = (data: InferenceItem[], sortBy: SortBy) => {
+ if (!data) {
+ return [];
+ }
+
+ switch (sortBy) {
+ case SortBy.balance:
+ return data.sort((a, b) => b.balance - a.balance);
+
+ case SortBy.rank:
+ return data.sort((a, b) => b.rank - a.rank);
+
+ default:
+ return data.sort((a, b) => b.inference - a.inference);
+ }
+};
+
+export default sortByKey;