diff --git a/src/components/Availability/AvailabilityCreate.tsx b/src/components/Availability/AvailabilityCreate.tsx index 47e69d4..baaae45 100644 --- a/src/components/Availability/AvailabilityCreate.tsx +++ b/src/components/Availability/AvailabilityCreate.tsx @@ -67,6 +67,11 @@ export function AvailabilityCreate({ space }: Props) { if (step === components.length) { setAvailability(defaultAvailabilityData); + dispatch({ + step: 0, + type: "next", + }); + dispatch({ type: "close", }); diff --git a/src/components/StorageRequestSetup/StorageRequestDone.tsx b/src/components/StorageRequestSetup/StorageRequestDone.tsx index e52e66b..caa028d 100644 --- a/src/components/StorageRequestSetup/StorageRequestDone.tsx +++ b/src/components/StorageRequestSetup/StorageRequestDone.tsx @@ -1,16 +1,22 @@ import { Placeholder } from "@codex-storage/marketplace-ui-components"; import { CircleCheck } from "lucide-react"; -import { useEffect } from "react"; import "./StorageRequestDone.css"; +import { StorageRequestComponentProps } from "./types"; +import { useEffect } from "react"; -type Props = { - onChangeNextState: (value: "enable" | "disable") => void; -}; - -export function StorageRequestDone({ onChangeNextState }: Props) { +// TODO rename +export function StorageRequestDone({ dispatch }: StorageRequestComponentProps) { useEffect(() => { - onChangeNextState("enable"); - }, [onChangeNextState]); + dispatch({ + type: "toggle-next", + isNextEnable: true, + }); + + dispatch({ + type: "toggle-back", + isBackEnable: false, + }); + }, [dispatch]); return ( { + dispatch({ + type: "toggle-next", + isNextEnable: false, + }); + + dispatch({ + type: "toggle-back", + isBackEnable: true, + }); + }, [dispatch]); + + return ( + + ); +} diff --git a/src/components/StorageRequestSetup/StorageRequestFileChooser.tsx b/src/components/StorageRequestSetup/StorageRequestFileChooser.tsx index 1d749c3..a0b5470 100644 --- a/src/components/StorageRequestSetup/StorageRequestFileChooser.tsx +++ b/src/components/StorageRequestSetup/StorageRequestFileChooser.tsx @@ -1,6 +1,6 @@ import { CodexSdk } from "../../sdk/codex"; import "./StorageRequestFileChooser.css"; -import { ChangeEvent, useEffect, useRef, useState } from "react"; +import { ChangeEvent, useEffect } from "react"; import { WebStorage } from "../../utils/web-storage"; import { classnames } from "../../utils/classnames"; import { @@ -10,57 +10,47 @@ import { WebFileIcon, } from "@codex-storage/marketplace-ui-components"; import { useData } from "../../hooks/useData"; +import { StorageRequestComponentProps } from "./types"; -type Props = { - onChangeNextState: (value: "enable" | "disable") => void; -}; - -export function StorageRequestFileChooser({ onChangeNextState }: Props) { +export function StorageRequestFileChooser({ + storageRequest, + dispatch, + onStorageRequestChange, +}: StorageRequestComponentProps) { const files = useData(); - const [cid, setCid] = useState(""); - const cache = useRef(""); useEffect(() => { - WebStorage.get("storage-request-step-1").then((val) => { - cache.current = val || ""; - - setCid(val || ""); - onChangeNextState(!val ? "disable" : "enable"); + dispatch({ + type: "toggle-next", + isNextEnable: !!storageRequest.cid, }); - return () => { - WebStorage.set("storage-request-step-1", cache.current || ""); - }; - }, [onChangeNextState]); + dispatch({ + type: "toggle-back", + isBackEnable: true, + }); + }, [dispatch, storageRequest]); const onSelected = (o: DropdownOption) => { - setCid(o.subtitle || ""); - onChangeNextState(!o.subtitle ? "disable" : "enable"); - cache.current = o.subtitle || ""; + onStorageRequestChange({ cid: o.subtitle }); }; const onChange = (e: ChangeEvent) => { - setCid(e.currentTarget.value); - onChangeNextState(!e.currentTarget.value ? "disable" : "enable"); - cache.current = e.currentTarget.value; + const value = e.currentTarget.value; + onStorageRequestChange({ cid: value }); }; const onSuccess = (data: string, file: File) => { + // TODO Move this to proxy object WebStorage.set(data, { type: file.type, name: file.name, }); - onChangeNextState("enable"); - - setCid(data); - cache.current = data; + onStorageRequestChange({ cid: data }); }; - const onDelete = () => { - setCid(""); - onChangeNextState("disable"); - }; + const onDelete = () => onStorageRequestChange({ cid: "" }); const options = files.map((f) => { @@ -84,12 +74,12 @@ export function StorageRequestFileChooser({ onChangeNextState }: Props) { id="cid" placeholder="Select or type your CID" onChange={onChange} - value={cid} + value={storageRequest.cid} options={options} onSelected={onSelected} className={classnames( ["storageRequestFileChooser-dropdown"], - ["storageRequestFileChooser-dropdown-success", !!cid] + ["storageRequestFileChooser-dropdown-success", !!storageRequest.cid] )} /> diff --git a/src/components/StorageRequestSetup/StorageRequestReview.css b/src/components/StorageRequestSetup/StorageRequestReview.css index bca067c..20cb376 100644 --- a/src/components/StorageRequestSetup/StorageRequestReview.css +++ b/src/components/StorageRequestSetup/StorageRequestReview.css @@ -38,7 +38,7 @@ border-radius: var(--codex-border-radius); background-color: rgb(56 56 56); align-items: center; - padding: 1rem 2rem; + padding: 1rem; align-items: center; justify-content: center; text-align: center; diff --git a/src/components/StorageRequestSetup/StorageRequestReview.tsx b/src/components/StorageRequestSetup/StorageRequestReview.tsx index d6b921c..0387a79 100644 --- a/src/components/StorageRequestSetup/StorageRequestReview.tsx +++ b/src/components/StorageRequestSetup/StorageRequestReview.tsx @@ -1,15 +1,14 @@ -import { useEffect, useState } from "react"; -import { WebStorage } from "../../utils/web-storage"; +import { useCallback, useEffect, useState } from "react"; import "./StorageRequestReview.css"; import { Alert } from "@codex-storage/marketplace-ui-components"; import { CardNumbers } from "../CardNumbers/CardNumbers"; import { FileWarning } from "lucide-react"; import { classnames } from "../../utils/classnames"; -import { AvailabilityUnit, StorageRequestCriteria } from "./types"; - -type Props = { - onChangeNextState: (value: "enable" | "disable") => void; -}; +import { + AvailabilityUnit, + StorageRequest, + StorageRequestComponentProps, +} from "./types"; type Durability = { nodes: number; @@ -35,84 +34,63 @@ const findDurabilityIndex = (d: Durability) => { const units = ["days", "minutes", "hours", "days", "months", "years"]; -export function StorageRequestReview({ onChangeNextState }: Props) { - const [cid, setCid] = useState(""); +export function StorageRequestReview({ + dispatch, + onStorageRequestChange, + storageRequest, +}: StorageRequestComponentProps) { const [durability, setDurability] = useState(1); - const [data, setData] = useState({ - availabilityUnit: "days", - availability: 1, - tolerance: 1, - proofProbability: 1, - nodes: 3, - reward: 10, - collateral: 10, - expiration: 300, - }); + + const isInvalidConstrainst = useCallback( + (nodes: number, tolerance: number) => { + const ecK = nodes - tolerance; + const ecM = tolerance; + + return ecK <= 1 || ecK < ecM; + }, + [] + ); useEffect(() => { - Promise.all([ - WebStorage.get("storage-request-criteria"), - WebStorage.get("storage-request-step-1"), - ]).then(([d, cid]) => { - if (d) { - setData(d); + const invalid = isInvalidConstrainst( + storageRequest.nodes, + storageRequest.tolerance + ); - const index = findDurabilityIndex({ - nodes: d.nodes, - tolerance: d.tolerance, - proofProbability: d.proofProbability, - }); - - setDurability(index + 1); - } else { - WebStorage.set("storage-request-criteria", { - availabilityUnit: "days", - availability: 1, - tolerance: 1, - proofProbability: 1, - nodes: 3, - reward: 10, - collateral: 10, - expiration: 300, - }); - } - - if (cid) { - setCid(cid); - } - - onChangeNextState("enable"); + dispatch({ + type: "toggle-next", + isNextEnable: !invalid, }); - }, [onChangeNextState]); - const updateData = (p: Partial) => { - setData((d) => { - const newData = { ...d, ...p }; - - WebStorage.set("storage-request-criteria", newData); - - return newData; + dispatch({ + type: "toggle-back", + isBackEnable: true, }); + }, [dispatch, storageRequest]); + + const onUpdateDurability = (data: Partial) => { + onStorageRequestChange(data); + + const index = findDurabilityIndex({ + nodes: storageRequest.nodes, + tolerance: storageRequest.tolerance, + proofProbability: storageRequest.proofProbability, + }); + + setDurability(index + 1); }; const onDurabilityChange = (d: number) => { const durability = durabilities[d - 1]; if (durability) { - updateData(durability); + onStorageRequestChange(durability); setDurability(d); } else { setDurability(0); } }; - const isInvalidConstrainst = (nodes: number, tolerance: number) => { - const ecK = nodes - tolerance; - const ecM = tolerance; - - return ecK <= 1 || ecK < ecM; - }; - const isInvalidNodes = (nodes: string) => { const error = isInvalidNumber(nodes); @@ -122,7 +100,7 @@ export function StorageRequestReview({ onChangeNextState }: Props) { const n = Number(nodes); - if (isInvalidConstrainst(n, data.tolerance)) { + if (isInvalidConstrainst(n, storageRequest.tolerance)) { return "The data does not match Codex contrainst"; } @@ -138,11 +116,11 @@ export function StorageRequestReview({ onChangeNextState }: Props) { const n = Number(tolerance); - if (n > data.nodes) { + if (n > storageRequest.nodes) { return "The tolerance cannot be greater than the nodes."; } - if (isInvalidConstrainst(data.nodes, n)) { + if (isInvalidConstrainst(storageRequest.nodes, n)) { return "The data does not match Codex contrainst."; } @@ -172,47 +150,14 @@ export function StorageRequestReview({ onChangeNextState }: Props) { const isInvalidNumber = (value: string) => isNaN(Number(value)) ? "The value is not a number" : ""; - const onNodesChange = (value: string) => { - const nodes = Number(value); + const onNodesChange = (value: string) => + onUpdateDurability({ nodes: Number(value) }); - updateData({ nodes }); + const onToleranceChange = (value: string) => + onUpdateDurability({ tolerance: Number(value) }); - const index = findDurabilityIndex({ - nodes: nodes, - tolerance: data.tolerance, - proofProbability: data.proofProbability, - }); - - setDurability(index + 1); - }; - - const onToleranceChange = (value: string) => { - const tolerance = Number(value); - - updateData({ tolerance }); - - const index = findDurabilityIndex({ - nodes: data.nodes, - tolerance: tolerance, - proofProbability: data.proofProbability, - }); - - setDurability(index + 1); - }; - - const onProofProbabilityChange = (value: string) => { - const proofProbability = Number(value); - - updateData({ proofProbability }); - - const index = findDurabilityIndex({ - nodes: data.nodes, - tolerance: data.tolerance, - proofProbability: proofProbability, - }); - - setDurability(index + 1); - }; + const onProofProbabilityChange = (value: string) => + onUpdateDurability({ proofProbability: Number(value) }); const onAvailabilityChange = (value: string) => { const [availability, availabilityUnit = "days"] = value.split(" "); @@ -221,29 +166,20 @@ export function StorageRequestReview({ onChangeNextState }: Props) { // availabilityUnit += "s"; // } - updateData({ + onStorageRequestChange({ availability: Number(availability), availabilityUnit: availabilityUnit as AvailabilityUnit, }); }; - const onRewardChange = (value: string) => { - const reward = Number(value); + const onRewardChange = (value: string) => + onStorageRequestChange({ reward: Number(value) }); - updateData({ reward }); - }; + const onExpirationChange = (value: string) => + onStorageRequestChange({ expiration: Number(value) }); - const onExpirationChange = (value: string) => { - const expiration = Number(value); - - updateData({ expiration }); - }; - - const onCollateralChange = (value: string) => { - const collateral = Number(value); - - updateData({ collateral }); - }; + const onCollateralChange = (value: string) => + onStorageRequestChange({ collateral: Number(value) }); // const pluralizeUnit = () => { // if (data.availability > 1 && !data.availabilityUnit.endsWith("s")) { @@ -257,7 +193,7 @@ export function StorageRequestReview({ onChangeNextState }: Props) { // return data.availabilityUnit; // }; - const availability = `${data.availability} ${data.availabilityUnit}`; + const availability = `${storageRequest.availability} ${storageRequest.availabilityUnit}`; return (
@@ -265,19 +201,19 @@ export function StorageRequestReview({ onChangeNextState }: Props) {
@@ -365,13 +301,13 @@ export function StorageRequestReview({ onChangeNextState }: Props) { helper="Full period of the contract"> @@ -393,7 +329,7 @@ export function StorageRequestReview({ onChangeNextState }: Props) {
- If no suitable hosts are found for the CID {cid} matching your storage - requirements, you will incur a charge a small amount of tokens. + If no suitable hosts are found for the CID {storageRequest.cid}{" "} + matching your storage requirements, you will incur a charge a small + amount of tokens.
diff --git a/src/components/StorageRequestSetup/StorageRequestSetup.css b/src/components/StorageRequestSetup/StorageRequestSetup.css index d09e908..a836b75 100644 --- a/src/components/StorageRequestSetup/StorageRequestSetup.css +++ b/src/components/StorageRequestSetup/StorageRequestSetup.css @@ -1,29 +1,3 @@ -.storageRequest { - background-color: var(--codex-background); - background-color: var(--codex-background); - border-radius: var(--codex-border-radius); - transition: transform 0.15s; - max-width: 800px; - overflow-y: auto; - overflow-x: hidden; - opacity: 0; - z-index: -1; - max-height: 100%; - left: 50%; - top: 50%; - transform: translate(-50%, -50%) scale(0); - position: fixed; -} - -.storageRequest-open { - transform: translate(-50%, -50%) scale(1); -} - -.storageRequest-open { - opacity: 1; - z-index: 10; -} - .storageRequest-title { margin-bottom: 0.5rem; font-weight: 600; diff --git a/src/components/StorageRequestSetup/StorageRequestStepper.css b/src/components/StorageRequestSetup/StorageRequestStepper.css new file mode 100644 index 0000000..64ac1c3 --- /dev/null +++ b/src/components/StorageRequestSetup/StorageRequestStepper.css @@ -0,0 +1,5 @@ +@media (min-width: 801px) { + .storageRequest-stepper { + min-width: 700px; + } +} diff --git a/src/components/StorageRequestSetup/StorageRequestStepper.tsx b/src/components/StorageRequestSetup/StorageRequestStepper.tsx index fa8c0eb..1388744 100644 --- a/src/components/StorageRequestSetup/StorageRequestStepper.tsx +++ b/src/components/StorageRequestSetup/StorageRequestStepper.tsx @@ -1,202 +1,153 @@ import { StorageRequestFileChooser } from "../../components/StorageRequestSetup/StorageRequestFileChooser"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { WebStorage } from "../../utils/web-storage"; import { STEPPER_DURATION } from "../../utils/constants"; import { StorageRequestReview } from "./StorageRequestReview"; -import { CodexCreateStorageRequestInput } from "@codex-storage/sdk-js"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { CodexSdk } from "../../sdk/codex"; -import { StorageAvailabilityUnit, StorageRequestCriteria } from "./types"; +import { StorageRequest } from "./types"; import { - Backdrop, + Button, + Modal, Stepper, - Toast, + useStepperReducer, } from "@codex-storage/marketplace-ui-components"; -import { classnames } from "../../utils/classnames"; import { StorageRequestDone } from "./StorageRequestDone"; -import { PurchaseStorage } from "../../utils/purchases-storage"; -import { Promises } from "../../utils/promises"; -import * as Sentry from "@sentry/browser"; +import { Times } from "../../utils/times"; +import { useStorageRequestMutation } from "./useStorageRequestMutation"; +import { ErrorPlaceholder } from "../ErrorPlaceholder/ErrorPlaceholder"; +import { Plus } from "lucide-react"; +import "./StorageRequestStepper.css"; +import { StorageRequestError } from "./StorageRequestError"; -function calculateAvailability(value: number, unit: StorageAvailabilityUnit) { - switch (unit) { - case "minutes": - return 60 * value; - case "hours": - return 60 * 60 * value; - case "days": - return 24 * 60 * 60 * value; - case "months": - return 30 * 24 * 60 * 60 * value; - case "years": - return 365 * 24 * 60 * 60 * value; - } -} +type Props = {}; -type Props = { - open: boolean; - onClose: () => void; - className?: string; +const CONFIRM_STATE = 2; +const STEPS = 3; + +const defaultStorageRequest: StorageRequest = { + cid: "", + availabilityUnit: "days", + availability: 1, + tolerance: 1, + proofProbability: 1, + nodes: 3, + reward: 10, + collateral: 10, + expiration: 300, }; -const UPLOAD_STEP = 0; -const SUCCESS_STEP = 2; - -export function StorageRequestStepper({ className, open, onClose }: Props) { - const [progress, setProgress] = useState(true); - const [step, setStep] = useState(0); +export function StorageRequestStepper({}: Props) { + const [storageRequest, setStorageRequest] = useState( + defaultStorageRequest + ); const steps = useRef(["File", "Criteria", "Success"]); - const [isNextDisable, setIsNextDisable] = useState(true); - const queryClient = useQueryClient(); - const [toast, setToast] = useState({ - time: 0, - message: "", - }); - - const { mutateAsync } = useMutation({ - mutationKey: ["debug"], - mutationFn: (input: CodexCreateStorageRequestInput) => - CodexSdk.marketplace - .createStorageRequest(input) - .then((s) => Promises.rejectOnError(s)), - onSuccess: async (requestId, { cid }) => { - queryClient.invalidateQueries({ queryKey: ["purchases"] }); - - if (!requestId.startsWith("0x")) { - requestId = "0x" + requestId; - } - - PurchaseStorage.set(requestId, cid); - WebStorage.set("storage-request-step", SUCCESS_STEP); - - setProgress(false); - setStep(SUCCESS_STEP); - }, - onError: (error) => { - if (import.meta.env.PROD) { - Sentry.captureException(error); - } - - setProgress(false); - setToast({ - message: "Error when trying to update: " + error.message, - time: Date.now(), - }); - }, - }); + const { state, dispatch } = useStepperReducer(); + const { mutateAsync, error } = useStorageRequestMutation(dispatch, state); useEffect(() => { - WebStorage.get("storage-request-step").then((value) => { - setStep(value || 0); + Promise.all([ + WebStorage.get("storage-request-step"), + WebStorage.get("storage-request"), + ]).then(([s, data]) => { + if (s) { + dispatch({ + type: "next", + step: s, + }); + } - setTimeout(() => { - setProgress(false); - }, STEPPER_DURATION); + if (data) { + setStorageRequest(data); + } }); - }, []); - - const onChangeNextState = useCallback( - (s: "enable" | "disable") => setIsNextDisable(s === "disable"), - [] - ); + }, [dispatch]); const components = [ StorageRequestFileChooser, StorageRequestReview, - StorageRequestDone, + error ? StorageRequestError : StorageRequestDone, ]; - const onChangeStep = async (nextStep: number, state: "before" | "end") => { - if (nextStep < UPLOAD_STEP) { - setStep(0); - setIsNextDisable(true); - setProgress(false); - onClose(); - return; - } + const onNextStep = async (step: number) => { + if (step === components.length) { + setStorageRequest(defaultStorageRequest); - if (state === "before") { - setIsNextDisable(true); - setProgress(true); - setStep(nextStep); - return; - } - - if (nextStep > SUCCESS_STEP) { - WebStorage.delete("storage-request-step"); - WebStorage.delete("storage-request-criteria"); - - setIsNextDisable(true); - setProgress(false); - setStep(0); - - onClose(); - - return; - } - - if (nextStep == SUCCESS_STEP) { - const [cid, criteria] = await Promise.all([ - WebStorage.get("storage-request-step-1"), - WebStorage.get("storage-request-criteria"), - ]); - - if (!cid || !criteria) { - return; - } - - const { - availabilityUnit = "days", - availability, - reward, - collateral, - expiration, - nodes, - proofProbability, - tolerance, - } = criteria; - - mutateAsync({ - cid, - collateral, - duration: calculateAvailability(availability, availabilityUnit), - expiry: expiration * 60, - nodes, - proofProbability, - tolerance, - reward, + dispatch({ + step: 0, + type: "next", }); - // TODO When the thread bug will be fixed, - // move to the next step without waiting the end of the request - // and add a line into the table - } else { - WebStorage.set("storage-request-step", nextStep); - setProgress(false); + dispatch({ + type: "close", + }); + + return; + } + + WebStorage.set("storage-request-step", step); + + if (step == CONFIRM_STATE) { + const { availabilityUnit, availability, expiration, ...rest } = + storageRequest; + mutateAsync({ + ...rest, + duration: Times.toSeconds(availability, availabilityUnit), + expiry: expiration * 60, + }); + } else { + dispatch({ + step, + type: "next", + }); } }; - const Body = progress ? () => : components[step] || components[0]; + const onStorageRequestChange = (data: Partial) => { + const val = { ...storageRequest, ...data }; + + WebStorage.set("storage-request", val); + + setStorageRequest(val); + }; + + const onOpen = () => + dispatch({ + type: "open", + }); + + const onClose = () => dispatch({ type: "close" }); + + const Body = components[state.step] || (() => ); + const backLabel = state.step ? "Back" : "Close"; + const nextLabel = state.step === steps.current.length - 1 ? "Finish" : "Next"; return ( <> - -
+
- - + state={state} + dispatch={dispatch} + duration={STEPPER_DURATION} + onNextStep={onNextStep} + backLabel={backLabel} + className="storageRequest-stepper" + nextLabel={nextLabel}> + + + ); } diff --git a/src/components/StorageRequestSetup/types.ts b/src/components/StorageRequestSetup/types.ts index de4e9d8..5a64ff3 100644 --- a/src/components/StorageRequestSetup/types.ts +++ b/src/components/StorageRequestSetup/types.ts @@ -1,3 +1,9 @@ +import { + StepperAction, + StepperState, +} from "@codex-storage/marketplace-ui-components"; +import { Dispatch } from "react"; + export type StorageDurabilityStepValue = { tolerance: number; proofProbability: number; @@ -29,7 +35,8 @@ export type AvailabilityUnit = | "minutes" | "hours"; -export type StorageRequestCriteria = { +export type StorageRequest = { + cid: string; availability: number; availabilityUnit: AvailabilityUnit; tolerance: number; @@ -39,3 +46,11 @@ export type StorageRequestCriteria = { collateral: number; expiration: number; }; + +export type StorageRequestComponentProps = { + dispatch: Dispatch; + state: StepperState; + onStorageRequestChange: (data: Partial) => void; + storageRequest: StorageRequest; + error: Error | null; +}; diff --git a/src/components/StorageRequestSetup/useStorageRequestMutation.ts b/src/components/StorageRequestSetup/useStorageRequestMutation.ts new file mode 100644 index 0000000..f6dc2a6 --- /dev/null +++ b/src/components/StorageRequestSetup/useStorageRequestMutation.ts @@ -0,0 +1,61 @@ +import { CodexCreateStorageRequestInput } from "@codex-storage/sdk-js"; +import { CodexSdk } from "../../sdk/codex"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { Promises } from "../../utils/promises"; +import { PurchaseStorage } from "../../utils/purchases-storage"; +import { WebStorage } from "../../utils/web-storage"; +import { + StepperAction, + StepperState, +} from "@codex-storage/marketplace-ui-components"; +import { Dispatch, useState } from "react"; +import * as Sentry from "@sentry/browser"; + +export function useStorageRequestMutation( + dispatch: Dispatch, + state: StepperState +) { + const queryClient = useQueryClient(); + const [error, setError] = useState(null); + + const { mutateAsync } = useMutation({ + mutationKey: ["debug"], + mutationFn: (input: CodexCreateStorageRequestInput) => + CodexSdk.marketplace + .createStorageRequest(input) + .then((s) => Promises.rejectOnError(s)), + onSuccess: async () => { + queryClient.invalidateQueries({ queryKey: ["purchases"] }); + + // if (!requestId.startsWith("0x")) { + // requestId = "0x" + requestId; + // } + + WebStorage.delete("storage-request-step"); + WebStorage.delete("storage-request"); + + // PurchaseStorage.set(requestId, cid); + // WebStorage.set("storage-request-step", SUCCESS_STEP); + dispatch({ + type: "next", + step: state.step, + }); + }, + onError: (error) => { + if (import.meta.env.PROD) { + Sentry.captureException(error); + } + + setError(error); + + WebStorage.set("storage-request-step", state.step - 1); + + dispatch({ + type: "next", + step: state.step, + }); + }, + }); + + return { mutateAsync, error }; +} diff --git a/src/routes/dashboard/purchases.tsx b/src/routes/dashboard/purchases.tsx index 8e2d28a..7e70a5a 100644 --- a/src/routes/dashboard/purchases.tsx +++ b/src/routes/dashboard/purchases.tsx @@ -1,17 +1,9 @@ import { useQuery } from "@tanstack/react-query"; import { createFileRoute } from "@tanstack/react-router"; import { CodexSdk } from "../../sdk/codex"; -import { Plus } from "lucide-react"; -import { useState } from "react"; -import { - Button, - Cell, - Spinner, - Table, -} from "@codex-storage/marketplace-ui-components"; +import { Cell, Spinner, Table } from "@codex-storage/marketplace-ui-components"; import { StorageRequestStepper } from "../../components/StorageRequestSetup/StorageRequestStepper"; import "./purchases.css"; -import { classnames } from "../../utils/classnames"; import { FileCell } from "../../components/FileCellRender/FileCell"; import { CustomStateCellRender } from "../../components/CustomStateCellRender/CustomStateCellRender"; import prettyMilliseconds from "pretty-ms"; @@ -20,7 +12,6 @@ import { Promises } from "../../utils/promises"; import { TruncateCell } from "../../components/TruncateCell/TruncateCell"; const Purchases = () => { - const [open, setOpen] = useState(false); const { data, isPending } = useQuery({ queryFn: () => CodexSdk.marketplace.purchases().then((s) => Promises.rejectOnError(s)), @@ -67,38 +58,21 @@ const Purchases = () => { ]; }) || []; + // TODO make name uniforms + return (
-
- setOpen(false)} - /> - - - {/* {!cells.length && ( - - )} */} ); }; +// TODO make uniforms for availabilities + export const Route = createFileRoute("/dashboard/purchases")({ component: () => (