Merge branch 'feature_add_matrix_connect_view' of https://github.com/jejolare-dev/zano-explorer

This commit is contained in:
jejolare 2024-12-12 13:57:54 +07:00
commit 4c6236b656
7 changed files with 142 additions and 88 deletions

View file

@ -1194,6 +1194,33 @@ const requestsLimiter = rateLimit({
}))
app.get('/api/get_matrix_addresses', exceptionHandler(async (req, res) => {
const {page, items} = req.query;
if (!page || !items) {
return res.status(200).send({
success: false,
data: "no page or items provided"
})
}
const matrixAddressesResponse = await fetch(`${config.matrix_api_url}/get-registered-addresses/?page=${page}&items=${items}`)
.then(res => res.json())
const {addresses} = matrixAddressesResponse;
if (matrixAddressesResponse?.success && addresses) {
return res.status(200).send({
success: true,
addresses
})
} else {
return res.status(200).send({
success: false,
})
}
}))
io.on('connection', async (socket) => {

View file

@ -3,34 +3,32 @@ import styles from "./Switch.module.scss";
import { Dispatch, SetStateAction } from "react";
interface SwitchProps {
firstTitle: string;
secondTitle: string;
isFirstSelected: boolean;
setIsFirstSelected: Dispatch<SetStateAction<boolean>>;
titles: string[];
selectedTitleIdx: number;
setSelectedTitleIdx: Dispatch<SetStateAction<number>>;
}
export default function Switch({
firstTitle,
secondTitle,
isFirstSelected,
setIsFirstSelected
titles,
selectedTitleIdx,
setSelectedTitleIdx
}: SwitchProps) {
return (
<div className={styles["switch"]}>
return (
<div className={styles['switch']}>
{titles.map((title, idx) => {
return (
<Button
key={idx}
wrapper
className={`${styles["switch__item"]} ${isFirstSelected ? styles["switch__item_selected"] : ""}`}
onClick={() => setIsFirstSelected(true)}
>
<p>{firstTitle}</p>
</Button>
<Button
wrapper
className={`${styles["switch__item"]} ${!isFirstSelected ? styles["switch__item_selected"] : ""}`}
onClick={() => setIsFirstSelected(false)}
>
<p>{secondTitle}</p>
</Button>
</div>
)
className={`${styles["switch__item"]} ${(idx === selectedTitleIdx) && styles["switch__item_selected"] }`}
onClick={() => setSelectedTitleIdx(idx)}
>
<p>{title}</p>
</Button>
)
})}
</div>
)
}

View file

@ -68,57 +68,59 @@ function Table(props: TableProps) {
</tbody>
</table>
{pagination &&
<div className={styles["table__pagination"]}>
<div className={styles["table__pagination__pages"]}>
<p>Pages: </p>
<div>
<button
className={page === "1" ? styles.disabled : undefined}
onClick={() => changePage(-1)}
>
<ArrowImg />
</button>
<button
onClick={() => changePage(1)}
>
<ArrowImg />
</button>
</div>
<Input
type="text"
value={page}
onInput={(e) => onNumberInput(e, setPage)}
/>
</div>
{pagesTotal && <p>Pages total: {pagesTotal}</p>}
<div className={styles["table__pagination__blocks"]}>
<div>
<p>Items on page: </p>
<Input
type="text"
value={itemsOnPage}
onInput={(e) => onNumberInput(e, setItemsOnPage, 50)}
/>
</div>
{!hidePaginationBlock &&
<div>
<p>Go to block: </p>
<Input
type="text"
placeholder="number"
value={goToBlock}
onInput={(e) => onNumberInput(e, setGoToBlock)}
onEnterPress={goToBlockEnter}
/>
</div>
}
</div>
</div>
}
<Pagination pagination={pagination}/>
</div>
)
function Pagination ({pagination}:{pagination:boolean | undefined}) {
if (!pagination) return null
return <div className={styles["table__pagination"]}>
<div className={styles["table__pagination__pages"]}>
<p>Pages: </p>
<div>
<button
className={page === "1" ? styles.disabled : undefined}
onClick={() => changePage(-1)}
>
<ArrowImg />
</button>
<button
onClick={() => changePage(1)}
>
<ArrowImg />
</button>
</div>
<Input
type="text"
value={page}
onInput={(e) => onNumberInput(e, setPage)}
/>
</div>
{pagesTotal && <p>Pages total: {pagesTotal}</p>}
<div className={styles["table__pagination__blocks"]}>
<div>
<p>Items on page: </p>
<Input
type="text"
value={itemsOnPage}
onInput={(e) => onNumberInput(e, setItemsOnPage, 50)}
/>
</div>
{!hidePaginationBlock &&
<div>
<p>Go to block: </p>
<Input
type="text"
placeholder="number"
value={goToBlock}
onInput={(e) => onNumberInput(e, setGoToBlock)}
onEnterPress={goToBlockEnter}
/>
</div>
}
</div>
</div>
}
}
export default Table;

View file

@ -30,7 +30,11 @@ function Aliases(props: AliasesPageProps) {
aliasesAmount: props.aliasesAmount,
premiumAliasesAmount: props.premiumAliasesAmount
});
const [isPremiumOnly, setIsPremiumOnly] = useState(false);
const [selectedTitleIdx, setSelectedTitleIdx] = useState(0);
const isPremiumOnly = selectedTitleIdx === 0;
const isInMatrix = selectedTitleIdx === 2;
const fetchIdRef = useRef<string>(nanoid());
@ -54,6 +58,7 @@ function Aliases(props: AliasesPageProps) {
if (result.sucess === false) return;
if (!(result instanceof Array)) return;
if (isInMatrix) return;
setAliases(
result.map((e: any) => ({
alias: e.alias || "",
@ -61,12 +66,27 @@ function Aliases(props: AliasesPageProps) {
hasMatrixConnection: e.hasMatrixConnection || false
}))
);
}, [itemsOnPage, page, searchState, isPremiumOnly]);
}, [itemsOnPage, page, searchState, isPremiumOnly, isInMatrix]);
const fetchMatrixAliases = useCallback(async () => {
const result = await Fetch.getMatrixAddresses(page, itemsOnPage);
if(!result.success || !(result.addresses instanceof Array)) return;
const aliases = result.addresses.map((e :any)=>{
return {...e, hasMatrixConnection: true}
})
setAliases(aliases);
},[itemsOnPage, page])
useEffect(() => {
setPage("1");
}, [isPremiumOnly, searchState]);
useEffect(() => {
if (isInMatrix) {
fetchMatrixAliases();
}
}, [isInMatrix, fetchMatrixAliases])
useEffect(() => {
fetchAliases();
@ -104,23 +124,25 @@ function Aliases(props: AliasesPageProps) {
<CrownImg />
</div>
</div>
{hasMatrixConnection && <ConnectionIcon/>}
{hasMatrixConnection && <ConnectionIcon alias={alias}/>}
</>
</div>
:
<div className={styles["alias_wrapper"]}>
<>
{alias}
{hasMatrixConnection && <ConnectionIcon/>}
{hasMatrixConnection && <ConnectionIcon alias={alias}/>}
</>
</div>
);
}
function ConnectionIcon(){
function ConnectionIcon({alias}:{alias: string}){
const [hovered, setHovered] = useState(false);
const link = `https://matrix.to/#/@${alias}:zano.org`
return (
<a href={link}>
<div className={styles["connection_icon"]} onMouseEnter={ () => setHovered(true)}
onMouseLeave={ ()=> setHovered(false)}
> <>
@ -132,6 +154,7 @@ function Aliases(props: AliasesPageProps) {
</div>}
</>
</div>
</a>
)
}
@ -164,10 +187,9 @@ function Aliases(props: AliasesPageProps) {
}}
content={
<Switch
firstTitle="Premium"
secondTitle="All Aliases"
isFirstSelected={isPremiumOnly}
setIsFirstSelected={setIsPremiumOnly}
titles={["Premium", "All Aliases", "In Matrix"]}
selectedTitleIdx={selectedTitleIdx}
setSelectedTitleIdx={setSelectedTitleIdx}
/>
}
/>

View file

@ -60,6 +60,8 @@ function Assets(props: AssetsPageProps) {
const searchParams = useSearchParams();
const router = useRouter();
const [selectedTitleIdx, setSelectedTitleIdx] = useState(0);
const [burgerOpened, setBurgerOpened] = useState(false);
const [assets, setAssets] = useState<any[]>(props.assets);
@ -72,7 +74,7 @@ function Assets(props: AssetsPageProps) {
const [itemsOnPage, setItemsOnPage] = useState(DEFAULT_ASSETS_ON_PAGE);
const [page, setPage] = useState("1");
const [isWhitelist, setIsWhitelist] = useState(true);
const isWhitelist = selectedTitleIdx === 0;
const [inputState, setInputState] = useState("");
const [initFetched, setInitFetched] = useState(false);
@ -250,10 +252,9 @@ function Assets(props: AssetsPageProps) {
}}
content={
<Switch
firstTitle="Whitelisted"
secondTitle="All Assets"
isFirstSelected={isWhitelist}
setIsFirstSelected={setIsWhitelist}
titles={["Whitelisted", "All Assets"]}
selectedTitleIdx={selectedTitleIdx}
setSelectedTitleIdx={setSelectedTitleIdx}
/>
}
/>

View file

@ -20,7 +20,7 @@
.connection_icon__tooltip__arrow {
z-index: 1;
position: absolute;
top:0px;
top: 0px;
transform: rotate(45deg) translateY(-5px);
height: 10px;
width: 10px;

View file

@ -111,6 +111,10 @@ class Fetch {
{ assetsIds },
).then(res => res.json());
}
static async getMatrixAddresses(page: string, items:string){
return await fetch(this.proxyPath + `/get_matrix_addresses/?page=${page}&items=${items}`,).then((res) => res.json());
}
}
export default Fetch;