Skip to content

Commit

Permalink
Merge pull request #1452 from ecency/feat/claim-account-credit
Browse files Browse the repository at this point in the history
Added claiming to RC modal
  • Loading branch information
feruzm authored Sep 17, 2023
2 parents 4cd70ee + a8e23ce commit 394f89d
Show file tree
Hide file tree
Showing 9 changed files with 443 additions and 184 deletions.
24 changes: 24 additions & 0 deletions src/common/api/mutations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { useMutation } from "@tanstack/react-query";
import { usrActivity } from "./private-api";
import { claimAccount, claimAccountByKeychain } from "./operations";
import { FullAccount } from "../store/accounts/types";
import { PrivateKey } from "@hiveio/dhive";

interface Params {
bl?: string | number;
Expand All @@ -13,3 +16,24 @@ export function useUserActivity(username: string | undefined, ty: number) {
}
});
}

export function useAccountClaiming(account: FullAccount) {
return useMutation(
["account-claiming", account.name],
async ({ isKeychain, key }: { key?: PrivateKey; isKeychain?: boolean }) => {
try {
if (isKeychain) {
return await claimAccountByKeychain(account);
}

if (key) {
return await claimAccount(account, key);
}

throw new Error();
} catch (error) {
throw new Error("Failed RC claiming. Please, try again or contact with support.");
}
}
);
}
65 changes: 63 additions & 2 deletions src/common/api/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import {
TransactionConfirmation
} from "@hiveio/dhive";

import { Parameters } from "hive-uri";
import { encodeOp, Parameters } from "hive-uri";

import { client as hiveClient } from "./hive";

import { Account } from "../store/accounts/types";
import { Account, FullAccount } from "../store/accounts/types";

import { usrActivity } from "./private-api";

Expand Down Expand Up @@ -2279,3 +2279,64 @@ export const createAccountWithCreditKey = async (
return err;
}
};

export const claimAccount = async (account: FullAccount, key: PrivateKey) => {
if (!key) {
throw new Error("[Account claiming] Active/owner key is not provided");
}

return hiveClient.broadcast.sendOperations(
[
[
"claim_account",
{
fee: {
amount: "0",
precision: 3,
nai: "@@000000021"
},
creator: account.name,
extensions: []
}
]
],
key
);
};

export const claimAccountByHiveSigner = (account: FullAccount) =>
hotSign(
encodeOp(
[
"claim_account",
{
fee: "0.000 HIVE",
creator: account.name,
extensions: []
}
],
{}
).replace("hive://sign/", ""),
{
authority: "active",
required_auths: `["${account.name}"]`,
required_posting_auths: "[]"
},
`@${account.name}/wallet`
);

export const claimAccountByKeychain = (account: FullAccount) =>
keychain.broadcast(
account.name,
[
[
"claim_account",
{
creator: account.name,
extensions: [],
fee: "0.000 HIVE"
}
]
],
"Active"
);
34 changes: 34 additions & 0 deletions src/common/components/claim-account-credit/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@import "src/style/vars_mixins";

.claim-credit {
&-title {
display: flex;
align-items: center;
gap: 0.5rem;

&-back {
cursor: pointer;

svg {
width: 1rem;
height: 1rem;
}
}

@include themify(night) {
color: $gray-400;
}
}

.key-or-hot {
padding: 0;
margin: 1rem 0 0;

.input-group {
svg {
width: 1rem;
height: 1rem;
}
}
}
}
100 changes: 100 additions & 0 deletions src/common/components/claim-account-credit/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import { arrowLeftSvg } from "../../img/svg";
import "./index.scss";
import { FullAccount } from "../../store/accounts/types";
import { useAccountClaiming } from "../../api/mutations";
import { _t } from "../../i18n";
import KeyOrHot from "../key-or-hot";
import { useMappedStore } from "../../store/use-mapped-store";
import { claimAccountByHiveSigner } from "../../api/operations";

interface Props {
account: FullAccount;
claimAccountAmount: number;
}

const ClaimAccountCredit = ({ account, claimAccountAmount }: Props) => {
const { global, activeUser, addAccount } = useMappedStore();
const {
mutateAsync: claimAccount,
isLoading,
error,
isSuccess,
reset
} = useAccountClaiming(account);

const [key, setKey] = useState("");
const [isKeySetting, setIsKeySetting] = useState(false);

useEffect(() => {
if (isSuccess) {
addAccount({
...account,
pending_claimed_accounts: 0
});
}
}, [isSuccess]);

return (
<div className="claim-credit">
<div className="claim-credit-title">
{isKeySetting ? (
<div
className="claim-credit-title-back"
onClick={() => {
setIsKeySetting(false);
reset();
}}
>
{arrowLeftSvg}
</div>
) : (
<></>
)}
{_t("rc-info.claim-accounts")}
<span className="text-primary">{claimAccountAmount}</span>
</div>
{!isSuccess &&
!isKeySetting &&
claimAccountAmount > 0 &&
activeUser?.username === account.name ? (
<Button size="sm" onClick={() => setIsKeySetting(true)}>
{_t("rc-info.claim")}
</Button>
) : (
<></>
)}
{isSuccess ? (
<small className="text-success my-3 d-block">{_t("rc-info.successfully-claimed")}</small>
) : (
<></>
)}
{error ? (
<small className="d-block text-danger my-3">{(error as Error)?.message}</small>
) : (
<></>
)}
{isKeySetting && !isSuccess ? (
<KeyOrHot
inProgress={isLoading}
signingKey={key}
setSigningKey={(k) => setKey(k)}
global={global}
activeUser={activeUser}
onKey={(key) => claimAccount({ key })}
onHot={() => claimAccountByHiveSigner(account)}
onKc={() =>
claimAccount({
isKeychain: true
})
}
/>
) : (
<></>
)}
</div>
);
};

export default ClaimAccountCredit;
40 changes: 24 additions & 16 deletions src/common/components/key-or-hot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface Props {
onKey: (key: PrivateKey) => void;
onHot?: () => void;
onKc?: () => void;
keyOnly?: boolean;
}

interface State {
Expand Down Expand Up @@ -117,21 +118,27 @@ export class KeyOrHot extends Component<Props, State> {
</InputGroup.Append>
</InputGroup>
</Form>
<OrDivider />
<div className="hs-sign">
<Button variant="outline-primary" onClick={this.hotClicked}>
<img src={hsLogo} className="hs-logo" alt="hivesigner" />{" "}
{_t("key-or-hot.with-hivesigner")}
</Button>
</div>

{global.hasKeyChain && (
<div className="kc-sign">
<Button variant="outline-primary" onClick={this.kcClicked}>
<img src={keyChainLogo} className="kc-logo" alt="keychain" />{" "}
{_t("key-or-hot.with-keychain")}
</Button>
</div>
{this.props.keyOnly ? (
<></>
) : (
<>
<OrDivider />
<div className="hs-sign">
<Button variant="outline-primary" onClick={this.hotClicked}>
<img src={hsLogo} className="hs-logo" alt="hivesigner" />{" "}
{_t("key-or-hot.with-hivesigner")}
</Button>
</div>

{global.hasKeyChain && (
<div className="kc-sign">
<Button variant="outline-primary" onClick={this.kcClicked}>
<img src={keyChainLogo} className="kc-logo" alt="keychain" />{" "}
{_t("key-or-hot.with-keychain")}
</Button>
</div>
)}
</>
)}
</div>
</>
Expand All @@ -148,7 +155,8 @@ export default (p: Props) => {
inProgress: p.inProgress,
onKey: p.onKey,
onHot: p.onHot,
onKc: p.onKc
onKc: p.onKc,
keyOnly: p.keyOnly
};

return <KeyOrHot {...props} />;
Expand Down
Loading

0 comments on commit 394f89d

Please sign in to comment.