mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-22 08:01:47 +03:00
Merge pull request #345 from kinode-dao/tm/appstore-flows
repair some missing appstore flows
This commit is contained in:
commit
1bb7b5a86f
94
kinode/packages/app_store/pkg/ui/assets/index-34EVhDFF.js
Normal file
94
kinode/packages/app_store/pkg/ui/assets/index-34EVhDFF.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -14,8 +14,8 @@
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-BxGs27ah.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-umttRNrr.css">
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-34EVhDFF.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-cJEV35Fc.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -5,6 +5,7 @@ import DownloadButton from "./DownloadButton";
|
||||
import InstallButton from "./InstallButton";
|
||||
import LaunchButton from "./LaunchButton";
|
||||
import { FaCheck } from "react-icons/fa6";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface ActionButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
@ -12,7 +13,6 @@ interface ActionButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
}
|
||||
|
||||
export default function ActionButton({ app, isIcon = false, ...props }: ActionButtonProps) {
|
||||
const [incrementNumber, setIncrementNumber] = useState(0);
|
||||
const { installed, downloaded, updatable } = useMemo(() => {
|
||||
const versions = Object.entries(app?.metadata?.properties?.code_hashes || {});
|
||||
const latestHash = (versions.find(([v]) => v === app.metadata?.properties?.current_version) || [])[1];
|
||||
@ -29,7 +29,7 @@ export default function ActionButton({ app, isIcon = false, ...props }: ActionBu
|
||||
downloaded,
|
||||
updatable,
|
||||
};
|
||||
}, [app, incrementNumber]);
|
||||
}, [app]);
|
||||
|
||||
|
||||
const [launchPath, setLaunchPath] = useState('');
|
||||
@ -44,25 +44,33 @@ export default function ActionButton({ app, isIcon = false, ...props }: ActionBu
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [app, incrementNumber])
|
||||
}, [app])
|
||||
|
||||
return (
|
||||
<>
|
||||
{(installed && launchPath)
|
||||
? <LaunchButton app={app} {...props} isIcon={isIcon} launchPath={launchPath} />
|
||||
: (installed && updatable)
|
||||
? <UpdateButton app={app} {...props} isIcon={isIcon} callback={() => setIncrementNumber(incrementNumber + 1)} />
|
||||
? <UpdateButton app={app} {...props} isIcon={isIcon} />
|
||||
: !downloaded
|
||||
? <DownloadButton app={app} {...props} isIcon={isIcon} callback={() => setIncrementNumber(incrementNumber + 1)} />
|
||||
? <DownloadButton app={app} {...props} isIcon={isIcon} />
|
||||
: !installed
|
||||
? <InstallButton app={app} {...props} isIcon={isIcon} callback={() => setIncrementNumber(incrementNumber + 1)} />
|
||||
? <InstallButton app={app} {...props} isIcon={isIcon} />
|
||||
: isIcon
|
||||
? <button
|
||||
className="pointer-events none icon clear absolute top-0 right-0"
|
||||
>
|
||||
<FaCheck />
|
||||
</button>
|
||||
: <div>Installed</div>}
|
||||
: <></>
|
||||
// <button
|
||||
// onClick={() => { }}
|
||||
// {...props as any}
|
||||
// className={classNames("clear pointer-events-none", props.className)}
|
||||
// >
|
||||
// Installed
|
||||
// </button>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -8,14 +8,16 @@ import { isMobileCheck } from "../utils/dimensions";
|
||||
import classNames from "classnames";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { APP_DETAILS_PATH } from "../constants/path";
|
||||
import MoreActions from "./MoreActions";
|
||||
|
||||
interface AppEntryProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
app: AppInfo;
|
||||
size?: "small" | "medium" | "large";
|
||||
overrideImageSize?: "small" | "medium" | "large";
|
||||
showMoreActions?: boolean;
|
||||
}
|
||||
|
||||
export default function AppEntry({ app, size = "medium", overrideImageSize, ...props }: AppEntryProps) {
|
||||
export default function AppEntry({ app, size = "medium", overrideImageSize, showMoreActions, ...props }: AppEntryProps) {
|
||||
const isMobile = isMobileCheck()
|
||||
const navigate = useNavigate()
|
||||
|
||||
@ -27,17 +29,26 @@ export default function AppEntry({ app, size = "medium", overrideImageSize, ...p
|
||||
'flex-wrap gap-2': isMobile,
|
||||
'flex-col relative': size !== 'large'
|
||||
})}
|
||||
onClick={() => navigate(`/${APP_DETAILS_PATH}/${appId(app)}`)}
|
||||
onClick={() => {
|
||||
if (!showMoreActions) {
|
||||
navigate(`/${APP_DETAILS_PATH}/${appId(app)}`)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AppHeader app={app} size={size} overrideImageSize={overrideImageSize} />
|
||||
<ActionButton
|
||||
app={app}
|
||||
isIcon={size !== 'large'}
|
||||
isIcon={!showMoreActions && size !== 'large'}
|
||||
className={classNames({
|
||||
'absolute top-0 right-0': size !== 'large',
|
||||
'absolute': size !== 'large',
|
||||
'top-2 right-2': size !== 'large' && showMoreActions,
|
||||
'top-0 right-0': size !== 'large' && !showMoreActions,
|
||||
'bg-orange text-lg min-w-1/5': size === 'large',
|
||||
'ml-auto': size === 'large' && isMobile
|
||||
})} />
|
||||
{showMoreActions && <div className="absolute bottom-2 right-2">
|
||||
<MoreActions app={app} />
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -47,15 +47,15 @@ export default function AppHeader({
|
||||
alt="app icon"
|
||||
className={classNames('object-cover', {
|
||||
'rounded': !imageSize,
|
||||
'rounded-lg': imageSize === 'small',
|
||||
'rounded-xl': imageSize === 'medium',
|
||||
'rounded-md': imageSize === 'small',
|
||||
'rounded-lg': imageSize === 'medium',
|
||||
'rounded-2xl': imageSize === 'large',
|
||||
'h-32': imageSize === 'large' || imageSize === 'small',
|
||||
'h-20': imageSize === 'medium',
|
||||
})}
|
||||
/>
|
||||
: <ColorDot
|
||||
num={app.metadata_hash}
|
||||
num={app.metadata_hash || app.state?.our_version?.toString() || ''}
|
||||
dotSize={imageSize}
|
||||
/>}
|
||||
<div className={classNames("flex flex-col", {
|
||||
|
@ -15,7 +15,7 @@ const ColorDot: React.FC<ColorDotProps> = ({
|
||||
}) => {
|
||||
const isMobile = isMobileCheck()
|
||||
|
||||
num = (num || '').replace(/(0x|\.)/g, '')
|
||||
num = num ? num : '';
|
||||
|
||||
while (num.length < 6) {
|
||||
num = '0' + num
|
||||
|
@ -5,17 +5,15 @@ import Modal from "./Modal";
|
||||
import { getAppName } from "../utils/app";
|
||||
import Loader from "./Loader";
|
||||
import classNames from "classnames";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { FaDownload } from "react-icons/fa6";
|
||||
|
||||
interface DownloadButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
isIcon?: boolean;
|
||||
callback?: () => void;
|
||||
}
|
||||
|
||||
export default function DownloadButton({ app, isIcon = false, callback, ...props }: DownloadButtonProps) {
|
||||
const { downloadApp, getCaps, getMyApp } =
|
||||
export default function DownloadButton({ app, isIcon = false, ...props }: DownloadButtonProps) {
|
||||
const { downloadApp, getCaps, getMyApp, getMyApps } =
|
||||
useAppsStore();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [mirror, setMirror] = useState(app.metadata?.properties?.mirrors?.[0] || "Other");
|
||||
@ -50,7 +48,7 @@ export default function DownloadButton({ app, isIcon = false, callback, ...props
|
||||
setLoading("");
|
||||
setShowModal(false);
|
||||
clearInterval(interval);
|
||||
callback && callback();
|
||||
getMyApps();
|
||||
})
|
||||
.catch(console.log);
|
||||
}, 2000);
|
||||
|
@ -12,6 +12,7 @@ export default function Dropdown({ ...props }: DropdownProps) {
|
||||
{...props}
|
||||
unmountOnClose={true}
|
||||
className={classNames("relative", props.className)}
|
||||
direction='left'
|
||||
menuButton={<MenuButton className="small">
|
||||
<FaEllipsisH className='-mb-1' />
|
||||
</MenuButton>}
|
||||
|
@ -10,11 +10,10 @@ import { FaI } from "react-icons/fa6";
|
||||
interface InstallButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
isIcon?: boolean;
|
||||
callback?: () => void;
|
||||
}
|
||||
|
||||
export default function InstallButton({ app, isIcon = false, callback, ...props }: InstallButtonProps) {
|
||||
const { installApp, getCaps, getMyApp } =
|
||||
export default function InstallButton({ app, isIcon = false, ...props }: InstallButtonProps) {
|
||||
const { installApp, getCaps, getMyApp, getMyApps } =
|
||||
useAppsStore();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [caps, setCaps] = useState<string[]>([]);
|
||||
@ -40,7 +39,7 @@ export default function InstallButton({ app, isIcon = false, callback, ...props
|
||||
setLoading("");
|
||||
setShowModal(false);
|
||||
clearInterval(interval);
|
||||
callback && callback();
|
||||
getMyApps();
|
||||
})
|
||||
.catch(console.log);
|
||||
}, 2000);
|
||||
|
@ -23,7 +23,7 @@ export default function MoreActions({ app, className }: MoreActionsProps) {
|
||||
|
||||
return (
|
||||
<Dropdown className={className}>
|
||||
<div className="flex flex-col backdrop-blur-lg p-2 rounded-lg relative z-10">
|
||||
<div className="flex flex-col backdrop-blur-lg bg-black/10 p-2 rounded-lg relative z-10">
|
||||
{app.metadata?.description && (
|
||||
<button
|
||||
className="my-1 whitespace-nowrap clear"
|
||||
|
@ -9,11 +9,10 @@ import classNames from "classnames";
|
||||
interface UpdateButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
isIcon?: boolean;
|
||||
callback?: () => void
|
||||
}
|
||||
|
||||
export default function UpdateButton({ app, callback, isIcon = false, ...props }: UpdateButtonProps) {
|
||||
const { updateApp, getCaps, getMyApp } =
|
||||
export default function UpdateButton({ app, isIcon = false, ...props }: UpdateButtonProps) {
|
||||
const { updateApp, getCaps, getMyApp, getMyApps } =
|
||||
useAppsStore();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [caps, setCaps] = useState<string[]>([]);
|
||||
@ -40,7 +39,7 @@ export default function UpdateButton({ app, callback, isIcon = false, ...props }
|
||||
setLoading("");
|
||||
setShowModal(false);
|
||||
clearInterval(interval);
|
||||
callback && callback();
|
||||
getMyApps();
|
||||
})
|
||||
.catch(console.log);
|
||||
}, 2000);
|
||||
|
@ -37,7 +37,7 @@ export default function AppPage() {
|
||||
.catch(console.error);
|
||||
}
|
||||
}
|
||||
}, [params.id]);
|
||||
}, [params.id, myApps, listedApps]);
|
||||
|
||||
const goToPublish = useCallback(() => {
|
||||
navigate(PUBLISH_PATH, { state: { app } });
|
||||
@ -92,9 +92,9 @@ export default function AppPage() {
|
||||
]
|
||||
|
||||
return (
|
||||
<div className={classNames("flex flex-col w-full h-screen",
|
||||
<div className={classNames("flex flex-col w-full p-2",
|
||||
{
|
||||
'gap-4 p-2 max-w-screen': isMobile,
|
||||
'gap-4 max-w-screen': isMobile,
|
||||
'gap-8 max-w-[900px]': !isMobile,
|
||||
})}
|
||||
>
|
||||
|
@ -10,9 +10,11 @@ import { useNavigate } from "react-router-dom";
|
||||
import { appId } from "../utils/app";
|
||||
import { PUBLISH_PATH } from "../constants/path";
|
||||
import HomeButton from "../components/HomeButton";
|
||||
import { isMobileCheck } from "../utils/dimensions";
|
||||
import classNames from "classnames";
|
||||
|
||||
export default function MyAppsPage() { // eslint-disable-line
|
||||
const { myApps, getMyApps } = useAppsStore()
|
||||
const { myApps, getMyApps, } = useAppsStore()
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||
@ -52,8 +54,15 @@ export default function MyAppsPage() { // eslint-disable-line
|
||||
}
|
||||
}, [myApps]);
|
||||
|
||||
const isMobile = isMobileCheck()
|
||||
console.log({ myApps })
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full max-w-[900px]">
|
||||
<div className={classNames("flex flex-col w-full h-screen p-2",
|
||||
{
|
||||
'gap-4 max-w-screen': isMobile,
|
||||
'gap-8 max-w-[900px]': !isMobile,
|
||||
})}>
|
||||
<HomeButton />
|
||||
<SearchHeader value={searchQuery} onChange={searchMyApps} />
|
||||
<div className="flex justify-between items-center mt-2">
|
||||
@ -64,15 +73,39 @@ export default function MyAppsPage() { // eslint-disable-line
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col card gap-2 mt-2">
|
||||
<h4>Downloaded</h4>
|
||||
{(displayedApps.downloaded || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>Installed</h4>
|
||||
{(displayedApps.installed || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>Local</h4>
|
||||
{(displayedApps.local || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>System</h4>
|
||||
{(displayedApps.system || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<div className={classNames("flex flex-col card gap-2 mt-2",
|
||||
{
|
||||
'max-h-[80vh] overflow-y-scroll overflow-x-visible': !isMobile,
|
||||
})}
|
||||
style={{
|
||||
scrollbarWidth: 'thin',
|
||||
scrollbarColor: '#FFF5D9 transparent',
|
||||
}}
|
||||
>
|
||||
{displayedApps.downloaded.length > 0 && <h4>Downloaded</h4>}
|
||||
{(displayedApps.downloaded || []).map((app) => <AppEntry
|
||||
key={appId(app)}
|
||||
app={app}
|
||||
showMoreActions
|
||||
/>)}
|
||||
{displayedApps.installed.length > 0 && <h4>Installed</h4>}
|
||||
{(displayedApps.installed || []).map((app) => <AppEntry
|
||||
key={appId(app)}
|
||||
app={app}
|
||||
showMoreActions
|
||||
/>)}
|
||||
{displayedApps.local.length > 0 && <h4>Local</h4>}
|
||||
{(displayedApps.local || []).map((app) => <AppEntry
|
||||
key={appId(app)}
|
||||
app={app}
|
||||
showMoreActions
|
||||
/>)}
|
||||
{displayedApps.system.length > 0 && <h4>System</h4>}
|
||||
{(displayedApps.system || []).map((app) => <AppEntry
|
||||
key={appId(app)}
|
||||
app={app}
|
||||
showMoreActions
|
||||
/>)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -126,8 +126,8 @@ export default function StorePage() {
|
||||
const isMobile = isMobileCheck()
|
||||
|
||||
return (
|
||||
<div className={classNames("flex flex-col w-full max-h-screen", {
|
||||
'gap-4 max-w-screen p-2': isMobile,
|
||||
<div className={classNames("flex flex-col w-full max-h-screen p-2", {
|
||||
'gap-4 max-w-screen': isMobile,
|
||||
'gap-6 max-w-[900px]': !isMobile
|
||||
})}>
|
||||
{!isMobile && <HomeButton />}
|
||||
@ -173,7 +173,8 @@ export default function StorePage() {
|
||||
</select>
|
||||
</div>
|
||||
{!searchQuery ? <div className={classNames("flex flex-col", {
|
||||
'grow overflow-y-auto gap-4 items-center px-2': isMobile
|
||||
'gap-4': !isMobile,
|
||||
'grow overflow-y-auto gap-2 items-center px-2': isMobile
|
||||
})}>
|
||||
<h2>Top apps this week...</h2>
|
||||
<div className={classNames("flex gap-2", {
|
||||
@ -195,7 +196,7 @@ export default function StorePage() {
|
||||
<div className={classNames("flex gap-2", {
|
||||
'flex-col': isMobile
|
||||
})}>
|
||||
{displayedApps.slice(0, 6).map((app) => (
|
||||
{displayedApps.slice(0, 5).map((app) => (
|
||||
<AppEntry
|
||||
key={appId(app) + (app.state?.our_version || "")}
|
||||
size={isMobile ? 'medium' : 'small'}
|
||||
|
@ -47,12 +47,16 @@ const useAppsStore = create<AppsStore>()(
|
||||
searchResults: [] as AppInfo[],
|
||||
query: '',
|
||||
getMyApps: async () => {
|
||||
const listedApps = await get().getListedApps()
|
||||
const res = await fetch(`${BASE_URL}/apps`)
|
||||
const apps = await res.json() as AppInfo[]
|
||||
|
||||
const myApps = apps.reduce((acc, app) => {
|
||||
const appType = getAppType(app)
|
||||
|
||||
if (listedApps.find(lapp => lapp.metadata_hash === app.metadata_hash)) {
|
||||
console.log({ listedappmatch: app })
|
||||
}
|
||||
acc[appType].push(app)
|
||||
return acc
|
||||
}, {
|
||||
|
Loading…
Reference in New Issue
Block a user