diff --git a/CHANGELOG_UNRELEASED.md b/CHANGELOG_UNRELEASED.md
index d995def357..9278e4b347 100644
--- a/CHANGELOG_UNRELEASED.md
+++ b/CHANGELOG_UNRELEASED.md
@@ -23,7 +23,7 @@
- (bugs) [\#2295](https://github.com/bandprotocol/bandchain/pull/2295) Truncate `accumulated_commission` precision.
### Scan
-
+- (impv) [\#2310](https://github.com/bandprotocol/bandchain/pull/2310) Implemented the TxIndexpage layout for mobile view
- (impv) [\#2305](https://github.com/bandprotocol/bandchain/pull/2305) Implement the TxHomepage layout for mobile view and adjusted the pagination on mobile view.
- (feat) [\#2294](https://github.com/bandprotocol/bandchain/pull/2294) Implemented top part of `ValidatorIndexPage` for mobile
- (impv) [\#2299](https://github.com/bandprotocol/bandchain/pull/2299) Update the latest transactions table for mobile version.
diff --git a/scan/src/components/AmountRender.re b/scan/src/components/AmountRender.re
index 950023d86f..72f2aefb35 100644
--- a/scan/src/components/AmountRender.re
+++ b/scan/src/components/AmountRender.re
@@ -1,6 +1,7 @@
type pos =
| Msg
- | TxIndex;
+ | TxIndex
+ | Fee;
module Styles = {
open Css;
@@ -22,6 +23,7 @@ let make = (~coins, ~pos=Msg) => {
{switch (pos) {
| Msg =>
| TxIndex =>
+ | Fee => React.null
}}
;
};
diff --git a/scan/src/components/TxIndexPageTable.re b/scan/src/components/TxIndexPageTable.re
index 720a0b0ef3..385ada59b3 100644
--- a/scan/src/components/TxIndexPageTable.re
+++ b/scan/src/components/TxIndexPageTable.re
@@ -953,7 +953,7 @@ let renderUnknownMessage = () => {
;
};
-let renderBody = (msg: TxSub.Msg.t) => {
+let renderBody = (msg: TxSub.Msg.t) =>
switch (msg) {
| SendMsg(send) => renderSend(send)
| CreateDataSourceMsg(dataSource) => renderCreateDataSource(dataSource)
@@ -997,7 +997,6 @@ let renderBody = (msg: TxSub.Msg.t) => {
| FailMsg(_) => renderFailMessage()
| UnknownMsg => renderUnknownMessage()
};
-};
module THead = {
[@react.component]
@@ -1052,6 +1051,7 @@ let make = (~messages: list(TxSub.Msg.t)) => {
{messages
->Belt.List.mapWithIndex((index, msg) => {
let theme = msg |> TxSub.Msg.getBadgeTheme;
+ //TODO: Change index to be uniqe something
string_of_int}>
diff --git a/scan/src/components/TxMobileIndexPageTable.re b/scan/src/components/TxMobileIndexPageTable.re
new file mode 100644
index 0000000000..66f8db8d52
--- /dev/null
+++ b/scan/src/components/TxMobileIndexPageTable.re
@@ -0,0 +1,160 @@
+let addressWidth = 160;
+let renderMuitisendList = (tx: TxSub.Msg.MultiSend.t) =>
+ InfoMobileCard.[("INPUTS", Nothing)]
+ ->Belt.List.concat(
+ {
+ let%IterList {address, coins} = tx.inputs;
+ [
+ ("FROM", InfoMobileCard.Address(address, addressWidth, false)),
+ ("AMOUNT", Coin({value: coins, hasDenom: false})),
+ ];
+ },
+ )
+ ->Belt.List.concat([("OUTPUT", Nothing)])
+ ->Belt.List.concat(
+ {
+ let%IterList {address, coins} = tx.outputs;
+ [
+ ("TO", InfoMobileCard.Address(address, addressWidth, false)),
+ ("AMOUNT", Coin({value: coins, hasDenom: false})),
+ ];
+ },
+ );
+
+let renderDetailMobile =
+ //TODO: implement Guan Yu's message later
+ fun
+ | TxSub.Msg.SendMsg({fromAddress, toAddress, amount}) =>
+ InfoMobileCard.[
+ ("FROM", Address(fromAddress, addressWidth, false)),
+ ("TO", Address(toAddress, addressWidth, false)),
+ ("AMOUNT", Coin({value: amount, hasDenom: true})),
+ ]
+ | DelegateMsg({validatorAddress, delegatorAddress, amount}) => [
+ ("DELEGATOR ADDRESS", Address(delegatorAddress, addressWidth, false)),
+ ("VALIDATOR ADDRESS", Address(validatorAddress, addressWidth, true)),
+ ("AMOUNT", Coin({value: [amount], hasDenom: true})),
+ ]
+ | UndelegateMsg({validatorAddress, delegatorAddress, amount}) => [
+ ("DELEGATOR ADDRESS", Address(delegatorAddress, addressWidth, false)),
+ ("VALIDATOR ADDRESS", Address(validatorAddress, addressWidth, true)),
+ ("AMOUNT", Coin({value: [amount], hasDenom: true})),
+ ]
+ | MultiSendMsg(tx) => renderMuitisendList(tx)
+ | WithdrawRewardMsg({validatorAddress, delegatorAddress, amount}) => [
+ ("DELEGATOR ADDRESS", Address(delegatorAddress, addressWidth, false)),
+ ("VALIDATOR ADDRESS", Address(validatorAddress, addressWidth, true)),
+ ("AMOUNT", Coin({value: amount, hasDenom: true})),
+ ]
+ | RedelegateMsg({validatorSourceAddress, validatorDestinationAddress, delegatorAddress, amount}) => [
+ ("DELEGATOR ADDRESS", Address(delegatorAddress, addressWidth, false)),
+ ("SOURCE ADDRESS", Address(validatorSourceAddress, addressWidth, true)),
+ ("DESTINATION ADDRESS", Address(validatorDestinationAddress, addressWidth, true)),
+ ("AMOUNT", Coin({value: [amount], hasDenom: true})),
+ ]
+ | SetWithdrawAddressMsg({delegatorAddress, withdrawAddress}) => [
+ ("DELEGATOR ADDRESS", Address(delegatorAddress, addressWidth, false)),
+ ("WITHDRAW ADDRESS", Address(withdrawAddress, addressWidth, false)),
+ ]
+ | CreateValidatorMsg({
+ moniker,
+ identity,
+ website,
+ details,
+ commissionRate,
+ commissionMaxRate,
+ commissionMaxChange,
+ delegatorAddress,
+ validatorAddress,
+ publicKey,
+ minSelfDelegation,
+ selfDelegation,
+ }) => [
+ ("MONIKER", Text(moniker)),
+ ("IDENTITY", Text(identity)),
+ ("WEBSITE", Text(website)),
+ ("DETAIL", Text(details)),
+ ("COMMISSION RATE", Percentage(commissionRate, Some(4))),
+ ("COMMISSION MAX RATE", Percentage(commissionMaxRate, Some(4))),
+ ("COMMISSION MAX CHANGE", Percentage(commissionMaxChange, Some(4))),
+ ("DELEGATOR ADDRESS", Address(delegatorAddress, addressWidth, false)),
+ ("VALIDATOR ADDRESS", Address(validatorAddress, addressWidth, true)),
+ ("PUBLIC KEY", PubKey(publicKey)),
+ ("MIN SELF DELEGATION", Coin({value: [minSelfDelegation], hasDenom: true})),
+ ("SELF DELEGATION", Coin({value: [selfDelegation], hasDenom: true})),
+ ]
+ | EditValidatorMsg({
+ moniker,
+ identity,
+ website,
+ details,
+ commissionRate,
+ sender,
+ minSelfDelegation,
+ }) => [
+ ("MONIKER", moniker == Config.doNotModify ? Text("Unchanged") : Text(moniker)),
+ ("IDENTITY", identity == Config.doNotModify ? Text("Unchanged") : Text(identity)),
+ ("WEBSITE", website == Config.doNotModify ? Text("Unchanged") : Text(website)),
+ ("DETAIL", details == Config.doNotModify ? Text("Unchanged") : Text(details)),
+ (
+ "COMMISSION RATE",
+ switch (commissionRate) {
+ | Some(rate) => Percentage(rate, Some(4))
+ | None => Text("Unchanged")
+ },
+ ),
+ ("VALIDATOR ADDRESS", Address(sender, addressWidth, true)),
+ (
+ "MIN SELF DELEGATION",
+ switch (minSelfDelegation) {
+ | Some(amount) => Coin({value: [amount], hasDenom: true})
+ | None => Text("Unchanged")
+ },
+ ),
+ ]
+ | WithdrawCommissionMsg({validatorAddress, amount}) => [
+ ("VALIDATOR ADDRESS", Address(validatorAddress, addressWidth, true)),
+ ("AMOUNT", Coin({value: amount, hasDenom: true})),
+ ]
+ | UnjailMsg({address}) => [("VALIDATOR ADDRESS", Address(address, addressWidth, true))]
+ | _ => [];
+
+[@react.component]
+let make = (~messages: list(TxSub.Msg.t)) => {
+ <>
+ //TODO: Change index to be uniqe something
+ {messages
+ ->Belt.List.mapWithIndex((index, msg) => {
+ let renderList = msg |> renderDetailMobile;
+ let theme = msg |> TxSub.Msg.getBadgeTheme;
+ let creator = msg |> TxSub.Msg.getCreator;
+ Belt.List.concat(renderList)
+ }
+ key={index |> string_of_int}
+ idx={index |> string_of_int}
+ />;
+ })
+ ->Array.of_list
+ ->React.array}
+ >;
+};
+
+module Loading = {
+ [@react.component]
+ let make = () => {
+ ;
+ };
+};
diff --git a/scan/src/components/TxsTable.re b/scan/src/components/TxsTable.re
index c6441c9e15..50a66e4607 100644
--- a/scan/src/components/TxsTable.re
+++ b/scan/src/components/TxsTable.re
@@ -105,7 +105,7 @@ let renderBodyMobile = (reserveIndex, txSub: ApolloHooks.Subscription.variant(Tx
values=InfoMobileCard.[
("TX HASH", TxHash(txHash, 200)),
("BLOCK", Height(blockHeight)),
- ("GAS FEE\n(BAND)", Coin(gasFee)),
+ ("GAS FEE\n(BAND)", Coin({value: gasFee, hasDenom: false})),
("ACTIONS", Messages(txHash, messages, success, errMsg)),
]
key={blockHeight |> ID.Block.toString}
diff --git a/scan/src/components/validator/DelegatorsTable.re b/scan/src/components/validator/DelegatorsTable.re
index 1b669a7002..67ba84acd9 100644
--- a/scan/src/components/validator/DelegatorsTable.re
+++ b/scan/src/components/validator/DelegatorsTable.re
@@ -109,9 +109,9 @@ let renderBodyMobile =
| Data({amount, sharePercentage, delegatorAddress}) =>
Coin.getBandAmountFromCoin)),
+ ("DELEGATOR", Address(delegatorAddress, 149, false)),
+ ("SHARES (%)", Float(sharePercentage, Some(4))),
+ ("AMOUNT\n(BAND)", Coin({value: [amount], hasDenom: false})),
]
key={delegatorAddress |> Address.toBech32}
idx={delegatorAddress |> Address.toBech32}
diff --git a/scan/src/pages/TxIndexPage.re b/scan/src/pages/TxIndexPage.re
index 0ed8c23a48..75862276f1 100644
--- a/scan/src/pages/TxIndexPage.re
+++ b/scan/src/pages/TxIndexPage.re
@@ -22,6 +22,7 @@ module Styles = {
alignItems(`center),
marginTop(`px(25)),
marginBottom(`px(44)),
+ Media.mobile([marginBottom(`px(25))]),
]);
let correctLogo = style([width(`px(20)), marginLeft(`px(10))]);
@@ -43,6 +44,25 @@ module Styles = {
boxShadow(Shadow.box(~x=`zero, ~y=`px(2), ~blur=`px(4), rgba(0, 0, 0, 0.1))),
]);
let notfoundLogo = style([width(`px(180)), marginRight(`px(10))]);
+ let infoContainerFullwidth =
+ style([
+ Media.mobile([
+ selector("> div", [flexBasis(`percent(100.))]),
+ selector("> div + div", [marginTop(`px(15))]),
+ selector("> div > div > div", [display(`block)]),
+ ]),
+ ]);
+ let infoContainerHalfwidth =
+ style([
+ Media.mobile([
+ selector(
+ "> div",
+ [flexGrow(0.), flexShrink(0.), flexBasis(`calc((`sub, `percent(50.), `px(20))))],
+ ),
+ selector("> div + div + div", [marginTop(`px(15))]),
+ selector("> div *", [alignItems(`flexStart)]),
+ ]),
+ ]);
};
module TxNotFound = {
@@ -71,8 +91,8 @@ module TxNotFound = {
[@react.component]
let make = (~txHash) => {
+ let isMobile = Media.isMobile();
let txSub = TxSub.get(txHash);
-
switch (txSub) {
| Loading
| Data(_) =>
@@ -115,21 +135,33 @@ let make = (~txHash) => {
{switch (txSub) {
| Data(_) =>
<>
- Hash.toHex(~upper=true)}
- size=Text.Xxl
- weight=Text.Bold
- nowrap=true
- code=true
- color=Colors.gray7
- />
-
- Hash.toHex(~upper=true)} />
+ {isMobile
+ ? Hash.toHex(~upper=true)}
+ size=Text.Lg
+ weight=Text.Bold
+ nowrap=false
+ breakAll=true
+ code=true
+ color=Colors.gray7
+ />
+ : <>
+ Hash.toHex(~upper=true)}
+ size=Text.Xxl
+ weight=Text.Bold
+ nowrap=true
+ code=true
+ color=Colors.gray7
+ />
+
+ Hash.toHex(~upper=true)} />
+ >}
>
| _ =>
}}
-
+
{switch (txSub) {
| Data({blockHeight}) =>
@@ -140,7 +172,17 @@ let make = (~txHash) => {
{switch (txSub) {
| Data({timestamp}) =>
- | _ =>
+ | _ =>
+
}}
@@ -151,7 +193,7 @@ let make = (~txHash) => {
-
+
{switch (txSub) {
| Data({gasUsed}) =>
@@ -207,7 +249,7 @@ let make = (~txHash) => {
-
+ {isMobile ? : }
>
| _ =>
<>
@@ -217,7 +259,7 @@ let make = (~txHash) => {
-
+ {isMobile ? : }
>
}}
>
diff --git a/scan/src/reusable/InfoMobileCard.re b/scan/src/reusable/InfoMobileCard.re
index 99a2ff6c45..33c2699d6a 100644
--- a/scan/src/reusable/InfoMobileCard.re
+++ b/scan/src/reusable/InfoMobileCard.re
@@ -1,14 +1,24 @@
+type coin_amount_t = {
+ value: list(Coin.t),
+ hasDenom: bool,
+};
+
type t =
- | Address(Address.t, int)
+ | Address(Address.t, int, bool)
| Height(ID.Block.t)
- | Coin(list(Coin.t))
+ | Coin(coin_amount_t)
| Count(int)
- | Float(float)
+ | Float(float, option(int))
+ | Percentage(float, option(int))
| Timestamp(MomentRe.Moment.t)
| TxHash(Hash.t, int)
| Validator(Address.t, string, string)
| Messages(Hash.t, list(TxSub.Msg.t), bool, string)
- | Loading(int);
+ | PubKey(PubKey.t)
+ | Badge(TxSub.Msg.badge_theme_t)
+ | Loading(int)
+ | Text(string)
+ | Nothing;
module Styles = {
open Css;
@@ -16,14 +26,21 @@ module Styles = {
let addressContainer = w => {
style([width(`px(w))]);
};
+ let badge = color =>
+ style([
+ display(`inlineFlex),
+ padding2(~v=`px(5), ~h=`px(10)),
+ backgroundColor(color),
+ borderRadius(`px(15)),
+ ]);
};
[@react.component]
let make = (~info) => {
switch (info) {
- | Address(address, width) =>
+ | Address(address, width, isValidator) =>
| Height(height) =>
@@ -35,15 +52,31 @@ let make = (~info) => {
spacing={Text.Em(0.02)}
code=true
/>
- | Float(value) =>
- Format.fPretty} size=Text.Md spacing={Text.Em(0.02)} code=true />
- | Coin(value) =>
+ | Float(value, digits) =>
+ Format.fPretty(~digits?)}
+ size=Text.Md
+ spacing={Text.Em(0.02)}
+ code=true
+ />
+ | Percentage(value, digits) =>
Format.fPercent(~digits?)}
+ size=Text.Md
+ spacing={Text.Em(0.02)}
+ code=true
+ />
+ | Coin({value, hasDenom}) =>
+
+ | Text(text) =>
+ Coin.getBandAmountFromCoins->Format.fPretty}
- weight=Text.Medium
+ nowrap=true
+ ellipsis=true
/>
| Timestamp(time) =>
| Validator(address, moniker, identity) =>
@@ -54,9 +87,15 @@ let make = (~info) => {
identity
width={`percent(100.)}
/>
+ | PubKey(publicKey) =>
| TxHash(txHash, width) =>
| Messages(txHash, messages, success, errMsg) =>
+ | Badge({text, textColor, bgColor}) =>
+
+
+
| Loading(width) =>
+ | Nothing => React.null
};
};
diff --git a/scan/src/reusable/MobileCard.re b/scan/src/reusable/MobileCard.re
index aa22caaf80..4feea3c91b 100644
--- a/scan/src/reusable/MobileCard.re
+++ b/scan/src/reusable/MobileCard.re
@@ -19,6 +19,7 @@ module Styles = {
flexBasis(`percent(25.)),
]);
let logo = style([width(`px(20)), position(`absolute), top(`px(5)), right(`px(12))]);
+ let cardItemHeadingLg = style([padding2(~v=`px(10), ~h=`zero)]);
};
[@react.component]
@@ -35,20 +36,35 @@ let make = (~values, ~idx, ~status=?) => {
| InfoMobileCard.Messages(_) => `baseline
| _ => `center
};
+
string_of_int)}>
{heading
->Js.String2.split("\n")
- ->Belt.Array.map(each =>
-
- )
+ ->Belt.Array.map(each => {
+ switch (value) {
+ | InfoMobileCard.Nothing =>
+
+
+
+ | _ =>
+
+ }
+ })
->React.array}