diff --git a/src/components/Availability/AvailabilityCreate.tsx b/src/components/Availability/AvailabilityCreate.tsx index bf5ae41..ca0f87b 100644 --- a/src/components/Availability/AvailabilityCreate.tsx +++ b/src/components/Availability/AvailabilityCreate.tsx @@ -1,6 +1,5 @@ import { Stepper, - Toast, useStepperReducer, Button, Modal, @@ -14,18 +13,18 @@ import { WebStorage } from "../../utils/web-storage"; import { UIAvailability } from "./types"; import { STEPPER_DURATION } from "../../utils/constants"; import { useAvailabilityMutation } from "./useAvailabilityMutation"; -import { AvailabilityDone } from "./AvailabilityDone"; +import { AvailabilitySuccess } from "./AvailabilitySuccess"; +import { AvailabilityError } from "./AvailabilityError"; type Props = { space: CodexNodeSpace; }; const CONFIRM_STATE = 2; +const STEPS = 3; export function AvailabilityCreate({ space }: Props) { - const components = [AvailabilityForm, AvailabilityConfirm, AvailabilityDone]; const steps = useRef(["Availability", "Confirmation", "Success"]); - const { state, dispatch } = useStepperReducer(components.length); const [availability, setAvailability] = useState({ totalSize: 1, duration: 1, @@ -34,6 +33,13 @@ export function AvailabilityCreate({ space }: Props) { totalSizeUnit: "gb", durationUnit: "days", }); + const { state, dispatch } = useStepperReducer(STEPS); + const { mutateAsync, error } = useAvailabilityMutation(dispatch, state); + const components = [ + AvailabilityForm, + AvailabilityConfirm, + error ? () => : AvailabilitySuccess, + ]; useEffect(() => { Promise.all([ @@ -58,8 +64,6 @@ export function AvailabilityCreate({ space }: Props) { }); }, [dispatch]); - const { mutateAsync, toast } = useAvailabilityMutation(dispatch, state); - const onNextStep = async (step: number) => { WebStorage.set("availability-step", step); @@ -130,8 +134,6 @@ export function AvailabilityCreate({ space }: Props) { /> - - ); } diff --git a/src/components/Availability/AvailabilityDone.css b/src/components/Availability/AvailabilityDone.css deleted file mode 100644 index 3d4684d..0000000 --- a/src/components/Availability/AvailabilityDone.css +++ /dev/null @@ -1,7 +0,0 @@ -.availabilityDone { - margin: auto; -} - -.availabilityDone-icon { - color: var(--codex-color-primary); -} diff --git a/src/components/Availability/AvailabilityError.tsx b/src/components/Availability/AvailabilityError.tsx new file mode 100644 index 0000000..dd36185 --- /dev/null +++ b/src/components/Availability/AvailabilityError.tsx @@ -0,0 +1,16 @@ +import { Placeholder } from "@codex-storage/marketplace-ui-components"; +import { ErrorIcon } from "../ErrorIcon/ErrorIcon"; + +type Props = { + error: Error; +}; + +export function AvailabilityError({ error }: Props) { + return ( + } + title="Error" + subtitle={"Got an error when trying to create the availability."} + message={error.message}> + ); +} diff --git a/src/components/Availability/AvailabilityForm.tsx b/src/components/Availability/AvailabilityForm.tsx index 8cfcb87..673e5fb 100644 --- a/src/components/Availability/AvailabilityForm.tsx +++ b/src/components/Availability/AvailabilityForm.tsx @@ -33,7 +33,7 @@ export function AvailabilityForm({ const unit = availability.totalSizeUnit === "gb" ? GB : TB; return value * unit > space.quotaMaxBytes - space.quotaReservedBytes; }, - [space] + [space, availability] ); useEffect(() => { @@ -41,12 +41,13 @@ export function AvailabilityForm({ setTotalSizeError( "You cannot allocate more space than the remaining space." ); + } else { + setTotalSizeError(""); } - }, [availability]); + }, [availability, isAvailabilityInvalid]); const onTotalSizeUnitChange = async (e: ChangeEvent) => { const element = e.currentTarget; - const valid = element.value === "tb" || element.value === "gb"; dispatch({ type: "toggle-next", @@ -98,7 +99,6 @@ export function AvailabilityForm({ const onInputChange = async (e: ChangeEvent) => { const element = e.currentTarget; - const valid = element.checkValidity(); onAvailabilityChange({ [element.name]: parseFloat(element.value), diff --git a/src/components/Availability/AvailabilityDone.tsx b/src/components/Availability/AvailabilitySuccess.tsx similarity index 62% rename from src/components/Availability/AvailabilityDone.tsx rename to src/components/Availability/AvailabilitySuccess.tsx index 98c658b..70ed625 100644 --- a/src/components/Availability/AvailabilityDone.tsx +++ b/src/components/Availability/AvailabilitySuccess.tsx @@ -2,15 +2,14 @@ import { Placeholder, StepperAction, } from "@codex-storage/marketplace-ui-components"; -import { CircleCheck } from "lucide-react"; import { Dispatch, useEffect } from "react"; -import "./AvailabilityDone.css"; +import { SuccessIcon } from "../SuccessIcon/SuccessIcon"; type Props = { dispatch: Dispatch; }; -export function AvailabilityDone({ dispatch }: Props) { +export function AvailabilitySuccess({ dispatch }: Props) { useEffect(() => { dispatch({ isNextEnable: true, @@ -20,9 +19,8 @@ export function AvailabilityDone({ dispatch }: Props) { return ( } - className="availabilityDone" - title="Your availability is created." + Icon={} + title="Success" message="The new availability will appear in your availability list. You can safely close this dialog."> ); } diff --git a/src/components/Availability/useAvailabilityMutation.ts b/src/components/Availability/useAvailabilityMutation.ts index 8abcebf..1900e7e 100644 --- a/src/components/Availability/useAvailabilityMutation.ts +++ b/src/components/Availability/useAvailabilityMutation.ts @@ -1,5 +1,4 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { CodexSdk } from "../../proxy"; import { GB, TB } from "../../utils/constants"; import { Promises } from "../../utils/promises"; import { WebStorage } from "../../utils/web-storage"; @@ -12,16 +11,14 @@ import { import * as Sentry from "@sentry/browser"; import { SafeValue } from "@codex-storage/sdk-js/async"; import { Times } from "../../utils/times"; +import { CodexSdk } from "../../sdk/codex"; export function useAvailabilityMutation( dispatch: Dispatch, state: StepperState ) { const queryClient = useQueryClient(); - const [toast, setToast] = useState({ - time: 0, - message: "", - }); + const [error, setError] = useState(null); const { mutateAsync } = useMutation({ mutationKey: ["debug"], @@ -66,12 +63,15 @@ export function useAvailabilityMutation( Sentry.captureException(error); } - setToast({ - message: "Error when trying to update: " + error.message, - time: Date.now(), + setError(error); + + dispatch({ + type: "next", + step: state.step, + isBackEnable: true, }); }, }); - return { mutateAsync, toast }; + return { mutateAsync, error }; } diff --git a/src/components/ErrorIcon/ErrorIcon.tsx b/src/components/ErrorIcon/ErrorIcon.tsx new file mode 100644 index 0000000..8982be3 --- /dev/null +++ b/src/components/ErrorIcon/ErrorIcon.tsx @@ -0,0 +1,10 @@ +import { CircleX } from "lucide-react"; +import { SimpleText } from "@codex-storage/marketplace-ui-components"; + +export function ErrorIcon() { + return ( + + + + ); +} diff --git a/src/components/SuccessIcon/SuccessIcon.tsx b/src/components/SuccessIcon/SuccessIcon.tsx new file mode 100644 index 0000000..e53eab6 --- /dev/null +++ b/src/components/SuccessIcon/SuccessIcon.tsx @@ -0,0 +1,10 @@ +import { SimpleText } from "@codex-storage/marketplace-ui-components"; +import { CircleCheck } from "lucide-react"; + +export function SuccessIcon() { + return ( + + + + ); +}