diff --git a/public/shape-1.png b/public/shape-1.png new file mode 100644 index 0000000..288284f Binary files /dev/null and b/public/shape-1.png differ diff --git a/public/shape-2.png b/public/shape-2.png new file mode 100644 index 0000000..52a303b Binary files /dev/null and b/public/shape-2.png differ diff --git a/public/shape-3.png b/public/shape-3.png new file mode 100644 index 0000000..3cac334 Binary files /dev/null and b/public/shape-3.png differ diff --git a/public/shape-4.png b/public/shape-4.png new file mode 100644 index 0000000..89ec808 Binary files /dev/null and b/public/shape-4.png differ diff --git a/src/components/CardNumbers/CardNumbers.css b/src/components/CardNumbers/CardNumbers.css index a51730e..3230fde 100644 --- a/src/components/CardNumbers/CardNumbers.css +++ b/src/components/CardNumbers/CardNumbers.css @@ -8,11 +8,24 @@ flex-direction: column; } +.cardNumber-container { + display: flex; + flex-direction: column; +} + .cardNumber--error { border-color: rgb(var(--codex-color-error)); } -.cardNumber--error .cardNumber-tooltip { +.cardNumber-errorText, +.cardNumber-helperText { + height: 2rem; + display: inline-block; + margin-top: 0.25rem; + padding: 0 0.5rem; +} + +.cardNumber-errorText { color: rgb(var(--codex-color-error)); } @@ -64,6 +77,11 @@ .cardNumber .input { min-width: 0; - width: 100px; + width: 65px; height: 2.5rem; } + +.cardNumber .inputGroup-select { + height: 2.5rem; + padding: 0.25rem 1rem; +} diff --git a/src/components/CardNumbers/CardNumbers.tsx b/src/components/CardNumbers/CardNumbers.tsx index 05d69b4..13b9ab8 100644 --- a/src/components/CardNumbers/CardNumbers.tsx +++ b/src/components/CardNumbers/CardNumbers.tsx @@ -1,107 +1,178 @@ -import { ButtonIcon, Input, Tooltip } from "@codex-storage/marketplace-ui-components"; +import { + ButtonIcon, + SimpleText, +} from "@codex-storage/marketplace-ui-components"; import "./CardNumbers.css"; -import { Check, Info, Pencil, ShieldAlert } from "lucide-react"; -import { ChangeEvent, useEffect, useState } from "react"; +import { Check, CircleX, Pencil } from "lucide-react"; +import { ChangeEvent, useCallback, useEffect, useRef, useState } from "react"; import { classnames } from "../../utils/classnames"; type Props = { title: string; data: string; - comment?: string; - onChange?: (value: number) => void; - hasError?: boolean; + onChange: (value: string) => void; + onValidation?: (value: string) => string; + className?: string; + + /** + * If true, the caret will be set at the end of the input + * Default is true + */ + repositionCaret?: boolean; + + helper: string; }; export function CardNumbers({ title, data, - comment, - hasError = false, + onValidation, onChange, + helper, + className = "", + repositionCaret = true, }: Props) { - const [editing, setEditing] = useState(false); - const [value, setValue] = useState(data); + const [isDirty, setIsDirty] = useState(false); + const [error, setError] = useState(""); + const ref = useRef(null); + + const replaceCaret = useCallback( + (el: HTMLElement) => { + if (!repositionCaret) { + return; + } + + // Place the caret at the end of the element + const target = document.createTextNode(""); + el.appendChild(target); + // do not move caret if element was not focused + const isTargetFocused = document.activeElement === el; + if (target !== null && target.nodeValue !== null && isTargetFocused) { + const sel = window.getSelection(); + if (sel !== null) { + const range = document.createRange(); + range.setStart(target, target.nodeValue.length); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + } + if (el instanceof HTMLElement) el.focus(); + } + }, + [repositionCaret] + ); + + const updateText = useCallback( + (text: string | null) => { + const current = ref.current; + + if (current && text) { + current.textContent = text; + replaceCaret(current); + } + }, + [replaceCaret, ref] + ); useEffect(() => { - setValue(data); - }, [data]); + console.info("received update //", data); + updateText(data); + setIsDirty(false); + }, [data, updateText]); - const onEditingClick = () => setEditing(!editing); + const onEditingClick = () => { + const current = ref.current; - const onInputChange = (e: ChangeEvent) => { - setValue(e.currentTarget.value); + if (isDirty) { + onChange?.(current?.textContent || ""); + } else if (current) { + current.focus(); + replaceCaret(current); + } }; - const onButtonClick = () => { - setEditing(false); - onChange?.(parseInt(value, 10)); + const onInput = (e: ChangeEvent) => { + const text = e.currentTarget.textContent; + + setIsDirty(text !== data); + + if (!text) { + setError("A value is required"); + return; + } + + if (text?.length > 10) { + e.currentTarget.textContent = text.slice(0, 10); + replaceCaret(e.currentTarget); + setError("The value is too long"); + return; + } + + updateText(text); + + const msg = onValidation?.(text); + + if (msg) { + setError(msg); + return; + } + + setError(""); }; - if (editing) { - return ( + const onBlur = () => { + if (error === "") { + if (isDirty) { + onChange?.(ref.current?.textContent || ""); + } + } else { + updateText(data); + } + + setIsDirty(false); + setError(""); + }; + + const Icon = error + ? () => + : isDirty + ? () => + : () => ; + + return ( +
+ className={classnames(["cardNumber"], ["cardNumber--error", !!error])}>
- - + <> +

+ + +

{title} - {comment && ( - - {hasError ? ( - - ) : ( - - )} - - )}
- ); - } - - const DataContainer = editing ? ( - <> - - - - ) : ( - <> -

{data}

- }> - - ); - - return ( -
-
{DataContainer}
-
- {title} - {comment && ( - - {hasError ? : } - - )} -
+ {error ? ( + {error} + ) : ( + + {helper} + + )}
); } diff --git a/src/components/Range/Range.css b/src/components/Range/Range.css index d860eb6..d9e9919 100644 --- a/src/components/Range/Range.css +++ b/src/components/Range/Range.css @@ -1,11 +1,145 @@ .range { - width: 100%; + /* width: 100%; accent-color: var(--codex-color-primary); - height: 4px; - outline: none; + height: 1px; + outline: none; */ + --val: 50; + width: 100%; + margin: 1.5rem 0; } .range-labels { display: flex; justify-content: space-between; } + +@property --c { + syntax: ""; + inherits: true; + initial-value: #0000; +} + +.glow { + --c: rgb(0, 255, 255, calc(0.25 + var(--val) / 125)); + --c: hsl(160deg 80% 50% / calc(0.25 + var(--val) / 125)); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: transparent; + cursor: pointer; + position: relative; +} + +.glow::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: calc((var(--val) - 1) * 1%); + min-width: 0.5em; + height: 100%; + background: var(--c); + box-shadow: + 0 0 0.2em 0 hsl(0 0% 0%) inset, + -0.1em 0.1em 0.1em -0.1em hsl(0 0% 100% / 0.5), + 0 0 calc(1em + 0.001em * var(--val)) calc(0.1em + 0.00025em * var(--val)) + var(--c); + border-radius: 1em 0 0 1em; + aopacity: calc(20% + var(--val) * 1%); +} + +/***** Track Styles *****/ +/***** Chrome, Safari, Opera, and Edge Chromium *****/ +.glow::-webkit-slider-runnable-track { + box-shadow: + 0 0 0.2em 0 hsl(0 0% 0%) inset, + -0.1em 0.1em 0.1em -0.1em hsl(0 0% 100% / 0.5); + background: linear-gradient(to bottom right, #0001, #0000), #343133; + border-radius: 1em; + height: 1em; +} + +/******** Firefox ********/ +.glow::-moz-range-track { + box-shadow: + 0 0 2px 0 hsl(0 0% 0%) inset, + -1px 1px 1px -1px hsl(0 0% 100% / 0.5); + background: + linear-gradient(var(--c) 0 0) 0 0 / calc(var(--val) * 1%) 100% no-repeat, + linear-gradient(to bottom right, #0001, #0000), + #343133; + border-radius: 1em; + height: 1em; +} + +/***** Thumb Styles *****/ +/***** Chrome, Safari, Opera, and Edge Chromium *****/ +.glow::-webkit-slider-thumb { + --d: var(--c); + --d: rgb(from var(--c) r g b / calc(0.35 * var(--val) * 1%)); + -webkit-appearance: none; /* Override default look */ + appearance: none; + background-color: #5cd5eb; + transform: translateY(calc(-50% + 0.5em)); + width: 4em; + aspect-ratio: 1; + background: red; + border-radius: 50%; + background: + radial-gradient( + farthest-side, + #0000 22.5%, + var(--d) 0, + #0000 calc(var(--val) * 0.75%) + ) + 50% 50% / 100% 100% no-repeat, + radial-gradient(#0000 15%, #343133 16%, #545153 20%), + repeating-linear-gradient(#0000 0 10%, #0002 0 20%) 50% 50% / 25% 25% + no-repeat, + repeating-linear-gradient(90deg, #0000 0 10%, #0002 0 20%) 50% 50% / 25% 25% + no-repeat, + radial-gradient(var(--c) 17%, #0000 0), + #545153; + box-shadow: + inset -0.15em -0.15em 0.2em #0008, + inset 0.15em 0.15em 0.2em #ffffff22, + inset calc(var(--val) * 1em / 500) 0em calc(var(--val) * 1em / 500) + calc(var(--val) * -1em / 700) var(--c), + 0.25em 0.25em 0.5em #0006, + calc(0.0125em * var(--val)) calc(0.005em * var(--val)) + calc(0.02em * var(--val)) calc(-0.01em * var(--val)) #000a; + border-radius: 50%; +} + +/***** Firefox *****/ +.glow::-moz-range-thumb { + /* --d: var(--c); + --d: rgb(from var(--c) r g b / calc(0.35 * var(--val) * 1%)); */ + border: none; /*Removes extra border that FF applies*/ + -webkit-appearance: none; /* Override default look */ + appearance: none; + background-color: #5cd5eb; + width: 4em; + height: 4em; + aspect-ratio: 1; + background: red; + border-radius: 50%; + background: +/* radial-gradient(farthest-side, #0000 22.5%, var(--d) 0, #0000 calc(var(--val) * 0.75%)) 50% 50% / 100% 100% no-repeat, */ + radial-gradient(#0000 15%, #343133 16%, #545153 20%), + repeating-linear-gradient(#0000 0 10%, #0002 0 20%) 50% 50% / 25% 25% + no-repeat, + repeating-linear-gradient(90deg, #0000 0 10%, #0002 0 20%) 50% 50% / 25% 25% + no-repeat, + radial-gradient(var(--c) 17%, #0000 0), + #545153; + box-shadow: + inset -0.15em -0.15em 0.2em #0008, + inset 0.15em 0.15em 0.2em #ffffff22, + inset calc(var(--val) * 1em / 500) 0em calc(var(--val) * 1em / 500) + calc(var(--val) * -1em / 700) var(--c), + 0.25em 0.25em 0.5em #0006, + calc(0.015em * var(--val)) calc(0.005em * var(--val)) + calc(0.02em * var(--val)) calc(-0.01em * var(--val)) #0008; + border-radius: 50%; +} diff --git a/src/components/Range/Range.tsx b/src/components/Range/Range.tsx index 369bbcb..e94415d 100644 --- a/src/components/Range/Range.tsx +++ b/src/components/Range/Range.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent } from "react"; +import { ChangeEvent, FormEvent, useState } from "react"; import "./Range.css"; type Props = { @@ -14,12 +14,17 @@ type Props = { export function Range({ label, max, - labels, onChange, defaultValue, value, className = "", }: Props) { + const [val, setVal] = useState(value); + + const onInput = (e: FormEvent) => { + setVal(parseInt(e.currentTarget.value, 10)); + }; + return (
{label} @@ -27,19 +32,20 @@ export function Range({ type="range" max={max} min={1} - step="1" - className="range" + className="range glow" onChange={onChange} defaultValue={defaultValue} value={value} + style={{ "--val": val } as React.CSSProperties} + onInput={onInput} /> -
+ {/*
{labels.map((l) => (
{l}
))} -
+
*/}
); } diff --git a/src/components/StorageRequestSetup/StorageRequestReview.css b/src/components/StorageRequestSetup/StorageRequestReview.css index fe68a66..d242404 100644 --- a/src/components/StorageRequestSetup/StorageRequestReview.css +++ b/src/components/StorageRequestSetup/StorageRequestReview.css @@ -1,61 +1,6 @@ -.storageRequestReview-bar { - background-image: linear-gradient(to right, #ef4444, #facc15, #2dd4bf); - border-radius: var(--codex-border-radius); - height: 10px; - position: relative; - margin-top: 1rem; -} - -.storageRequestReview-barIndicator { - position: absolute; - border: 2px solid rgb(38 38 38); - background-color: rgb(249 115 22); - height: 1.25rem; - width: 0.5rem; - top: -6px; - bottom: 0; - transform: translateX(270px); -} - -.storageRequestReview-legendItem, -.storageRequestReview-legend { - display: flex; - align-items: center; - gap: 0.75rem; -} - -.storageRequestReview-legend { - justify-content: space-between; - margin-bottom: 0.25rem; - margin-top: 0.75rem; -} - -.storageRequestReview-legendItemColor { - border-radius: 2px; - height: 10px; - width: 10px; - display: inline-block; - background-color: var(--codex-storage-request-review-legend-item-color); -} - -.storageRequestReview-legendItemColor-cheap { - --codex-storage-request-review-legend-item-color: rgb(239 68 68); -} - -.storageRequestReview-legendItemColor-average { - --codex-storage-request-review-legend-item-color: rgb(249 115 22); -} - -.storageRequestReview-legendItemColor-good { - --codex-storage-request-review-legend-item-color: rgb(254 240 138); -} - -.storageRequestReview-legendItemColor-excellent { - --codex-storage-request-review-legend-item-color: rgb(45 212 191); -} - .storageRequestReview-hr { - margin: 1.5rem 0; + margin-bottom: 1.5rem; + margin-top: 0rem; } .storageRequestReview-numbers { @@ -75,20 +20,71 @@ .storageRequestReview-range--disabled .range { opacity: 0.5; } -/* -.storageRequestReview-range--disabled .range::-webkit-slider-thumb { - background-color: var(--codex-background-light); -} */ + +.storageRequestReview-presets { + display: flex; + padding: 0 0.5rem 2rem 0.5rem; + gap: 1rem; +} + +.storageRequestReview-presets-blocs { + display: flex; + flex: 1; + gap: 0.5rem; +} + +.storageRequestReview-presets-bloc { + flex: 1; + border-radius: var(--codex-border-radius); + background-color: rgb(56 56 56); + align-items: center; + padding: 1rem 2rem; + align-items: center; + justify-content: center; + text-align: center; + display: flex; + flex-direction: column; + gap: 0.5rem; + transition: opacity 0.35s; + cursor: pointer; + border: 1px solid transparent; +} + +.storageRequest-price { + display: flex; + justify-content: center; +} + +.storageRequestReview-presets-title { + display: flex; + flex-direction: column; + justify-content: center; +} + +.storageRequestReview-presets-bloc:not( + .storageRequestReview-presets--selected + ):hover { + border: 1px solid var(--codex-border-color); +} + +.storageRequestReview-presets--selected { + border: 1px solid var(--codex-color-primary); +} + +.storageRequestReview-alert { + display: flex; + gap: 1rem; + align-items: flex-start; +} + +.storageRequestReview-expiration { + min-width: 33%; +} @media (max-width: 800px) { .storageRequestReview-numbers { grid-template-columns: 1fr 1fr; } - - .storageRequestReview-legend { - flex-direction: column; - align-items: flex-start; - } } @media (min-width: 801px) { diff --git a/src/components/StorageRequestSetup/StorageRequestReview.tsx b/src/components/StorageRequestSetup/StorageRequestReview.tsx index d3a40a7..9cabc18 100644 --- a/src/components/StorageRequestSetup/StorageRequestReview.tsx +++ b/src/components/StorageRequestSetup/StorageRequestReview.tsx @@ -1,15 +1,11 @@ -import { ChangeEvent, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { WebStorage } from "../../utils/web-storage"; import "./StorageRequestReview.css"; import { Alert } from "@codex-storage/marketplace-ui-components"; import { CardNumbers } from "../CardNumbers/CardNumbers"; -import { Range } from "../Range/Range"; import { FileWarning } from "lucide-react"; import { classnames } from "../../utils/classnames"; -const plurals = (type: "node" | "token" | "second" | "minute", value: number) => - `${value} ${type}` + (value > 1 ? "s" : ""); - type Props = { onChangeNextState: (value: "enable" | "disable") => void; }; @@ -39,31 +35,9 @@ type Durability = { }; const durabilities = [ - { nodes: 2, tolerance: 0, proofProbability: 1 }, { nodes: 3, tolerance: 1, proofProbability: 2 }, { nodes: 4, tolerance: 2, proofProbability: 3 }, - { nodes: 5, tolerance: 3, proofProbability: 4 }, - { nodes: 6, tolerance: 4, proofProbability: 5 }, -]; - -type Price = { - reward: number; - collateral: number; -}; - -const prices = [ - { - reward: 5, - collateral: 5, - }, - { - reward: 10, - collateral: 10, - }, - { - reward: 50, - collateral: 20, - }, + { nodes: 5, tolerance: 2, proofProbability: 4 }, ]; const findDurabilityIndex = (d: Durability) => { @@ -76,24 +50,11 @@ const findDurabilityIndex = (d: Durability) => { return durabilities.findIndex((d) => JSON.stringify(d) === s); }; -const findPriceIndex = (d: Price) => { - const s = JSON.stringify({ - reward: d.reward, - collateral: d.collateral, - }); - - return prices.findIndex((p) => JSON.stringify(p) === s); -}; +const units = ["days", "minutes", "hours", "days", "months", "years"]; export function StorageRequestReview({ onChangeNextState }: Props) { const [cid, setCid] = useState(""); - const [errors, setErrors] = useState({ - nodes: "", - tolerance: "", - proofProbability: "", - }); const [durability, setDurability] = useState(1); - const [price, setPrice] = useState(1); const [data, setData] = useState({ availabilityUnit: "days", availability: 1, @@ -120,13 +81,6 @@ export function StorageRequestReview({ onChangeNextState }: Props) { }); setDurability(index + 1); - - const pindex = findPriceIndex({ - reward: d.reward, - collateral: d.collateral, - }); - - setPrice(pindex + 1); } else { WebStorage.set("storage-request-criteria", { availabilityUnit: "days", @@ -158,44 +112,86 @@ export function StorageRequestReview({ onChangeNextState }: Props) { }); }; - const onDurabilityRangeChange = (e: ChangeEvent) => { - const l = parseInt(e.currentTarget.value, 10); + const onDurabilityChange = (d: number) => { + const durability = durabilities[d - 1]; - const durability = durabilities[l - 1]; - - updateData(durability); - setDurability(l); - setErrors({ nodes: "", tolerance: "", proofProbability: "" }); + if (durability) { + updateData(durability); + setDurability(d); + } else { + setDurability(0); + } }; - const onPriceRangeChange = (e: ChangeEvent) => { - const l = parseInt(e.currentTarget.value, 10); - - const price = prices[l - 1]; - - updateData(price); - setPrice(l); - }; - - const isUnvalidConstrainst = (nodes: number, tolerance: number) => { + const isInvalidConstrainst = (nodes: number, tolerance: number) => { const ecK = nodes - tolerance; const ecM = tolerance; return ecK <= 1 || ecK < ecM; }; - const onNodesChange = (nodes: number) => { - setErrors((e) => ({ ...e, tolerance: "" })); + const isInvalidNodes = (nodes: string) => { + const error = isInvalidNumber(nodes); - if (isUnvalidConstrainst(nodes, data.tolerance)) { - setErrors((e) => ({ - ...e, - nodes: - "The data does not match Codex contrainst. Try with other values.", - })); - return; + if (error) { + return error; } + const n = Number(nodes); + + if (isInvalidConstrainst(n, data.tolerance)) { + return "The data does not match Codex contrainst"; + } + + return ""; + }; + + const isInvalidTolerance = (tolerance: string) => { + const error = isInvalidNumber(tolerance); + + if (error) { + return error; + } + + const n = Number(tolerance); + + if (n > data.nodes) { + return "The tolerance cannot be greater than the nodes."; + } + + if (isInvalidConstrainst(data.nodes, n)) { + return "The data does not match Codex contrainst."; + } + + return ""; + }; + + const isInvalidAvailability = (data: string) => { + const [value, unit = "days"] = data.split(" "); + + const error = isInvalidNumber(value); + + if (error) { + return error; + } + + // if (!unit.endsWith("s")) { + // unit += "s"; + // } + + if (!units.includes(unit)) { + return "Invalid unit must one of: minutes, hours, days, months, years"; + } + + return ""; + }; + + const isInvalidNumber = (value: string) => + isNaN(Number(value)) ? "The value is not a number" : ""; + + const onNodesChange = (value: string) => { + const nodes = Number(value); + updateData({ nodes }); const index = findDurabilityIndex({ @@ -207,25 +203,8 @@ export function StorageRequestReview({ onChangeNextState }: Props) { setDurability(index + 1); }; - const onToleranceChange = (tolerance: number) => { - setErrors((e) => ({ ...e, tolerance: "" })); - - if (tolerance > data.nodes) { - setErrors((e) => ({ - ...e, - tolerance: "The tolerance cannot be greater than the nodes.", - })); - return; - } - - if (isUnvalidConstrainst(data.nodes, tolerance)) { - setErrors((e) => ({ - ...e, - tolerance: - "The data does not match Codex contrainst. Try with other values.", - })); - return; - } + const onToleranceChange = (value: string) => { + const tolerance = Number(value); updateData({ tolerance }); @@ -238,7 +217,9 @@ export function StorageRequestReview({ onChangeNextState }: Props) { setDurability(index + 1); }; - const onProofProbabilityChange = (proofProbability: number) => { + const onProofProbabilityChange = (value: string) => { + const proofProbability = Number(value); + updateData({ proofProbability }); const index = findDurabilityIndex({ @@ -250,58 +231,134 @@ export function StorageRequestReview({ onChangeNextState }: Props) { setDurability(index + 1); }; - const onAvailabilityChange = (availability: number) => - updateData({ availability }); + const onAvailabilityChange = (value: string) => { + const [availability, availabilityUnit = "days"] = value.split(" "); + + // if (!availabilityUnit.endsWith("s")) { + // availabilityUnit += "s"; + // } + + updateData({ + availability: Number(availability), + availabilityUnit: availabilityUnit as AvailabilityUnit, + }); + }; + + const onRewardChange = (value: string) => { + const reward = Number(value); - const onRewardChange = (reward: number) => { updateData({ reward }); - - const index = findPriceIndex({ - reward, - collateral: data.collateral, - }); - - setPrice(index + 1); }; - const onCollateralChange = (collateral: number) => { + const onExpirationChange = (value: string) => { + const expiration = Number(value); + + updateData({ expiration }); + }; + + const onCollateralChange = (value: string) => { + const collateral = Number(value); + updateData({ collateral }); - - const index = findPriceIndex({ - collateral, - reward: data.reward, - }); - - setPrice(index + 1); }; + // const pluralizeUnit = () => { + // if (data.availability > 1 && !data.availabilityUnit.endsWith("s")) { + // return data.availability + " " +data.availabilityUnit + "s"; + // } + + // if (data.availability <= 1 && data.availabilityUnit.endsWith("s")) { + // return data.availabilityUnit.slice(0, -1); + // } + + // return data.availabilityUnit; + // }; + + const availability = `${data.availability} ${data.availabilityUnit}`; + return (
- Choose your criteria + Durability
+ onValidation={isInvalidNodes} + helper="Number of storage nodes"> + onValidation={isInvalidTolerance} + helper="Failure node tolerated"> + helper="Proof request frequency in seconds">
- +
+ Define your durability profile +

+ Select the appropriate level of data storage reliability ensuring + your information is protected and accessible. +

+
+
+
onDurabilityChange(0)} + className={classnames( + ["storageRequestReview-presets-bloc"], + [ + "storageRequestReview-presets--selected", + durability <= 0 || durability > 3, + ] + )}> +
+ +
+

Custom

+
+
onDurabilityChange(1)} + className={classnames( + ["storageRequestReview-presets-bloc"], + ["storageRequestReview-presets--selected", durability === 1] + )}> +
+ +
+

Low

+
+
onDurabilityChange(2)} + className={classnames( + ["storageRequestReview-presets-bloc"], + ["storageRequestReview-presets--selected", durability === 2] + )}> +
+ +
+

Medium

+
+
onDurabilityChange(3)} + className={classnames( + ["storageRequestReview-presets-bloc"], + ["storageRequestReview-presets--selected", durability === 3] + )}> +
+ +
+

High

+
+
+
+ + {/* + /> */} + + Commitment
- + data={availability} + onChange={onAvailabilityChange} + onValidation={isInvalidAvailability} + repositionCaret={false} + helper="Full period of the contract"> + - - + onChange={onRewardChange} + onValidation={isInvalidNumber} + helper="Penality tokens"> +
+ {/* */}
- - } - title="Warning" - variant="warning" - className="storageRequestReview-alert"> - This request with CID - {cid} will expire in - {plurals("minute", data.expiration)} - after the start.
- If no suitable hosts are found matching your storage requirements, you - will incur a charge of X tokens. -

-

- - Price comparaison with the market - -

-
-
- - Cheap -
-
- - Average -
- -
- - Good -
- -
- - Excellent -
-
-
-
+
+ + } + title="Warning" + variant="warning" + className="storageRequestReview-alert"> + If no suitable hosts are found for the CID {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 3a62156..d09e908 100644 --- a/src/components/StorageRequestSetup/StorageRequestSetup.css +++ b/src/components/StorageRequestSetup/StorageRequestSetup.css @@ -8,6 +8,15 @@ 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 { @@ -80,23 +89,9 @@ @media (max-width: 800px) { .storageRequest { - margin: auto; - width: 100%; - position: absolute; - top: 0; - left: 0; - min-height: 100%; - display: flex; - align-items: center; - - .alert { - flex-direction: column; - align-items: flex-start; - } - .stepper-body, .stepper { - width: calc(100% - 3rem); + /* width: calc(100% - 3rem); */ } } } @@ -106,15 +101,4 @@ margin: auto; width: 85%; } - - .storageRequest { - left: 50%; - top: 50%; - transform: translate(-50%, -50%) scale(0); - position: fixed; - } - - .storageRequest-open { - transform: translate(-50%, -50%) scale(1); - } } diff --git a/src/components/StorageRequestSetup/StorageRequestStepper.tsx b/src/components/StorageRequestSetup/StorageRequestStepper.tsx index b917a88..984ac67 100644 --- a/src/components/StorageRequestSetup/StorageRequestStepper.tsx +++ b/src/components/StorageRequestSetup/StorageRequestStepper.tsx @@ -29,7 +29,7 @@ function calculateAvailability(value: number, unit: StorageAvailabilityUnit) { case "months": return 30 * 24 * 60 * 60 * value; case "years": - return 365 * 30 * 60 * 60 * value; + return 365 * 24 * 60 * 60 * value; } } @@ -50,7 +50,7 @@ export function StorageRequestStepper({ className, open, onClose }: Props) { message: "", }); - const { mutateAsync, isPending } = useMutation({ + const { mutateAsync } = useMutation({ mutationKey: ["debug"], mutationFn: (input: CodexCreateStorageRequestInput) => CodexSdk.marketplace() @@ -94,9 +94,6 @@ export function StorageRequestStepper({ className, open, onClose }: Props) { const components = [ StorageRequestFileChooser, - // StorageRequestAvailability, - // StorageRequestDurability, - // StorageRequestPrice, StorageRequestReview, StorageRequestDone, ]; @@ -111,20 +108,27 @@ export function StorageRequestStepper({ className, open, onClose }: Props) { if (state === "before") { setProgress(true); + setStep(s); return; } if (s >= steps.current.length) { + // TODO remove this + // Just a workaround because the request could take some time + // but the current client is doing the job in the main thread. + // So we are just waiting that the request is done for now. + await new Promise((resolve) => setTimeout(resolve, 3000)); + setIsNextDisable(true); - setProgress(false); if (s >= steps.current.length) { - console.info("delete"); setStep(0); WebStorage.delete("storage-request-step"); WebStorage.delete("storage-request-criteria"); } + setProgress(false); + onClose(); return; @@ -134,7 +138,6 @@ export function StorageRequestStepper({ className, open, onClose }: Props) { setIsNextDisable(true); setProgress(false); - setStep(s); if (s == 2) { setIsNextDisable(true); @@ -172,12 +175,14 @@ export function StorageRequestStepper({ className, open, onClose }: Props) { tolerance, reward, }); + + // TODO next step } else { setIsNextDisable(false); } }; - const Body = components[step] || components[0]; + const Body = progress ? () => : components[step] || components[0]; return ( <> @@ -193,7 +198,7 @@ export function StorageRequestStepper({ className, open, onClose }: Props) { Body={} step={step} onChangeStep={onChangeStep} - progress={progress || isPending} + progress={progress} isNextDisable={progress || isNextDisable}>
diff --git a/src/routes/dashboard/purchases.tsx b/src/routes/dashboard/purchases.tsx index 3a432ac..7242609 100644 --- a/src/routes/dashboard/purchases.tsx +++ b/src/routes/dashboard/purchases.tsx @@ -68,7 +68,7 @@ const Purchases = () => { , , , - , + , , ]; }) || []; @@ -93,7 +93,7 @@ const Purchases = () => { onClose={() => setOpen(false)} /> - {!open && } +
{/* {!cells.length && (