add exchange order screen
This commit is contained in:
51
app/javascript/__generated__/schema.graphql
generated
51
app/javascript/__generated__/schema.graphql
generated
@@ -39,6 +39,36 @@ type Currency implements Node {
|
|||||||
name: String!
|
name: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
The connection type for Currency.
|
||||||
|
"""
|
||||||
|
type CurrencyConnection {
|
||||||
|
"""
|
||||||
|
A list of edges.
|
||||||
|
"""
|
||||||
|
edges: [CurrencyEdge!]!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Information to aid in pagination.
|
||||||
|
"""
|
||||||
|
pageInfo: PageInfo!
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
An edge in a connection.
|
||||||
|
"""
|
||||||
|
type CurrencyEdge {
|
||||||
|
"""
|
||||||
|
A cursor for use in pagination.
|
||||||
|
"""
|
||||||
|
cursor: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
The item at the end of the edge.
|
||||||
|
"""
|
||||||
|
node: Currency!
|
||||||
|
}
|
||||||
|
|
||||||
type FiatBalance implements Node {
|
type FiatBalance implements Node {
|
||||||
amountCents: Int!
|
amountCents: Int!
|
||||||
amountCurrency: String!
|
amountCurrency: String!
|
||||||
@@ -139,6 +169,27 @@ type Query {
|
|||||||
"""
|
"""
|
||||||
last: Int
|
last: Int
|
||||||
): BalanceConnection!
|
): BalanceConnection!
|
||||||
|
currencies(
|
||||||
|
"""
|
||||||
|
Returns the elements in the list that come after the specified cursor.
|
||||||
|
"""
|
||||||
|
after: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the elements in the list that come before the specified cursor.
|
||||||
|
"""
|
||||||
|
before: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the first _n_ elements from the list.
|
||||||
|
"""
|
||||||
|
first: Int
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the last _n_ elements from the list.
|
||||||
|
"""
|
||||||
|
last: Int
|
||||||
|
): CurrencyConnection!
|
||||||
currentUser: User
|
currentUser: User
|
||||||
fiatBalances(
|
fiatBalances(
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { FC } from "react";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Switch, Route } from "react-router-dom";
|
import { Switch, Route } from "react-router-dom";
|
||||||
|
|
||||||
import { Home, Wallet } from "./pages";
|
import { Home, Orders, Wallet } from "./pages";
|
||||||
|
|
||||||
export const Routes: FC = () => {
|
export const Routes: FC = () => {
|
||||||
return (
|
return (
|
||||||
@@ -13,6 +13,9 @@ export const Routes: FC = () => {
|
|||||||
<Route exact path="/wallet">
|
<Route exact path="/wallet">
|
||||||
<Wallet />
|
<Wallet />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route exact path="/orders/exchange">
|
||||||
|
<Orders.Exchange />
|
||||||
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ const MenuItems: MenuItem[] = [
|
|||||||
label: "Carteira",
|
label: "Carteira",
|
||||||
path: "/wallet",
|
path: "/wallet",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Ordem de Troca",
|
||||||
|
path: "/orders/exchange",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const SideNav = () => {
|
export const SideNav = () => {
|
||||||
|
|||||||
182
app/javascript/src/pages/Orders/Exchange/Exchange.tsx
Normal file
182
app/javascript/src/pages/Orders/Exchange/Exchange.tsx
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import type { FC } from "react";
|
||||||
|
import { graphql } from "babel-plugin-relay/macro";
|
||||||
|
import { useLazyLoadQuery } from "react-relay";
|
||||||
|
import { BigNumber } from "bignumber.js";
|
||||||
|
import cx from "classnames";
|
||||||
|
|
||||||
|
import { useCurrentUser } from "../../../contexts/UserProvider";
|
||||||
|
import { Unauthenticated } from "../../../messages/Unauthenticated";
|
||||||
|
import type { ExchangeQuery } from "./__generated__/ExchangeQuery.graphql";
|
||||||
|
|
||||||
|
const tabBaseStyles =
|
||||||
|
"w-full text-base font-bold text-black px-4 py-2 focus:ring-blue-500";
|
||||||
|
|
||||||
|
const selectedTabStyles =
|
||||||
|
"bg-blue-600 hover:bg-blue-700 rounded-l-frounded-full text-white";
|
||||||
|
|
||||||
|
const inputBaseStyles =
|
||||||
|
"rounded-lg border-transparent flex-1 appearance-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-blue-600 focus:border-transparent mb-3";
|
||||||
|
|
||||||
|
export const Exchange: FC = () => {
|
||||||
|
const { isAuthenticated } = useCurrentUser();
|
||||||
|
const [exchangeOption, setExchangeOption] = useState<"BUY" | "SELL">("BUY");
|
||||||
|
const [cryptoDock, setCryptoDock] = useState<string>("0");
|
||||||
|
const [fiatDock, setFiatDock] = useState<string>("0.00");
|
||||||
|
|
||||||
|
const { balances, fiatBalances } = useLazyLoadQuery<ExchangeQuery>(
|
||||||
|
graphql`
|
||||||
|
query ExchangeQuery {
|
||||||
|
fiatBalances {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
amountCents
|
||||||
|
amountCurrency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
balances {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
amount
|
||||||
|
currency {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isAuthenticated) return <Unauthenticated />;
|
||||||
|
const [crypto] = balances.edges;
|
||||||
|
const [fiat] = fiatBalances.edges;
|
||||||
|
|
||||||
|
const avaliableCrypto = new BigNumber(crypto.node.amount);
|
||||||
|
const avaliableFiat = (
|
||||||
|
fiat.node.amountCents ? fiat.node.amountCents / 100 : 0
|
||||||
|
).toFixed(2);
|
||||||
|
|
||||||
|
const handleSellTabClick = () => {
|
||||||
|
setExchangeOption("SELL");
|
||||||
|
setCryptoDock("0");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBuyTabClick = () => {
|
||||||
|
setExchangeOption("BUY");
|
||||||
|
setCryptoDock("0");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCryptoAmountChange = ({
|
||||||
|
currentTarget: { value },
|
||||||
|
}: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const newCryptoAmount = new BigNumber(value);
|
||||||
|
|
||||||
|
if (newCryptoAmount.isLessThanOrEqualTo(avaliableCrypto)) {
|
||||||
|
setCryptoDock(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFiatAmountChange = ({
|
||||||
|
currentTarget: { value },
|
||||||
|
}: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const newFiatAmount = Number(value);
|
||||||
|
|
||||||
|
if (Number(avaliableFiat) >= newFiatAmount) {
|
||||||
|
setFiatDock(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMaxFiatDockButton = () => {
|
||||||
|
setFiatDock(avaliableFiat);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMaxCryptoButton = () => {
|
||||||
|
setCryptoDock(avaliableCrypto.toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid place-items-center w-full">
|
||||||
|
<div className="max-w-lg">
|
||||||
|
<div className="flex items-center bg-white rounded-full border border-gray-200 mb-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={cx(
|
||||||
|
tabBaseStyles,
|
||||||
|
"rounded-full",
|
||||||
|
exchangeOption === "BUY" && selectedTabStyles
|
||||||
|
)}
|
||||||
|
onClick={handleBuyTabClick}
|
||||||
|
>
|
||||||
|
Comprar
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={cx(
|
||||||
|
tabBaseStyles,
|
||||||
|
"rounded-full",
|
||||||
|
exchangeOption === "SELL" && selectedTabStyles
|
||||||
|
)}
|
||||||
|
onClick={handleSellTabClick}
|
||||||
|
>
|
||||||
|
Vender
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form className="bg-white p-4 rounded-2xl border border-gray-200">
|
||||||
|
<span className="mb-2">
|
||||||
|
{exchangeOption === "SELL" ? "CAKE" : "BRL"} disponível:{" "}
|
||||||
|
{exchangeOption === "SELL" ? crypto.node.amount : avaliableFiat}
|
||||||
|
</span>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
{exchangeOption === "BUY" ? (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
className={cx(inputBaseStyles)}
|
||||||
|
type="number"
|
||||||
|
value={fiatDock}
|
||||||
|
onChange={handleFiatAmountChange}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={fiatDock === avaliableFiat}
|
||||||
|
className="flex items-center mb-3 ml-3 font-bold rounded-full text-red-500"
|
||||||
|
onClick={handleMaxFiatDockButton}
|
||||||
|
>
|
||||||
|
Max
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
className={cx(inputBaseStyles)}
|
||||||
|
type="number"
|
||||||
|
value={cryptoDock}
|
||||||
|
onChange={handleCryptoAmountChange}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={avaliableCrypto.isEqualTo(cryptoDock)}
|
||||||
|
className="flex items-center mb-3 ml-3 font-bold rounded-full text-red-500"
|
||||||
|
onClick={handleMaxCryptoButton}
|
||||||
|
>
|
||||||
|
Max
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="cursor-pointer py-2 px-4 bg-blue-600 hover:bg-blue-700 focus:ring-blue-500 focus:ring-offset-blue-200 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{exchangeOption === "BUY" ? "Comprar" : "Vender"} CAKE
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
259
app/javascript/src/pages/Orders/Exchange/__generated__/ExchangeQuery.graphql.ts
generated
Normal file
259
app/javascript/src/pages/Orders/Exchange/__generated__/ExchangeQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from "relay-runtime";
|
||||||
|
export type ExchangeQueryVariables = {};
|
||||||
|
export type ExchangeQueryResponse = {
|
||||||
|
readonly fiatBalances: {
|
||||||
|
readonly edges: ReadonlyArray<{
|
||||||
|
readonly node: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly amountCents: number;
|
||||||
|
readonly amountCurrency: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
readonly balances: {
|
||||||
|
readonly edges: ReadonlyArray<{
|
||||||
|
readonly node: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly amount: string;
|
||||||
|
readonly currency: {
|
||||||
|
readonly name: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ExchangeQuery = {
|
||||||
|
readonly response: ExchangeQueryResponse;
|
||||||
|
readonly variables: ExchangeQueryVariables;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
query ExchangeQuery {
|
||||||
|
fiatBalances {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
amountCents
|
||||||
|
amountCurrency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
balances {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
amount
|
||||||
|
currency {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v1 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "FiatBalanceConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "fiatBalances",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "FiatBalanceEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "edges",
|
||||||
|
"plural": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "FiatBalance",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v0/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "amountCents",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "amountCurrency",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v2 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "amount",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v3 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ExchangeQuery",
|
||||||
|
"selections": [
|
||||||
|
(v1/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "BalanceConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "balances",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "BalanceEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "edges",
|
||||||
|
"plural": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Balance",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v0/*: any*/),
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Currency",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "currency",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Query",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ExchangeQuery",
|
||||||
|
"selections": [
|
||||||
|
(v1/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "BalanceConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "balances",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "BalanceEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "edges",
|
||||||
|
"plural": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Balance",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v0/*: any*/),
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Currency",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "currency",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
(v0/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "7a42b2fc93f97505aaaf21867de36321",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "ExchangeQuery",
|
||||||
|
"operationKind": "query",
|
||||||
|
"text": "query ExchangeQuery {\n fiatBalances {\n edges {\n node {\n id\n amountCents\n amountCurrency\n }\n }\n }\n balances {\n edges {\n node {\n id\n amount\n currency {\n name\n id\n }\n }\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
(node as any).hash = '80cac44f2e6288dfb573d0037b7d4148';
|
||||||
|
export default node;
|
||||||
1
app/javascript/src/pages/Orders/Exchange/index.ts
Normal file
1
app/javascript/src/pages/Orders/Exchange/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./Exchange";
|
||||||
5
app/javascript/src/pages/Orders/index.ts
Normal file
5
app/javascript/src/pages/Orders/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { Exchange } from "./Exchange";
|
||||||
|
|
||||||
|
export const Orders = {
|
||||||
|
Exchange,
|
||||||
|
};
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from "./Home";
|
export * from "./Home";
|
||||||
export * from "./Wallet";
|
export * from "./Wallet";
|
||||||
|
export * from "./Orders";
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class User < ApplicationRecord
|
|||||||
:recoverable, :rememberable, :validatable
|
:recoverable, :rememberable, :validatable
|
||||||
|
|
||||||
has_many :documents, class_name: "UserDocument", dependent: :destroy
|
has_many :documents, class_name: "UserDocument", dependent: :destroy
|
||||||
has_many :balances, dependent: :restrict_with_error
|
has_one :balance, dependent: :restrict_with_error
|
||||||
has_one :fiat_balance, dependent: :restrict_with_error
|
has_one :fiat_balance, dependent: :restrict_with_error
|
||||||
|
|
||||||
validates :first_name, :last_name, :email, presence: true
|
validates :first_name, :last_name, :email, presence: true
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"autoprefixer": "^9",
|
"autoprefixer": "^9",
|
||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"babel-plugin-relay": "^11.0.2",
|
"babel-plugin-relay": "^11.0.2",
|
||||||
|
"bignumber.js": "^9.0.1",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"postcss": "^7",
|
"postcss": "^7",
|
||||||
"ramda": "^0.27.1",
|
"ramda": "^0.27.1",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ RSpec.describe(User, type: :model) do
|
|||||||
|
|
||||||
describe "associations" do
|
describe "associations" do
|
||||||
it { is_expected.to(have_many(:documents)) }
|
it { is_expected.to(have_many(:documents)) }
|
||||||
it { is_expected.to(have_many(:balances)) }
|
it { is_expected.to(have_one(:balance)) }
|
||||||
|
it { is_expected.to(have_one(:fiat_balance)) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
5
yarn.lock
generated
5
yarn.lock
generated
@@ -2024,6 +2024,11 @@ big.js@^5.2.2:
|
|||||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
||||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
||||||
|
|
||||||
|
bignumber.js@^9.0.1:
|
||||||
|
version "9.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5"
|
||||||
|
integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==
|
||||||
|
|
||||||
binary-extensions@^1.0.0:
|
binary-extensions@^1.0.0:
|
||||||
version "1.13.1"
|
version "1.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
||||||
|
|||||||
Reference in New Issue
Block a user