mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-11-26 23:27:14 +03:00
app_store: widget change and more ui
This commit is contained in:
parent
aa4c114a17
commit
7edcf31ddd
@ -144,7 +144,7 @@ fn make_widget() -> String {
|
|||||||
if (app.metadata) {
|
if (app.metadata) {
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.className = 'app';
|
a.className = 'app';
|
||||||
a.href = `/main:app_store:sys/apps/${app.package}:${app.publisher}`
|
a.href = `/main:app_store:sys/app/${app.package}:${app.publisher}`
|
||||||
a.target = '_blank';
|
a.target = '_blank';
|
||||||
a.rel = 'noopener noreferrer';
|
a.rel = 'noopener noreferrer';
|
||||||
const iconLetter = app.metadata_hash.replace('0x', '')[0].toUpperCase();
|
const iconLetter = app.metadata_hash.replace('0x', '')[0].toUpperCase();
|
||||||
|
@ -2,9 +2,8 @@ import React from "react";
|
|||||||
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
||||||
|
|
||||||
import StorePage from "./pages/StorePage";
|
import StorePage from "./pages/StorePage";
|
||||||
import MyAppsPage from "./pages/MyAppsPage";
|
|
||||||
import AppPage from "./pages/AppPage";
|
import AppPage from "./pages/AppPage";
|
||||||
import { APP_DETAILS_PATH, MY_APPS_PATH, PUBLISH_PATH, STORE_PATH } from "./constants/path";
|
import { APP_DETAILS_PATH, PUBLISH_PATH, STORE_PATH } from "./constants/path";
|
||||||
import PublishPage from "./pages/PublishPage";
|
import PublishPage from "./pages/PublishPage";
|
||||||
import Header from "./components/Header";
|
import Header from "./components/Header";
|
||||||
|
|
||||||
@ -19,7 +18,6 @@ function App() {
|
|||||||
<Header />
|
<Header />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={STORE_PATH} element={<StorePage />} />
|
<Route path={STORE_PATH} element={<StorePage />} />
|
||||||
<Route path={MY_APPS_PATH} element={<MyAppsPage />} />
|
|
||||||
<Route path={`${APP_DETAILS_PATH}/:id`} element={<AppPage />} />
|
<Route path={`${APP_DETAILS_PATH}/:id`} element={<AppPage />} />
|
||||||
<Route path={PUBLISH_PATH} element={<PublishPage />} />
|
<Route path={PUBLISH_PATH} element={<PublishPage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
import { STORE_PATH, MY_APPS_PATH, PUBLISH_PATH } from '../constants/path';
|
import { STORE_PATH, PUBLISH_PATH } from '../constants/path';
|
||||||
import { ConnectButton } from '@rainbow-me/rainbowkit';
|
import { ConnectButton } from '@rainbow-me/rainbowkit';
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
const Header: React.FC = () => {
|
||||||
@ -11,7 +11,6 @@ const Header: React.FC = () => {
|
|||||||
<div className="header-left">
|
<div className="header-left">
|
||||||
<nav>
|
<nav>
|
||||||
<Link to={STORE_PATH} className={location.pathname === STORE_PATH ? 'active' : ''}>Home</Link>
|
<Link to={STORE_PATH} className={location.pathname === STORE_PATH ? 'active' : ''}>Home</Link>
|
||||||
<Link to={MY_APPS_PATH} className={location.pathname === MY_APPS_PATH ? 'active' : ''}>My Apps</Link>
|
|
||||||
<Link to={PUBLISH_PATH} className={location.pathname === PUBLISH_PATH ? 'active' : ''}>Publish</Link>
|
<Link to={PUBLISH_PATH} className={location.pathname === PUBLISH_PATH ? 'active' : ''}>Publish</Link>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
export const MY_APPS_PATH = '/my-apps';
|
|
||||||
export const STORE_PATH = '/';
|
export const STORE_PATH = '/';
|
||||||
export const PUBLISH_PATH = '/publish';
|
export const PUBLISH_PATH = '/publish';
|
||||||
export const APP_DETAILS_PATH = '/app';
|
export const APP_DETAILS_PATH = '/app';
|
||||||
|
@ -106,85 +106,89 @@
|
|||||||
color: light-dark(var(--gray), var(--off-white));
|
color: light-dark(var(--gray), var(--off-white));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... (previous styles) ... */
|
|
||||||
|
|
||||||
/* App Page Styles */
|
/* App Page Styles */
|
||||||
.app-page {
|
.app-page {
|
||||||
padding: 2rem;
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-details-card {
|
.app-description {
|
||||||
background-color: light-dark(var(--white), var(--off-black));
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 2rem;
|
|
||||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-divider {
|
|
||||||
border: none;
|
|
||||||
border-top: 1px solid var(--gray);
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-info-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
gap: 1rem;
|
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
color: light-dark(var(--gray), var(--off-white));
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-info-item {
|
.app-details {
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-info-top {
|
.app-info {
|
||||||
font-weight: bold;
|
flex: 1;
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-info-middle {
|
.app-details-list {
|
||||||
font-size: 1.5rem;
|
list-style-type: none;
|
||||||
margin-bottom: 0.5rem;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-info-bottom {
|
.app-details-list li {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
border-bottom: 1px solid light-dark(var(--gray), var(--maroon));
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-details-list li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon.installed,
|
||||||
|
.status-icon.mirroring,
|
||||||
|
.status-icon.auto-update {
|
||||||
|
color: var(--orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon.not-installed,
|
||||||
|
.status-icon.not-mirroring,
|
||||||
|
.status-icon.no-auto-update {
|
||||||
|
color: var(--ansi-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-actions button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: var(--gray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-screenshots {
|
.app-screenshots {
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
margin-bottom: 1rem;
|
padding: 1rem 0;
|
||||||
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-screenshot {
|
.app-screenshot {
|
||||||
max-width: 200px;
|
max-width: 200px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 1rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-actions button,
|
|
||||||
.app-actions .button {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.version-number {
|
|
||||||
font-family: monospace;
|
|
||||||
background-color: light-dark(var(--tan), var(--maroon));
|
|
||||||
padding: 0.2rem 0.5rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ... (previous styles) ... */
|
|
||||||
|
|
||||||
/* My Apps Page Styles */
|
/* My Apps Page Styles */
|
||||||
.my-apps-page {
|
.my-apps-page {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
@ -258,8 +262,6 @@
|
|||||||
color: light-dark(var(--gray), var(--off-white));
|
color: light-dark(var(--gray), var(--off-white));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... (previous styles) ... */
|
|
||||||
|
|
||||||
/* Publish Page Styles */
|
/* Publish Page Styles */
|
||||||
.publish-page {
|
.publish-page {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
@ -361,8 +363,6 @@
|
|||||||
background-color: #c62828;
|
background-color: #c62828;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... (previous styles) ... */
|
|
||||||
|
|
||||||
/* Store Page Styles */
|
/* Store Page Styles */
|
||||||
.store-page {
|
.store-page {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
@ -371,13 +371,15 @@
|
|||||||
.store-header {
|
.store-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
margin-right: 1rem;
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar input {
|
.search-bar input {
|
||||||
@ -386,6 +388,27 @@
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
border: 1px solid var(--gray);
|
border: 1px solid var(--gray);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-button,
|
||||||
|
.store-header button {
|
||||||
|
height: 38px;
|
||||||
|
padding: 0 1rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add these new styles */
|
||||||
|
.store-header>* {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.store-header button {
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-list table {
|
.app-list table {
|
||||||
@ -430,7 +453,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status.installed {
|
.status.installed {
|
||||||
background-color: var(--green);
|
background-color: var(--off-black);
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,148 +1,72 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { FaGlobe, FaPeopleGroup, FaCode, FaLink, FaCaretDown } from "react-icons/fa6";
|
import { FaDownload, FaSync, FaTrash, FaMagnet, FaCog, FaCheck, FaTimes } from "react-icons/fa";
|
||||||
|
|
||||||
import { AppInfo } from "../types/Apps";
|
|
||||||
import useAppsStore from "../store";
|
import useAppsStore from "../store";
|
||||||
import { PUBLISH_PATH } from "../constants/path";
|
import { appId } from "../utils/app";
|
||||||
import { FaCheckCircle, FaTimesCircle } from "react-icons/fa";
|
|
||||||
|
|
||||||
export default function AppPage() {
|
export default function AppPage() {
|
||||||
const { getApp, installApp, updateApp, uninstallApp, setMirroring, setAutoUpdate } = useAppsStore();
|
const { installApp, updateApp, uninstallApp, setMirroring, setAutoUpdate, apps } = useAppsStore();
|
||||||
const navigate = useNavigate();
|
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [app, setApp] = useState<AppInfo | undefined>(undefined);
|
const app = apps.find(a => appId(a) === id);
|
||||||
|
|
||||||
useEffect(() => {
|
if (!app) {
|
||||||
if (id) {
|
return <div className="app-page"><h4>App details not found for {id}</h4></div>;
|
||||||
getApp(id).then(setApp).catch(console.error);
|
}
|
||||||
}
|
|
||||||
}, [id, getApp]);
|
|
||||||
|
|
||||||
const handleInstall = () => app && installApp(app);
|
const handleInstall = () => app && installApp(app);
|
||||||
const handleUpdate = () => app && updateApp(app);
|
const handleUpdate = () => app && updateApp(app);
|
||||||
const handleUninstall = () => app && uninstallApp(app);
|
const handleUninstall = () => app && uninstallApp(app);
|
||||||
const handleMirror = () => app && setMirroring(app, !app.state?.mirroring);
|
const handleMirror = () => app && setMirroring(app, !app.state?.mirroring);
|
||||||
const handleAutoUpdate = () => app && setAutoUpdate(app, !app.state?.auto_update);
|
const handleAutoUpdate = () => app && setAutoUpdate(app, !app.state?.auto_update);
|
||||||
const handlePublish = () => navigate(PUBLISH_PATH, { state: { app } });
|
|
||||||
|
|
||||||
if (!app) {
|
|
||||||
return <div className="app-page"><h4>App details not found for {id}</h4></div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const version = app.metadata?.properties?.current_version || "Unknown";
|
|
||||||
const versions = Object.entries(app.metadata?.properties?.code_hashes || {});
|
|
||||||
const hash = app.state?.our_version || (versions[(versions.length || 1) - 1] || ["", ""])[1];
|
|
||||||
const mirrors = app.metadata?.properties?.mirrors || [];
|
|
||||||
|
|
||||||
const tbaLink = `https://optimistic.etherscan.io/address/${app.tba}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app-page">
|
<section className="app-page">
|
||||||
<div className="app-details-card">
|
<h2>{app.metadata?.name || app.package}</h2>
|
||||||
<h2>{app.metadata?.name || app.package}</h2>
|
<p className="app-description">{app.metadata?.description || "No description available"}</p>
|
||||||
<p>{app.metadata?.description || "No description available"}</p>
|
<div className="app-details">
|
||||||
<hr className="app-divider" />
|
<div className="app-info">
|
||||||
<div className="app-info-grid">
|
<ul className="app-details-list">
|
||||||
<div className="app-info-item">
|
<li><span>Version:</span> <span>{app.metadata?.properties?.current_version || "Unknown"}</span></li>
|
||||||
<FaPeopleGroup size={36} />
|
<li><span>Developer:</span> <span>{app.publisher}</span></li>
|
||||||
<span>Developer</span>
|
<li><span>Mirrors:</span> <span>{app.metadata?.properties?.mirrors?.length || 0}</span></li>
|
||||||
<span>{app.publisher}</span>
|
<li>
|
||||||
</div>
|
<span>Installed:</span>
|
||||||
<div className="app-info-item">
|
{app.installed ? <FaCheck className="status-icon installed" /> : <FaTimes className="status-icon not-installed" />}
|
||||||
<FaCode size={36} />
|
</li>
|
||||||
<span>Version</span>
|
<li>
|
||||||
<span>{version}</span>
|
<span>Mirroring:</span>
|
||||||
<span className="hash">{`${hash.slice(0, 5)}...${hash.slice(-5)}`}</span>
|
{app.state?.mirroring ? <FaCheck className="status-icon mirroring" /> : <FaTimes className="status-icon not-mirroring" />}
|
||||||
</div>
|
</li>
|
||||||
<div className="app-info-item">
|
<li>
|
||||||
<FaGlobe size={36} />
|
<span>Auto-Update:</span>
|
||||||
<span>Mirrors</span>
|
{app.state?.auto_update ? <FaCheck className="status-icon auto-update" /> : <FaTimes className="status-icon no-auto-update" />}
|
||||||
<span>{mirrors.length}</span>
|
</li>
|
||||||
<MirrorsDropdown mirrors={mirrors} />
|
</ul>
|
||||||
</div>
|
|
||||||
<div className="app-info-item">
|
|
||||||
<FaLink size={36} />
|
|
||||||
<span>TBA</span>
|
|
||||||
<a href={tbaLink} target="_blank" rel="noopener noreferrer">
|
|
||||||
{`${app.package}.${app.publisher}`}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="app-info-item">
|
|
||||||
<span>Installed</span>
|
|
||||||
{app.installed ? <FaCheckCircle color="green" /> : <FaTimesCircle color="red" />}
|
|
||||||
</div>
|
|
||||||
{app.state && (
|
|
||||||
<>
|
|
||||||
<div className="app-info-item">
|
|
||||||
<span>Mirrored From</span>
|
|
||||||
<span>{app.state.mirrored_from || "N/A"}</span>
|
|
||||||
</div>
|
|
||||||
<div className="app-info-item">
|
|
||||||
<span>Capabilities Approved</span>
|
|
||||||
{app.state.caps_approved ? <FaCheckCircle color="green" /> : <FaTimesCircle color="red" />}
|
|
||||||
</div>
|
|
||||||
<div className="app-info-item">
|
|
||||||
<span>Mirroring</span>
|
|
||||||
{app.state.mirroring ? <FaCheckCircle color="green" /> : <FaTimesCircle color="red" />}
|
|
||||||
</div>
|
|
||||||
<div className="app-info-item">
|
|
||||||
<span>Auto Update</span>
|
|
||||||
{app.state.auto_update ? <FaCheckCircle color="green" /> : <FaTimesCircle color="red" />}
|
|
||||||
</div>
|
|
||||||
<div className="app-info-item">
|
|
||||||
<span>Verified</span>
|
|
||||||
{app.state.verified ? <FaCheckCircle color="green" /> : <FaTimesCircle color="red" />}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{app.metadata?.properties?.screenshots && (
|
|
||||||
<div className="app-screenshots">
|
|
||||||
{app.metadata.properties.screenshots.map((screenshot, index) => (
|
|
||||||
<img key={index} src={screenshot} alt={`Screenshot ${index + 1}`} className="app-screenshot" />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="app-actions">
|
<div className="app-actions">
|
||||||
{app.installed ? (
|
{app.installed ? (
|
||||||
<>
|
<>
|
||||||
<button onClick={handleUpdate}>Update</button>
|
<button onClick={handleUpdate} className="secondary"><FaSync /> Update</button>
|
||||||
<button onClick={handleUninstall}>Uninstall</button>
|
<button onClick={handleUninstall} className="secondary"><FaTrash /> Uninstall</button>
|
||||||
<button onClick={handleMirror}>
|
|
||||||
{app.state?.mirroring ? "Stop Mirroring" : "Start Mirroring"}
|
|
||||||
</button>
|
|
||||||
<button onClick={handleAutoUpdate}>
|
|
||||||
{app.state?.auto_update ? "Disable Auto-Update" : "Enable Auto-Update"}
|
|
||||||
</button>
|
|
||||||
{app.state?.mirroring && (
|
|
||||||
<button onClick={handlePublish}>Publish</button>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<button onClick={handleInstall}>Install</button>
|
<button onClick={handleInstall}><FaDownload /> Install</button>
|
||||||
)}
|
)}
|
||||||
|
<button onClick={handleMirror} className="secondary">
|
||||||
|
<FaMagnet /> {app.state?.mirroring ? "Stop Mirroring" : "Start Mirroring"}
|
||||||
|
</button>
|
||||||
|
<button onClick={handleAutoUpdate} className="secondary">
|
||||||
|
<FaCog /> {app.state?.auto_update ? "Disable Auto-Update" : "Enable Auto-Update"}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{app.metadata?.properties?.screenshots && (
|
||||||
);
|
<div className="app-screenshots">
|
||||||
}
|
{app.metadata.properties.screenshots.map((screenshot, index) => (
|
||||||
|
<img key={index} src={screenshot} alt={`Screenshot ${index + 1}`} className="app-screenshot" />
|
||||||
const MirrorsDropdown = ({ mirrors }: { mirrors: string[] }) => {
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mirrors-dropdown">
|
|
||||||
<button onClick={() => setIsOpen(!isOpen)} className="mirrors-dropdown-toggle">
|
|
||||||
Mirrors <FaCaretDown />
|
|
||||||
</button>
|
|
||||||
{isOpen && (
|
|
||||||
<ul className="mirrors-list">
|
|
||||||
{mirrors.map((mirror, index) => (
|
|
||||||
<li key={index}>{mirror}</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
}
|
@ -39,7 +39,7 @@ export default function PublishPage() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMyPublishedApps(
|
setMyPublishedApps(
|
||||||
apps.filter((app) => app.owner?.toLowerCase() === address?.toLowerCase())
|
apps.filter((app) => app.publisher?.toLowerCase() === window.our.node?.toLowerCase())
|
||||||
);
|
);
|
||||||
}, [apps, address])
|
}, [apps, address])
|
||||||
|
|
||||||
|
@ -3,20 +3,22 @@ import useAppsStore from "../store";
|
|||||||
import { AppInfo } from "../types/Apps";
|
import { AppInfo } from "../types/Apps";
|
||||||
import { appId } from '../utils/app'
|
import { appId } from '../utils/app'
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { FaGlobe, FaPeopleGroup, FaCode } from "react-icons/fa6";
|
import { FaGlobe, FaPeopleGroup, FaCode, FaFilter } from "react-icons/fa6";
|
||||||
|
|
||||||
export default function StorePage() {
|
export default function StorePage() {
|
||||||
const { apps, getApps, rebuildIndex } = useAppsStore();
|
const { apps, getApps, rebuildIndex } = useAppsStore();
|
||||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||||
const [isRebuildingIndex, setIsRebuildingIndex] = useState(false);
|
const [isRebuildingIndex, setIsRebuildingIndex] = useState(false);
|
||||||
|
const [showMyApps, setShowMyApps] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getApps();
|
getApps();
|
||||||
}, [getApps]);
|
}, [getApps]);
|
||||||
|
|
||||||
const filteredApps = apps.filter((app) =>
|
const filteredApps = apps.filter((app) =>
|
||||||
app.package.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
(app.package.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
app.metadata?.description?.toLowerCase().includes(searchQuery.toLowerCase())
|
app.metadata?.description?.toLowerCase().includes(searchQuery.toLowerCase())) &&
|
||||||
|
(!showMyApps || app.installed)
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleRebuildIndex = async () => {
|
const handleRebuildIndex = async () => {
|
||||||
@ -44,6 +46,12 @@ export default function StorePage() {
|
|||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
className={`filter-button ${showMyApps ? 'active' : ''}`}
|
||||||
|
onClick={() => setShowMyApps(!showMyApps)}
|
||||||
|
>
|
||||||
|
<FaFilter /> {showMyApps ? 'All Apps' : 'My Apps'}
|
||||||
|
</button>
|
||||||
<button onClick={handleRebuildIndex} disabled={isRebuildingIndex}>
|
<button onClick={handleRebuildIndex} disabled={isRebuildingIndex}>
|
||||||
{isRebuildingIndex ? "Rebuilding..." : "Rebuild Index"}
|
{isRebuildingIndex ? "Rebuilding..." : "Rebuild Index"}
|
||||||
</button>
|
</button>
|
||||||
|
Loading…
Reference in New Issue
Block a user