-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Build Transaction] Attributes view UI only (without input values and…
… validation) (#825) * Build transaction: basic tabs setup * Attributes UI done * Update button label * Rename Attributes to Params
- Loading branch information
Showing
16 changed files
with
749 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,191 @@ | ||
"use client"; | ||
|
||
import { Alert, Button, Card } from "@stellar/design-system"; | ||
|
||
import { TabView } from "@/components/TabView"; | ||
import { PubKeyPicker } from "@/components/FormElements/PubKeyPicker"; | ||
import { Box } from "@/components/layout/Box"; | ||
import { SdsLink } from "@/components/SdsLink"; | ||
import { PositiveIntPicker } from "@/components/FormElements/PositiveIntPicker"; | ||
import { MemoPicker } from "@/components/FormElements/MemoPicker"; | ||
import { TimeBoundsPicker } from "@/components/FormElements/TimeBoundsPicker"; | ||
import { InputSideElement } from "@/components/InputSideElement"; | ||
|
||
import { useStore } from "@/store/useStore"; | ||
import { Routes } from "@/constants/routes"; | ||
import { useAccountSequenceNumber } from "@/query/useAccountSequenceNumber"; | ||
|
||
export default function BuildTransaction() { | ||
return <div>Build Transaction</div>; | ||
const { transaction, network } = useStore(); | ||
const { activeTab } = transaction.build; | ||
const { updateBuildActiveTab } = transaction; | ||
|
||
const { | ||
// data, | ||
// error, | ||
refetch: fetchSequenceNumber, | ||
} = useAccountSequenceNumber({ | ||
// TODO: pass source account | ||
publicKey: "", | ||
horizonUrl: network.horizonUrl, | ||
}); | ||
|
||
// useEffect(() => { | ||
// if (data || error) { | ||
// // TODO: set data ?? "" | ||
// // TODO: set error?.toString() ?? "" | ||
// } | ||
// }, [data, error]); | ||
|
||
// TODO: add info links | ||
// TODO: use store values | ||
// TODO: validation | ||
const renderParams = () => { | ||
return ( | ||
<Box gap="md"> | ||
<> | ||
<Card> | ||
<Box gap="lg"> | ||
<> | ||
<PubKeyPicker | ||
id="source_account" | ||
label="Source Account" | ||
// TODO: handle value | ||
value={""} | ||
// TODO: handle error | ||
error={""} | ||
// TODO: handle change | ||
onChange={() => {}} | ||
note={ | ||
<> | ||
If you don’t have an account yet, you can create and fund | ||
a test net account with the{" "} | ||
<SdsLink href={Routes.ACCOUNT_CREATE}> | ||
account creator | ||
</SdsLink> | ||
. | ||
</> | ||
} | ||
/> | ||
|
||
<PositiveIntPicker | ||
id="sequence_number" | ||
label="Transaction Sequence Number" | ||
placeholder="Ex: 559234806710273" | ||
// TODO: handle value | ||
value={""} | ||
// TODO: handle error | ||
error={""} | ||
// TODO: handle change | ||
onChange={() => {}} | ||
note="The transaction sequence number is usually one higher than current account sequence number." | ||
rightElement={ | ||
<InputSideElement | ||
variant="button" | ||
onClick={() => fetchSequenceNumber()} | ||
placement="right" | ||
// TODO: disable if no valid source account | ||
// disabled={} | ||
> | ||
Fetch next sequence | ||
</InputSideElement> | ||
} | ||
/> | ||
|
||
<PositiveIntPicker | ||
id="base_fee" | ||
label="Base Fee" | ||
// TODO: handle value | ||
value="" | ||
// TODO: handle error | ||
error="" | ||
// TODO: handle change | ||
onChange={() => {}} | ||
note={ | ||
<> | ||
The{" "} | ||
<SdsLink href="https://developers.stellar.org/docs/learn/glossary#base-fee"> | ||
network base fee | ||
</SdsLink>{" "} | ||
is currently set to 100 stroops (0.00001 lumens). Based on | ||
current network activity, we suggest setting it to 100 | ||
stroops. Final transaction fee is equal to base fee times | ||
number of operations in this transaction. | ||
</> | ||
} | ||
/> | ||
|
||
<MemoPicker | ||
id="memo" | ||
// TODO: handle value | ||
value={undefined} | ||
labelSuffix="optional" | ||
// TODO: handle error | ||
error="" | ||
// TODO: handle change | ||
onChange={() => {}} | ||
/> | ||
|
||
<TimeBoundsPicker | ||
// TODO: handle value | ||
value={undefined} | ||
labelSuffix="optional" | ||
// TODO: handle error | ||
error={undefined} | ||
// TODO: handle change | ||
onChange={() => {}} | ||
/> | ||
|
||
<div> | ||
{/* TODO: add validation */} | ||
<Button | ||
size="md" | ||
variant="secondary" | ||
onClick={() => { | ||
updateBuildActiveTab("operations"); | ||
}} | ||
> | ||
Add Operations | ||
</Button> | ||
</div> | ||
</> | ||
</Box> | ||
</Card> | ||
|
||
<Alert variant="primary" placement="inline"> | ||
The transaction builder lets you build a new Stellar transaction. | ||
This transaction will start out with no signatures. To make it into | ||
the ledger, this transaction will then need to be signed and | ||
submitted to the network. | ||
</Alert> | ||
</> | ||
</Box> | ||
); | ||
}; | ||
|
||
const renderOperations = () => { | ||
return <Card>Operations</Card>; | ||
}; | ||
|
||
return ( | ||
<div> | ||
<TabView | ||
heading={{ title: "Build Transaction" }} | ||
tab1={{ | ||
id: "params", | ||
label: "Params", | ||
content: renderParams(), | ||
}} | ||
tab2={{ | ||
id: "operations", | ||
label: "Operations", | ||
content: renderOperations(), | ||
}} | ||
activeTabId={activeTab} | ||
onTabChange={(id) => { | ||
updateBuildActiveTab(id); | ||
}} | ||
/> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React from "react"; | ||
import { MemoType, MemoValue } from "@stellar/stellar-sdk"; | ||
import { Input } from "@stellar/design-system"; | ||
|
||
import { RadioPicker } from "@/components/RadioPicker"; | ||
import { ExpandBox } from "@/components/ExpandBox"; | ||
|
||
type MemoPickerValue = { type: MemoType; value: MemoValue | undefined }; | ||
|
||
type MemoPickerProps = { | ||
id: string; | ||
value: MemoPickerValue | undefined; | ||
onChange: ( | ||
optionId: string | undefined, | ||
optionValue?: MemoPickerValue, | ||
) => void; | ||
labelSuffix?: string | React.ReactNode; | ||
error: string | undefined; | ||
}; | ||
|
||
export const MemoPicker = ({ | ||
id, | ||
value, | ||
onChange, | ||
labelSuffix, | ||
error, | ||
}: MemoPickerProps) => { | ||
const memoValuePlaceholder = (type?: MemoType) => { | ||
if (!type) { | ||
return ""; | ||
} | ||
|
||
switch (type) { | ||
case "id": | ||
return "Unsigned 64-bit integer"; | ||
case "hash": | ||
case "return": | ||
return "32-byte hash in hexadecimal format (64 [0-9a-f] characters)"; | ||
case "text": | ||
return "UTF-8 string of up to 28 bytes"; | ||
case "none": | ||
default: | ||
return ""; | ||
} | ||
}; | ||
|
||
return ( | ||
<div className="RadioPicker__inset"> | ||
<RadioPicker | ||
id={id} | ||
selectedOption={value?.type} | ||
label="Memo" | ||
labelSuffix={labelSuffix} | ||
onChange={onChange} | ||
options={[ | ||
{ id: "none", label: "None", value: { type: "none", value: "" } }, | ||
{ id: "text", label: "Text", value: { type: "text", value: "" } }, | ||
{ id: "id", label: "ID", value: { type: "id", value: "" } }, | ||
{ id: "hash", label: "Hash", value: { type: "hash", value: "" } }, | ||
{ | ||
id: "return", | ||
label: "Return", | ||
value: { type: "return", value: "" }, | ||
}, | ||
]} | ||
/> | ||
|
||
<ExpandBox | ||
isExpanded={Boolean(value?.type && value.type !== "none")} | ||
offsetTop="sm" | ||
> | ||
<Input | ||
fieldSize="md" | ||
id="memo_value" | ||
placeholder={memoValuePlaceholder(value?.type)} | ||
value={value?.value?.toString() || ""} | ||
onChange={(e) => { | ||
if (value?.type) { | ||
onChange(value.type, { type: value.type, value: e.target.value }); | ||
} | ||
}} | ||
error={error} | ||
/> | ||
</ExpandBox> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { Box } from "@/components/layout/Box"; | ||
import { SdsLink } from "@/components/SdsLink"; | ||
import { InputSideElement } from "@/components/InputSideElement"; | ||
import { PositiveIntPicker } from "./PositiveIntPicker"; | ||
|
||
type TimeBoundValue = { min: string; max: string }; | ||
|
||
type TimeBoundsPickerProps = { | ||
value: TimeBoundValue | undefined; | ||
labelSuffix?: string | React.ReactNode; | ||
onChange: (value: TimeBoundValue) => void; | ||
error: { min: string | false; max: string | false } | undefined; | ||
}; | ||
|
||
export const TimeBoundsPicker = ({ | ||
value = { min: "", max: "" }, | ||
labelSuffix, | ||
onChange, | ||
error, | ||
}: TimeBoundsPickerProps) => { | ||
return ( | ||
<Box gap="sm"> | ||
<> | ||
<Box gap="xs"> | ||
<> | ||
<PositiveIntPicker | ||
id="timebounds-min" | ||
label="Time Bounds" | ||
labelSuffix={labelSuffix} | ||
placeholder="Lower time bound unix timestamp. Ex: 1479151713" | ||
value={value.min} | ||
error={error?.min ? `Lower time bound: ${error.min}` : ""} | ||
onChange={(e) => { | ||
onChange({ ...value, min: e.target.value }); | ||
}} | ||
/> | ||
<PositiveIntPicker | ||
id="timebounds-max" | ||
label="" | ||
placeholder="Upper time bound unix timestamp. Ex: 1479151713" | ||
value={value.max} | ||
error={error?.max ? `Upper time bound: ${error.max}` : ""} | ||
onChange={(e) => { | ||
onChange({ ...value, max: e.target.value }); | ||
}} | ||
rightElement={ | ||
<InputSideElement | ||
variant="button" | ||
placement="right" | ||
onClick={() => { | ||
onChange({ | ||
...value, | ||
max: ( | ||
Math.ceil(new Date().getTime() / 1000) + | ||
5 * 60 | ||
).toString(), | ||
}); | ||
}} | ||
> | ||
Set to 5 min from now | ||
</InputSideElement> | ||
} | ||
/> | ||
</> | ||
</Box> | ||
<Box gap="xs" addlClassName="FieldNote FieldNote--note FieldNote--md"> | ||
<> | ||
<div> | ||
Enter{" "} | ||
<SdsLink href="http://www.epochconverter.com/"> | ||
unix timestamp | ||
</SdsLink>{" "} | ||
values of time bounds when this transaction will be valid. | ||
</div> | ||
|
||
<div> | ||
For regular transactions, it is highly recommended to set the | ||
upper time bound to get a{" "} | ||
<SdsLink href="https://github.com/stellar/stellar-core/issues/1811"> | ||
final result | ||
</SdsLink>{" "} | ||
of a transaction in a defined time. | ||
</div> | ||
</> | ||
</Box> | ||
</> | ||
</Box> | ||
); | ||
}; |
Oops, something went wrong.