mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-20 14:37:43 +01:00
Add onboarding functionality
This commit is contained in:
parent
925f3dff19
commit
a226f3347c
6 changed files with 92 additions and 20 deletions
|
@ -12,7 +12,7 @@ import { PageTitle } from "@/pages/parts/util/PageTitle";
|
|||
export function OnboardingPage() {
|
||||
const navigate = useNavigate();
|
||||
const skipModal = useModal("skip");
|
||||
const { skipAndRedirect } = useRedirectBack();
|
||||
const { completeAndRedirect } = useRedirectBack();
|
||||
|
||||
return (
|
||||
<MinimalPageLayout>
|
||||
|
@ -25,7 +25,7 @@ export function OnboardingPage() {
|
|||
<Button theme="secondary" onClick={skipModal.hide}>
|
||||
Lorem ipsum
|
||||
</Button>
|
||||
<Button theme="danger" onClick={() => skipAndRedirect()}>
|
||||
<Button theme="danger" onClick={() => completeAndRedirect()}>
|
||||
Lorem ipsum
|
||||
</Button>
|
||||
</ModalCard>
|
||||
|
|
|
@ -1,14 +1,64 @@
|
|||
import { ReactNode } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useAsyncFn, useInterval } from "react-use";
|
||||
|
||||
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
|
||||
import { extensionInfo } from "@/backend/extension/messaging";
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
import { Stepper } from "@/components/layout/Stepper";
|
||||
import { CenterContainer } from "@/components/layout/ThinContainer";
|
||||
import { Heading2, Paragraph } from "@/components/utils/Text";
|
||||
import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
|
||||
import { useRedirectBack } from "@/pages/onboarding/onboardingHooks";
|
||||
import { PageTitle } from "@/pages/parts/util/PageTitle";
|
||||
|
||||
type ExtensionStatus =
|
||||
| "unknown"
|
||||
| "failed"
|
||||
| "disallowed"
|
||||
| "noperms"
|
||||
| "outdated"
|
||||
| "success";
|
||||
|
||||
async function getExtensionState(): Promise<ExtensionStatus> {
|
||||
const info = await extensionInfo();
|
||||
if (!info) return "unknown"; // cant talk to extension
|
||||
if (!info.success) return "failed"; // extension failed to respond
|
||||
if (!info.allowed) return "disallowed"; // extension is not enabled on this page
|
||||
if (!info.hasPermission) return "noperms"; // extension has no perms to do it's tasks
|
||||
if (!isAllowedExtensionVersion(info.version)) return "outdated"; // extension is too old
|
||||
return "success"; // no problems
|
||||
}
|
||||
|
||||
export function ExtensionStatus(props: {
|
||||
status: ExtensionStatus;
|
||||
loading: boolean;
|
||||
}) {
|
||||
let content: ReactNode = null;
|
||||
if (props.loading || props.status === "unknown")
|
||||
content = <p>waiting on extension...</p>;
|
||||
if (props.status === "disallowed")
|
||||
content = <p>Extension disabled for this page</p>;
|
||||
else if (props.status === "failed") content = <p>Failed to request status</p>;
|
||||
else if (props.status === "outdated") content = <p>Extension too old</p>;
|
||||
else if (props.status === "noperms") content = <p>No permissions to act</p>;
|
||||
else if (props.status === "success") content = <p>Extension is working!</p>;
|
||||
return <div>{content}</div>;
|
||||
}
|
||||
|
||||
export function OnboardingExtensionPage() {
|
||||
const navigate = useNavigate();
|
||||
const { completeAndRedirect } = useRedirectBack();
|
||||
|
||||
const [{ loading, value }, exec] = useAsyncFn(
|
||||
async (triggeredManually: boolean = false) => {
|
||||
const status = await getExtensionState();
|
||||
if (status === "success" && triggeredManually) completeAndRedirect();
|
||||
return status;
|
||||
},
|
||||
[completeAndRedirect],
|
||||
);
|
||||
useInterval(exec, 1000);
|
||||
|
||||
return (
|
||||
<MinimalPageLayout>
|
||||
|
@ -17,9 +67,10 @@ export function OnboardingExtensionPage() {
|
|||
<Stepper steps={2} current={2} className="mb-12" />
|
||||
<Heading2 className="!mt-0">Lorem ipsum</Heading2>
|
||||
<Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph>
|
||||
<ExtensionStatus status={value ?? "unknown"} loading={loading} />
|
||||
<Button onClick={() => navigate("/onboarding")}>Back</Button>
|
||||
<Button onClick={() => alert("Check extension here or something")}>
|
||||
Check extension
|
||||
<Button onClick={() => exec(true)}>
|
||||
{value === "success" ? "Continue" : "Check extension"}{" "}
|
||||
</Button>
|
||||
</CenterContainer>
|
||||
</MinimalPageLayout>
|
||||
|
|
|
@ -1,14 +1,33 @@
|
|||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useAsyncFn } from "react-use";
|
||||
|
||||
import { singularProxiedFetch } from "@/backend/helpers/fetch";
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
import { Stepper } from "@/components/layout/Stepper";
|
||||
import { CenterContainer } from "@/components/layout/ThinContainer";
|
||||
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
||||
import { Heading2, Paragraph } from "@/components/utils/Text";
|
||||
import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
|
||||
import { useRedirectBack } from "@/pages/onboarding/onboardingHooks";
|
||||
import { PageTitle } from "@/pages/parts/util/PageTitle";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
const testUrl = "https://postman-echo.com/get";
|
||||
|
||||
export function OnboardingProxyPage() {
|
||||
const navigate = useNavigate();
|
||||
const { completeAndRedirect } = useRedirectBack();
|
||||
const [url, setUrl] = useState("");
|
||||
const setProxySet = useAuthStore((s) => s.setProxySet);
|
||||
|
||||
const [{ loading, error }, test] = useAsyncFn(async () => {
|
||||
if (!url.startsWith("http")) throw new Error("Not a valid URL");
|
||||
const res = await singularProxiedFetch(url, testUrl, {});
|
||||
if (res.url !== testUrl) throw new Error("Not a proxy");
|
||||
setProxySet([url]);
|
||||
completeAndRedirect();
|
||||
}, [url, completeAndRedirect, setProxySet]);
|
||||
|
||||
return (
|
||||
<MinimalPageLayout>
|
||||
|
@ -17,10 +36,12 @@ export function OnboardingProxyPage() {
|
|||
<Stepper steps={2} current={2} className="mb-12" />
|
||||
<Heading2 className="!mt-0">Lorem ipsum</Heading2>
|
||||
<Paragraph>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</Paragraph>
|
||||
<Button onClick={() => navigate("/onboarding")}>Back</Button>
|
||||
<Button onClick={() => alert("Check proxy or smth")}>
|
||||
Check extension
|
||||
<AuthInputBox value={url} onChange={setUrl} placeholder="lorem ipsum" />
|
||||
{error ? <p>url invalid</p> : null}
|
||||
<Button onClick={() => navigate("/onboarding")} loading={loading}>
|
||||
Backagd
|
||||
</Button>
|
||||
<Button onClick={test}>Submit proxy</Button>
|
||||
</CenterContainer>
|
||||
</MinimalPageLayout>
|
||||
);
|
||||
|
|
|
@ -7,16 +7,16 @@ import { useOnboardingStore } from "@/stores/onboarding";
|
|||
export function useRedirectBack() {
|
||||
const [url] = useQueryParam("redirect");
|
||||
const navigate = useNavigate();
|
||||
const setSkipped = useOnboardingStore((s) => s.setSkipped);
|
||||
const setCompleted = useOnboardingStore((s) => s.setCompleted);
|
||||
|
||||
const redirectBack = useCallback(() => {
|
||||
navigate(url ?? "/");
|
||||
}, [navigate, url]);
|
||||
|
||||
const skipAndRedirect = useCallback(() => {
|
||||
setSkipped(true);
|
||||
const completeAndRedirect = useCallback(() => {
|
||||
setCompleted(true);
|
||||
redirectBack();
|
||||
}, [redirectBack, setSkipped]);
|
||||
}, [redirectBack, setCompleted]);
|
||||
|
||||
return { redirectBack, skipAndRedirect };
|
||||
return { completeAndRedirect };
|
||||
}
|
||||
|
|
|
@ -3,17 +3,17 @@ import { persist } from "zustand/middleware";
|
|||
import { immer } from "zustand/middleware/immer";
|
||||
|
||||
export interface OnboardingStore {
|
||||
skipped: boolean;
|
||||
setSkipped(v: boolean): void;
|
||||
completed: boolean;
|
||||
setCompleted(v: boolean): void;
|
||||
}
|
||||
|
||||
export const useOnboardingStore = create(
|
||||
persist(
|
||||
immer<OnboardingStore>((set) => ({
|
||||
skipped: false,
|
||||
setSkipped(v) {
|
||||
completed: false,
|
||||
setCompleted(v) {
|
||||
set((s) => {
|
||||
s.skipped = v;
|
||||
s.completed = v;
|
||||
});
|
||||
},
|
||||
})),
|
||||
|
|
|
@ -15,9 +15,9 @@ export async function needsOnboarding(): Promise<boolean> {
|
|||
const proxyUrls = useAuthStore.getState().proxySet;
|
||||
if (proxyUrls) return false;
|
||||
|
||||
// if onboarding has been skipped, no onboarding needed
|
||||
const skipped = useOnboardingStore.getState().skipped;
|
||||
if (skipped) return false;
|
||||
// if onboarding has been completed, no onboarding needed
|
||||
const completed = useOnboardingStore.getState().completed;
|
||||
if (completed) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue