mirror of
https://github.com/codex-storage/codex-marketplace-ui.git
synced 2025-02-24 13:48:14 +00:00
Improve onboarding screen
This commit is contained in:
parent
ed932e1baf
commit
d4667c5ec7
@ -1,14 +1,10 @@
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useEffect, useState } from "react";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
import {
|
||||
NetworkIndicator,
|
||||
Toast,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { Promises } from "../../utils/promises";
|
||||
|
||||
const report = false;
|
||||
export let isCodexOnline: boolean | null = null;
|
||||
import { useCodexConnection } from "../../hooks/useCodexConnection";
|
||||
|
||||
export function NodeIndicator() {
|
||||
const queryClient = useQueryClient();
|
||||
@ -16,44 +12,19 @@ export function NodeIndicator() {
|
||||
time: 0,
|
||||
message: "",
|
||||
});
|
||||
|
||||
const { data, isError } = useQuery({
|
||||
queryKey: ["spr"],
|
||||
queryFn: async () => {
|
||||
return CodexSdk.node()
|
||||
.spr()
|
||||
.then((data) => Promises.rejectOnError(data, report));
|
||||
},
|
||||
refetchInterval: 5000,
|
||||
|
||||
// No need to retry because we defined a refetch interval
|
||||
retry: false,
|
||||
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
// Refreshing when focus returns can be useful if a user comes back
|
||||
// to the UI after performing an operation in the terminal.
|
||||
refetchOnWindowFocus: true,
|
||||
|
||||
// Cache is not useful for the spr endpoint
|
||||
gcTime: 0,
|
||||
});
|
||||
|
||||
isCodexOnline = !isError && !!data;
|
||||
const codex = useCodexConnection();
|
||||
|
||||
useEffect(() => {
|
||||
queryClient.invalidateQueries({
|
||||
type: "active",
|
||||
refetchType: "all",
|
||||
});
|
||||
}, [queryClient, isCodexOnline]);
|
||||
}, [queryClient, codex.enabled]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toast message={toast.message} time={toast.time} variant="success" />
|
||||
<NetworkIndicator online={isCodexOnline} text="Codex node" />
|
||||
<NetworkIndicator online={codex.enabled} text="Codex node" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
100
src/components/OnBoarding/OnBoardingStepOne.tsx
Normal file
100
src/components/OnBoarding/OnBoardingStepOne.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
import { AlphaIcon } from "./AlphaIcon";
|
||||
import { AlphaText } from "../AlphaText/AlphaText";
|
||||
import { Modal, SimpleText } from "@codex-storage/marketplace-ui-components";
|
||||
import { useState } from "react";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
|
||||
type Props = {
|
||||
onNextStep: () => void;
|
||||
};
|
||||
|
||||
export function OnBoardingStepOne({ onNextStep }: Props) {
|
||||
const [modal, setModal] = useState(false);
|
||||
|
||||
const onLegalDisclaimerOpen = () => setModal(true);
|
||||
|
||||
const onLegalDisclaimerClose = () => setModal(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="index-column-section">
|
||||
<div>
|
||||
<AlphaIcon />
|
||||
</div>
|
||||
<div className="index-alphaText">
|
||||
<p>
|
||||
<AlphaText></AlphaText>
|
||||
</p>
|
||||
<p>
|
||||
<SimpleText className="index-version" variant="normal">
|
||||
{import.meta.env.PACKAGE_VERSION}
|
||||
</SimpleText>
|
||||
</p>
|
||||
<p>
|
||||
<SimpleText
|
||||
className="index-disclaimer"
|
||||
variant="error"
|
||||
onClick={onLegalDisclaimerOpen}>
|
||||
<a className="index-link">Legal Disclaimer</a>
|
||||
</SimpleText>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="index-column-section">
|
||||
<h3 className="index-mainTitle">
|
||||
Hello,
|
||||
<br /> Welcome to <span className="index-codex">Codex</span>{" "}
|
||||
<span className="index-vault">Vault</span>
|
||||
</h3>
|
||||
<p className="index-description">
|
||||
<SimpleText variant="light">
|
||||
Codex is a durable, decentralised data storage protocol, created so
|
||||
the world community can preserve its most important knowledge
|
||||
without risk of censorship.
|
||||
</SimpleText>
|
||||
</p>
|
||||
</div>
|
||||
<div className="index-column-section ">
|
||||
<SimpleText variant="primary">
|
||||
<a onClick={onNextStep} className="index-link index-getStarted">
|
||||
Let’s get started <ArrowRight></ArrowRight>
|
||||
</a>
|
||||
</SimpleText>
|
||||
|
||||
<Modal onClose={onLegalDisclaimerClose} open={modal}>
|
||||
<h1 className="disclaimer-title" style={{ marginTop: 0 }}>
|
||||
Disclaimer
|
||||
</h1>
|
||||
|
||||
<p className="disclaimer-text">
|
||||
The website and the content herein is not intended for public use
|
||||
and is for informational and demonstration purposes only.
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<p className="disclaimer-text">
|
||||
The website and any associated functionalities are provided on an
|
||||
“as is” basis without any guarantees, warranties, or representations
|
||||
of any kind, either express or implied. The website and any
|
||||
associated functionalities may not reflect the final version of the
|
||||
project and is subject to changes, updates, or removal at any time
|
||||
and without notice.
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<p className="disclaimer-text">
|
||||
By accessing and using this website, you agree that we, Logos
|
||||
Collective Association and its affiliates, will not be liable for
|
||||
any direct, indirect, incidental, or consequential damages arising
|
||||
from the use of, or inability to use, this website. Any data,
|
||||
content, or interactions on this site are non-binding and should not
|
||||
be considered final or actionable. Your use of this website is at
|
||||
your sole risk.
|
||||
</p>
|
||||
</Modal>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
37
src/components/OnBoarding/OnBoardingStepThree.css
Normal file
37
src/components/OnBoarding/OnBoardingStepThree.css
Normal file
@ -0,0 +1,37 @@
|
||||
.onboarding-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.onboarding-check-icon--valid {
|
||||
color: var(--codex-color-primary);
|
||||
}
|
||||
|
||||
.onboarding-check-icon--invalid {
|
||||
color: rgb(var(--codex-color-error));
|
||||
}
|
||||
|
||||
.onboarding-check-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.onboarding-check-refresh {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.onboarding-check-refresh--fetching {
|
||||
animation: rotateAnimation 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg); /* Start at 0 degrees */
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg); /* End at 360 degrees */
|
||||
}
|
||||
}
|
114
src/components/OnBoarding/OnBoardingStepThree.tsx
Normal file
114
src/components/OnBoarding/OnBoardingStepThree.tsx
Normal file
@ -0,0 +1,114 @@
|
||||
import { CheckIcon, RefreshCcw, X } from "lucide-react";
|
||||
import { classnames } from "../../utils/classnames";
|
||||
import "./OnBoardingStepThree.css";
|
||||
import { usePortForwarding } from "../../hooks/usePortForwarding";
|
||||
import { useCodexConnection } from "../../hooks/useCodexConnection";
|
||||
import { SimpleText } from "@codex-storage/marketplace-ui-components";
|
||||
import { useEffect } from "react";
|
||||
|
||||
type Props = {
|
||||
online: boolean;
|
||||
onStepValid: (valid: boolean) => void;
|
||||
};
|
||||
|
||||
export function OnBoardingStepThree({ online, onStepValid }: Props) {
|
||||
const portForwarding = usePortForwarding(online);
|
||||
const codex = useCodexConnection();
|
||||
|
||||
useEffect(() => {
|
||||
onStepValid(online && portForwarding.enabled && codex.enabled);
|
||||
}, [portForwarding.enabled, codex.enabled, onStepValid, online]);
|
||||
|
||||
const InternetIcon = online ? CheckIcon : X;
|
||||
const PortForWarningIcon = portForwarding.enabled ? CheckIcon : X;
|
||||
const CodexIcon = codex.enabled ? CheckIcon : X;
|
||||
|
||||
return (
|
||||
<div className="index-column-section">
|
||||
<div
|
||||
className={classnames(
|
||||
["onboarding-check"],
|
||||
["onboarding-check--valid", online]
|
||||
)}>
|
||||
<InternetIcon
|
||||
className={classnames(
|
||||
["onboarding-check-icon--valid", online],
|
||||
["onboarding-check-icon--invalid", !online]
|
||||
)}
|
||||
/>
|
||||
<div>
|
||||
<p>Internet connection</p>
|
||||
<SimpleText variant="light">
|
||||
Status indicator for the Internet.
|
||||
</SimpleText>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classnames(
|
||||
["onboarding-check"],
|
||||
["onboarding-check--valid", portForwarding.enabled]
|
||||
)}>
|
||||
<PortForWarningIcon
|
||||
className={classnames(
|
||||
["onboarding-check-icon--valid", portForwarding.enabled],
|
||||
["onboarding-check-icon--invalid", !portForwarding.enabled]
|
||||
)}
|
||||
/>
|
||||
<div className="onboarding-check-line">
|
||||
<div>
|
||||
<p>Port forwarding</p>
|
||||
<SimpleText variant="light">
|
||||
Status indicator for port forwarding activation.
|
||||
</SimpleText>
|
||||
</div>
|
||||
{!portForwarding.enabled && (
|
||||
<a
|
||||
className="onboarding-check-refresh"
|
||||
onClick={() => portForwarding.refetch()}>
|
||||
<RefreshCcw
|
||||
size={"1.25rem"}
|
||||
className={classnames([
|
||||
"onboarding-check-refresh--fetching",
|
||||
portForwarding.isFetching,
|
||||
])}
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classnames(
|
||||
["onboarding-check"],
|
||||
["onboarding-check--valid", codex.enabled]
|
||||
)}>
|
||||
<CodexIcon
|
||||
className={classnames(
|
||||
["onboarding-check-icon--valid", codex.enabled],
|
||||
["onboarding-check-icon--invalid", !codex.enabled]
|
||||
)}
|
||||
/>
|
||||
<div className="onboarding-check-line">
|
||||
<div>
|
||||
<p>Codex connection</p>
|
||||
<SimpleText variant="light">
|
||||
Status indicator for the Codex network.
|
||||
</SimpleText>
|
||||
</div>
|
||||
{!codex.enabled && (
|
||||
<a
|
||||
className="onboarding-check-refresh"
|
||||
onClick={() => codex.refetch()}>
|
||||
<RefreshCcw
|
||||
size={"1.25rem"}
|
||||
className={classnames([
|
||||
"onboarding-check-refresh--fetching",
|
||||
codex.isFetching,
|
||||
])}
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
27
src/components/OnBoarding/OnBoardingStepTwo.tsx
Normal file
27
src/components/OnBoarding/OnBoardingStepTwo.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { Input } from "@codex-storage/marketplace-ui-components";
|
||||
import { ChangeEvent, useState } from "react";
|
||||
|
||||
type Props = {
|
||||
onStepValid: (valid: boolean) => void;
|
||||
};
|
||||
|
||||
export function OnBoardingStepTwo({ onStepValid }: Props) {
|
||||
const [displayName, setDisplayName] = useState("");
|
||||
|
||||
const onDisplayNameChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setDisplayName(e.currentTarget.value);
|
||||
onStepValid(!!e.currentTarget.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="index-column-section">
|
||||
<Input
|
||||
onChange={onDisplayNameChange}
|
||||
label="Display name"
|
||||
id="displayName"
|
||||
value={displayName}></Input>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
33
src/hooks/useCodexConnection.tsx
Normal file
33
src/hooks/useCodexConnection.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { CodexSdk } from "../sdk/codex";
|
||||
import { Promises } from "../utils/promises";
|
||||
|
||||
const report = false;
|
||||
|
||||
export function useCodexConnection() {
|
||||
const { data, isError, isFetching, refetch } = useQuery({
|
||||
queryKey: ["spr"],
|
||||
queryFn: async () => {
|
||||
return CodexSdk.node()
|
||||
.spr()
|
||||
.then((data) => Promises.rejectOnError(data, report));
|
||||
},
|
||||
refetchInterval: 5000,
|
||||
|
||||
// No need to retry because we defined a refetch interval
|
||||
retry: false,
|
||||
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
// Refreshing when focus returns can be useful if a user comes back
|
||||
// to the UI after performing an operation in the terminal.
|
||||
refetchOnWindowFocus: true,
|
||||
|
||||
// Cache is not useful for the spr endpoint
|
||||
gcTime: 0,
|
||||
});
|
||||
|
||||
return { enabled: !isError && !!data, isFetching, refetch };
|
||||
}
|
31
src/hooks/usePortForwarding.tsx
Normal file
31
src/hooks/usePortForwarding.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Errors } from "../utils/errors";
|
||||
|
||||
type PortForwardingResponse = { reachable: boolean };
|
||||
|
||||
export function usePortForwarding(online: boolean) {
|
||||
const { data, isFetching, refetch } = useQuery({
|
||||
queryFn: (): Promise<PortForwardingResponse> =>
|
||||
fetch(import.meta.env.VITE_ECHO_URL + "/port/8070")
|
||||
.then((res) => res.json())
|
||||
.catch((e) => Errors.report(e)),
|
||||
queryKey: ["port-forwarding"],
|
||||
|
||||
initialData: { reachable: false },
|
||||
|
||||
// Enable only when the use has an internet connection
|
||||
enabled: !!online,
|
||||
|
||||
// No need to retry because we provide a retry button
|
||||
retry: false,
|
||||
|
||||
// The data should not be cached
|
||||
staleTime: 0,
|
||||
|
||||
// The user may try to change the port forwarding and go back
|
||||
// to the tab
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
|
||||
return { enabled: data.reachable, isFetching, refetch };
|
||||
}
|
@ -52,7 +52,22 @@
|
||||
font-size: var(--codex-font-size);
|
||||
color-scheme: dark;
|
||||
color: var(--codex-color);
|
||||
background: linear-gradient(246.02deg, #000000 30.36%, #222222 91.05%);
|
||||
background: #000000; /* Fallback color */
|
||||
background: -webkit-linear-gradient(
|
||||
246.02deg,
|
||||
#000000 30.36%,
|
||||
#222222 91.05%
|
||||
); /* For Safari and older Chrome */
|
||||
background: -moz-linear-gradient(
|
||||
246.02deg,
|
||||
#000000 30.36%,
|
||||
#222222 91.05%
|
||||
); /* For older Firefox */
|
||||
background: linear-gradient(
|
||||
246.02deg,
|
||||
#000000 30.36%,
|
||||
#222222 91.05%
|
||||
); /* Standard syntax */
|
||||
}
|
||||
|
||||
::selection {
|
||||
@ -140,6 +155,12 @@ pre {
|
||||
a {
|
||||
text-decoration: inherit;
|
||||
color: var(--codex-color);
|
||||
transition: opacity 0.35s;
|
||||
}
|
||||
|
||||
a[aria-disabled] {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.root {
|
||||
|
@ -77,7 +77,7 @@
|
||||
filter: brightness(1);
|
||||
-webkit-filter: brightness(1);
|
||||
}
|
||||
50% {
|
||||
30% {
|
||||
filter: brightness(0.7);
|
||||
-webkit-filter: brightness(0.7);
|
||||
}
|
||||
@ -167,7 +167,6 @@
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
transition: opacity 0.35s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.index-dot:not(.index-dot--active) {
|
||||
@ -175,10 +174,24 @@
|
||||
}
|
||||
|
||||
.index-dot:hover {
|
||||
opacity: 0.8;
|
||||
animation-name: pulse;
|
||||
animation-duration: 2.5s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.index-dot--active {
|
||||
box-shadow: 0px 0px 13px 2px #fff;
|
||||
box-shadow: 0px 0px 12px 0px #fff;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
opacity: 0.4;
|
||||
}
|
||||
30% {
|
||||
opacity: 0.8;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import "./index.css";
|
||||
import { AlphaIcon } from "../components/AlphaIcon/AlphaIcon";
|
||||
import { AlphaText } from "../components/AlphaText/AlphaText";
|
||||
import { SimpleText } from "@codex-storage/marketplace-ui-components";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import { CodexLogo } from "../components/CodexLogo/CodexLogo";
|
||||
import { ArrowRightCircle } from "../components/ArrowRightCircle/ArrowRightCircle";
|
||||
import { useNetwork } from "../network/useNetwork";
|
||||
import { NetworkIcon } from "../components/NetworkIcon/NetworkIcon";
|
||||
import { Logotype } from "../components/Logotype/Logotype";
|
||||
import { useState } from "react";
|
||||
import { OnBoardingStepOne } from "../components/OnBoarding/OnBoardingStepOne";
|
||||
import { OnBoardingStepTwo } from "../components/OnBoarding/OnBoardingStepTwo";
|
||||
import { classnames } from "../utils/classnames";
|
||||
import { OnBoardingStepThree } from "../components/OnBoarding/OnBoardingStepThree";
|
||||
import { attributes } from "../utils/attributes";
|
||||
import { CodexLogo } from "../components/CodexLogo/CodexLogo";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: Index,
|
||||
@ -20,7 +22,31 @@ export const Route = createFileRoute("/")({
|
||||
});
|
||||
|
||||
function Index() {
|
||||
const [isStepValid, setIsStepValid] = useState(true);
|
||||
const [step, setStep] = useState(0);
|
||||
const online = useNetwork();
|
||||
const navigate = useNavigate({ from: "/" });
|
||||
const onStepValid = (valid: boolean) => setIsStepValid(valid);
|
||||
|
||||
const onNextStep = () => {
|
||||
if (!isStepValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (step === 2) {
|
||||
navigate({ to: "/dashboard" });
|
||||
return;
|
||||
}
|
||||
|
||||
setStep(step + 1);
|
||||
setIsStepValid(false);
|
||||
};
|
||||
|
||||
const components = [
|
||||
<OnBoardingStepOne onNextStep={onNextStep} />,
|
||||
<OnBoardingStepTwo onStepValid={onStepValid} />,
|
||||
<OnBoardingStepThree online={online} onStepValid={onStepValid} />,
|
||||
];
|
||||
|
||||
const text = online ? "Network connected" : "Network disconnected";
|
||||
|
||||
@ -32,51 +58,25 @@ function Index() {
|
||||
<Logotype />
|
||||
</div>
|
||||
|
||||
<div className="index-column-section">
|
||||
<div>
|
||||
<AlphaIcon />
|
||||
</div>
|
||||
<div className="index-alphaText">
|
||||
<p>
|
||||
<AlphaText></AlphaText>
|
||||
</p>
|
||||
<p>
|
||||
<SimpleText className="index-version" variant="normal">
|
||||
{import.meta.env.PACKAGE_VERSION}
|
||||
</SimpleText>
|
||||
</p>
|
||||
<p>
|
||||
<SimpleText className="index-disclaimer" variant="error">
|
||||
<a className="index-link">Legal Disclaimer</a>
|
||||
</SimpleText>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="index-column-section">
|
||||
<h3 className="index-mainTitle">
|
||||
Hello,
|
||||
<br /> Welcome to <span className="index-codex">Codex</span>{" "}
|
||||
<span className="index-vault">Vault</span>
|
||||
</h3>
|
||||
<p className="index-description">
|
||||
<SimpleText variant="light">
|
||||
Codex is a durable, decentralised data storage protocol, created
|
||||
so the world community can preserve its most important knowledge
|
||||
without risk of censorship.
|
||||
</SimpleText>
|
||||
</p>
|
||||
</div>
|
||||
<div className="index-column-section ">
|
||||
<SimpleText variant="primary">
|
||||
<a href="/dashboard" className="index-link index-getStarted">
|
||||
Let’s get started <ArrowRight></ArrowRight>
|
||||
</a>
|
||||
</SimpleText>
|
||||
{components[step]}
|
||||
|
||||
<div className=" ">
|
||||
<div className="index-dots">
|
||||
<span className="index-dot index-dot--active"></span>
|
||||
<span className="index-dot"></span>
|
||||
<span className="index-dot"></span>
|
||||
<span
|
||||
className={classnames(
|
||||
["index-dot"],
|
||||
["index-dot--active", step === 0]
|
||||
)}></span>
|
||||
<span
|
||||
className={classnames(
|
||||
["index-dot"],
|
||||
["index-dot--active", step === 1]
|
||||
)}></span>
|
||||
<span
|
||||
className={classnames(
|
||||
["index-dot"],
|
||||
["index-dot--active", step === 2]
|
||||
)}></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -88,7 +88,10 @@ function Index() {
|
||||
</div>
|
||||
<CodexLogo></CodexLogo>
|
||||
</div>
|
||||
<a href="/dashboard" className="index-link2">
|
||||
<a
|
||||
className="index-link2"
|
||||
{...attributes({ "aria-disabled": !isStepValid })}
|
||||
onClick={onNextStep}>
|
||||
<ArrowRightCircle></ArrowRightCircle>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -1,23 +1,6 @@
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { isCodexOnline } from "../components/NodeIndicator/NodeIndicator";
|
||||
import { CodexError } from "@codex-storage/sdk-js";
|
||||
|
||||
// It would be preferable to completely ignore the error
|
||||
// when the node is not connected. However, during the
|
||||
// initial load, we lack this information until the
|
||||
// SPR response is completed. In the meantime, other
|
||||
// requests may be initiated, so if the node is not
|
||||
// connected, we should set the level to 'log'.
|
||||
const getLogLevel = () => {
|
||||
switch (isCodexOnline) {
|
||||
case true:
|
||||
return "error";
|
||||
case null:
|
||||
return "info";
|
||||
case false:
|
||||
return "log";
|
||||
}
|
||||
};
|
||||
|
||||
export const Errors = {
|
||||
report(safe: { error: true, data: CodexError }) {
|
||||
@ -26,7 +9,6 @@ export const Errors = {
|
||||
code: safe.data.code,
|
||||
errors: safe.data.errors,
|
||||
sourceStack: safe.data.sourceStack,
|
||||
level: getLogLevel(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
1
src/vite-env.d.ts
vendored
1
src/vite-env.d.ts
vendored
@ -2,6 +2,7 @@
|
||||
|
||||
interface ImportMetaEnv {
|
||||
VITE_CODEX_API_URL: string;
|
||||
VITE_ECHO_URL: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
Loading…
x
Reference in New Issue
Block a user