From a057931c51ddd3b28590068cbf912c201e34fbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Geonizeli?= Date: Wed, 11 Aug 2021 20:51:42 -0300 Subject: [PATCH] wallet screen --- app/controllers/admin/balances_controller.rb | 3 + app/controllers/application_controller.rb | 2 - app/controllers/graphql_controller.rb | 2 + app/graphql/types/balance_type.rb | 13 ++ app/graphql/types/currency_type.rb | 12 + app/graphql/types/query_type.rb | 5 + app/graphql/types/user_type.rb | 3 +- app/graphql/x_stake_schema.rb | 15 +- app/javascript/__generated__/schema.graphql | 122 ++++++++++ app/javascript/src/Routes.tsx | 7 +- app/javascript/src/components/SideNav.tsx | 4 - app/javascript/src/pages/Wallet/Wallet.tsx | 94 ++++++++ .../__generated__/WalletQuery.graphql.ts | 165 ++++++++++++++ app/javascript/src/pages/Wallet/index.ts | 1 + app/javascript/src/pages/index.ts | 1 + app/javascript/src/pages/index.tsx | 1 - app/policies/balance_policy.rb | 10 + db/seeds.rb | 210 +++++++++++++++++- spec/policies/balance_policy_spec.rb | 6 + 19 files changed, 656 insertions(+), 20 deletions(-) create mode 100644 app/graphql/types/balance_type.rb create mode 100644 app/graphql/types/currency_type.rb create mode 100644 app/javascript/src/pages/Wallet/Wallet.tsx create mode 100644 app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts create mode 100644 app/javascript/src/pages/Wallet/index.ts delete mode 100644 app/javascript/src/pages/index.tsx create mode 100644 app/policies/balance_policy.rb create mode 100644 spec/policies/balance_policy_spec.rb diff --git a/app/controllers/admin/balances_controller.rb b/app/controllers/admin/balances_controller.rb index ecad826..7ab3220 100644 --- a/app/controllers/admin/balances_controller.rb +++ b/app/controllers/admin/balances_controller.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true module Admin class BalancesController < Admin::ApplicationController + def valid_action?(name, resource = resource_class) + ["destroy"].exclude?(name.to_s) && super + end end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b218fb5..d970904 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true class ApplicationController < ActionController::Base - include Pundit - before_action :configure_devise_permitted_parameters, if: :devise_controller? protected diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index a524f70..76fb005 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true class GraphqlController < ApplicationController + # protect_from_forgery with: :null_session + def execute variables = prepare_variables(params[:variables]) query = params[:query] diff --git a/app/graphql/types/balance_type.rb b/app/graphql/types/balance_type.rb new file mode 100644 index 0000000..f1a3e09 --- /dev/null +++ b/app/graphql/types/balance_type.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Types + class BalanceType < Types::BaseObject + implements GraphQL::Types::Relay::Node + global_id_field :id + + graphql_name "Balance" + + field :id, ID, null: false + field :currency, CurrencyType, null: false + field :amount, String, null: false + end +end diff --git a/app/graphql/types/currency_type.rb b/app/graphql/types/currency_type.rb new file mode 100644 index 0000000..6c35166 --- /dev/null +++ b/app/graphql/types/currency_type.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +module Types + class CurrencyType < Types::BaseObject + implements GraphQL::Types::Relay::Node + global_id_field :id + + graphql_name "Currency" + + field :id, ID, null: false + field :name, String, null: false + end +end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index f662605..95b6fb0 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -8,5 +8,10 @@ module Types def current_user context[:current_user] end + + field :balances, BalanceType.connection_type, null: false + def balances + Pundit.policy_scope(current_user, Balance) + end end end diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index 61bfec3..efd0c7b 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -2,9 +2,10 @@ module Types class UserType < Types::BaseObject # implements GraphQL::Types::Relay::Node - global_id_field :id + graphql_name "User" + field :id, ID, null: false field :first_name, String, null: false field :last_name, String, null: false diff --git a/app/graphql/x_stake_schema.rb b/app/graphql/x_stake_schema.rb index afef4fc..b89bdee 100644 --- a/app/graphql/x_stake_schema.rb +++ b/app/graphql/x_stake_schema.rb @@ -4,15 +4,22 @@ class XStakeSchema < GraphQL::Schema query(Types::QueryType) def self.resolve_type(abstract_type, obj, ctx) - raise(GraphQL::RequiredImplementationMissingError) + case obj + when Currency + Types::CurrencyType + when Balance + Types::BalanceType + else + raise(GraphQL::RequiredImplementationMissingError, "Unexpected object: #{obj}") + end end - def self.id_from_object(object, type_definition, query_ctx) + def self.id_from_object(object, type_definition, ctx) GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id) end - def self.object_from_id(id, query_ctx) + def self.object_from_id(id, ctx) type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id) - type_name.constantize.find(item_id) + Pundit.policy_scope(ctx[:current_user], type_name.constantize).find(item_id) end end diff --git a/app/javascript/__generated__/schema.graphql b/app/javascript/__generated__/schema.graphql index 79516c9..1594f5e 100644 --- a/app/javascript/__generated__/schema.graphql +++ b/app/javascript/__generated__/schema.graphql @@ -1,5 +1,127 @@ +type Balance implements Node { + amount: Float! + currency: Currency! + id: ID! +} + +""" +The connection type for Balance. +""" +type BalanceConnection { + """ + A list of edges. + """ + edges: [BalanceEdge] + + """ + A list of nodes. + """ + nodes: [Balance] + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An edge in a connection. +""" +type BalanceEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of the edge. + """ + node: Balance +} + +type Currency implements Node { + id: ID! + name: String! +} + +""" +An object with an ID. +""" +interface Node { + """ + ID of the object. + """ + id: ID! +} + +""" +Information about pagination in a connection. +""" +type PageInfo { + """ + When paginating forwards, the cursor to continue. + """ + endCursor: String + + """ + When paginating forwards, are there more items? + """ + hasNextPage: Boolean! + + """ + When paginating backwards, are there more items? + """ + hasPreviousPage: Boolean! + + """ + When paginating backwards, the cursor to continue. + """ + startCursor: String +} + type Query { + balances( + """ + 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 + ): BalanceConnection! currentUser: User + + """ + Fetches an object given its ID. + """ + node( + """ + ID of the object. + """ + id: ID! + ): Node + + """ + Fetches a list of objects given a list of IDs. + """ + nodes( + """ + IDs of the objects. + """ + ids: [ID!]! + ): [Node]! } type User { diff --git a/app/javascript/src/Routes.tsx b/app/javascript/src/Routes.tsx index 23528f3..b429084 100644 --- a/app/javascript/src/Routes.tsx +++ b/app/javascript/src/Routes.tsx @@ -2,14 +2,17 @@ import type { FC } from "react"; import React from "react"; import { Switch, Route } from "react-router-dom"; -import { Home } from "./pages"; +import { Home, Wallet } from "./pages"; export const Routes: FC = () => { return ( - + + + + ); }; diff --git a/app/javascript/src/components/SideNav.tsx b/app/javascript/src/components/SideNav.tsx index 62099c0..71289fa 100644 --- a/app/javascript/src/components/SideNav.tsx +++ b/app/javascript/src/components/SideNav.tsx @@ -14,10 +14,6 @@ const MenuItems: MenuItem[] = [ label: "Início", path: "/", }, - { - label: "Stake", - path: "/stake", - }, { label: "Carteira", path: "/wallet", diff --git a/app/javascript/src/pages/Wallet/Wallet.tsx b/app/javascript/src/pages/Wallet/Wallet.tsx new file mode 100644 index 0000000..727cf17 --- /dev/null +++ b/app/javascript/src/pages/Wallet/Wallet.tsx @@ -0,0 +1,94 @@ +import { graphql } from "babel-plugin-relay/macro"; +import type { FC } from "react"; +import React from "react"; +import { useLazyLoadQuery } from "react-relay"; + +import { tokens } from "../../constants/pancake/Tokens"; +import type { WalletQuery } from "./__generated__/WalletQuery.graphql"; + +export const Wallet: FC = () => { + const { balances } = useLazyLoadQuery( + graphql` + query WalletQuery { + balances { + nodes { + id + amount + currency { + name + } + } + } + } + `, + {} + ); + + const tokensList = Object.values(tokens); + + return ( +
+
+
+
+
+ + + + + + + + + {balances.nodes?.map((balance) => { + const token = tokensList.find( + ({ symbol }) => symbol === balance?.currency.name + ); + + return ( + + + + + ); + })} + +
+ Moeda + + Saldo +
+
+
+ + profil + +
+
+

+ {balance?.currency.name} +

+
+
+
+

+ {balance?.amount} +

+
+
+
+
+
+
+ ); +}; diff --git a/app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts b/app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts new file mode 100644 index 0000000..2e49fb5 --- /dev/null +++ b/app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts @@ -0,0 +1,165 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from "relay-runtime"; +export type WalletQueryVariables = {}; +export type WalletQueryResponse = { + readonly balances: { + readonly nodes: ReadonlyArray<{ + readonly id: string; + readonly amount: number; + readonly currency: { + readonly name: string; + }; + } | null> | null; + }; +}; +export type WalletQuery = { + readonly response: WalletQueryResponse; + readonly variables: WalletQueryVariables; +}; + + + +/* +query WalletQuery { + balances { + nodes { + 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, + "kind": "ScalarField", + "name": "amount", + "storageKey": null +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "WalletQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "BalanceConnection", + "kind": "LinkedField", + "name": "balances", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Balance", + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + (v0/*: any*/), + (v1/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Currency", + "kind": "LinkedField", + "name": "currency", + "plural": false, + "selections": [ + (v2/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "WalletQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "BalanceConnection", + "kind": "LinkedField", + "name": "balances", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Balance", + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + (v0/*: any*/), + (v1/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Currency", + "kind": "LinkedField", + "name": "currency", + "plural": false, + "selections": [ + (v2/*: any*/), + (v0/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "6b8d0c664bd2d9df4d323c19c4a823a5", + "id": null, + "metadata": {}, + "name": "WalletQuery", + "operationKind": "query", + "text": "query WalletQuery {\n balances {\n nodes {\n id\n amount\n currency {\n name\n id\n }\n }\n }\n}\n" + } +}; +})(); +(node as any).hash = '428f4f1ab769f9056dd38ec641a30733'; +export default node; diff --git a/app/javascript/src/pages/Wallet/index.ts b/app/javascript/src/pages/Wallet/index.ts new file mode 100644 index 0000000..7397bec --- /dev/null +++ b/app/javascript/src/pages/Wallet/index.ts @@ -0,0 +1 @@ +export * from "./Wallet"; diff --git a/app/javascript/src/pages/index.ts b/app/javascript/src/pages/index.ts index 5d79295..f07c67e 100644 --- a/app/javascript/src/pages/index.ts +++ b/app/javascript/src/pages/index.ts @@ -1 +1,2 @@ export * from "./Home"; +export * from "./Wallet"; diff --git a/app/javascript/src/pages/index.tsx b/app/javascript/src/pages/index.tsx deleted file mode 100644 index 5d79295..0000000 --- a/app/javascript/src/pages/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from "./Home"; diff --git a/app/policies/balance_policy.rb b/app/policies/balance_policy.rb new file mode 100644 index 0000000..f867bb3 --- /dev/null +++ b/app/policies/balance_policy.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +class BalancePolicy < ApplicationPolicy + class Scope < Scope + def resolve + return scope.none if user.nil? + + scope.where(user_id: user.id) + end + end +end diff --git a/db/seeds.rb b/db/seeds.rb index a60d211..3a1a6de 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -9,10 +9,208 @@ user = User.create!( password: "password" ) -currency = Currency.create!(name: "CAKE") +tokens = [ + "BNB", + "CAKE", + "CHESS", + "TITAN", + "ONE", + "MASK", + "DVI", + "ADX", + "BSCPAD", + "RABBIT", + "FORM", + "TXL", + "ORBS", + "COS", + "BUNNY", + "ALICE", + "FOR", + "BUX", + "NULS", + "BELT", + "RAMP", + "BFI", + "DEXE", + "BEL", + "TPT", + "WATCH", + "xMARK", + "bMXX", + "IOTX", + "BOR", + "bOPEN", + "DODO", + "SWINGBY", + "BRY", + "ZEE", + "SWGb", + "SWG", + "SFP", + "LINA", + "LIT", + "HGET", + "BDO", + "EGLD", + "UST", + "wSOTE", + "FRONT", + "Helmet", + "BTCST", + "BSCX", + "TEN", + "bALBT", + "ASR", + "ATM", + "OG", + "REEF", + "DITTO", + "JUV", + "PSG", + "VAI", + "wBNB", + "BLINK", + "UNFI", + "TWT", + "HARD", + "bROOBEE", + "STAX", + "NAR", + "NYA", + "CTK", + "INJ", + "SXP", + "ALPHA", + "XVS", + "SUSHI", + "COMP", + "SYRUP", + "BIFI", + "DUSK", + "BUSD", + "ETH", + "BETH", + "mAMZN", + "mGOOGL", + "mNFLX", + "mTSLA", + "LTC", + "USDC", + "DAI", + "ADA", + "BAND", + "DOT", + "EOS", + "LINK", + "USDT", + "BTCB", + "XRP", + "ATOM", + "YFII", + "XTZ", + "BCH", + "YFI", + "UNI", + "FIL", + "BAKE", + "BURGER", + "bDIGG", + "bBadger", + "TRADE", + "PNT", + "MIR", + "pBTC", + "LTO", + "pCWS", + "ZIL", + "LIEN", + "SWTH", + "DFT", + "GUM", + "DEGO", + "NRV", + "EASY", + "ODDZ", + "HOO", + "APYS", + "BONDLY", + "TKO", + "ITAM", + "ARPA", + "EPS", + "JGN", + "TLM", + "PERL", + "ALPA", + "HZN", + "SUTER", + "CGG", + "MIX", + "HAKKA", + "XED", + "τBTC", + "ALPACA", + "DFD", + "LMT", + "BTT", + "TRX", + "WIN", + "mCOIN", + "MATH", + "KUN", + "QSD", + "HYFI", + "OIN", + "DOGE", + "FINE", + "ONE", + "PMON", + "HOTCROSS", + "τDOGE", + "BTR", + "UBXT", + "WMASS", + "RFOX", + "XEND", + "CYC", + "CHR", + "KALM", + "DERI", + "WELL", + "WEX", + "WAULTx", + "pOPEN", + "EZ", + "VRT", + "TUSD", + "MTRG", + "KTN", + "QKC", + "bCFX", + "MX", + "ATA", + "MBOX", + "BORING", + "MARSH", + "AMPL", + "O3", + "HAI", + "HTB", + "WOO", + "$DG", +] -Balance.create!( - user_id: user.id, - currency_id: currency.id, - amount: 153124.72088 -) +currencies = tokens.map do |token| + Currency.create!(name: token) +end + +currencies.each do |currency| + random_floating_number = (rand * (10000 - 0) + 0) + + Balance.create!( + user_id: user.id, + currency_id: currency.id, + amount: random_floating_number + ) +end diff --git a/spec/policies/balance_policy_spec.rb b/spec/policies/balance_policy_spec.rb new file mode 100644 index 0000000..eb3c421 --- /dev/null +++ b/spec/policies/balance_policy_spec.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +require "rails_helper" + +RSpec.describe(BalancePolicy, type: :policy) do + pending "add some examples to (or delete) #{__FILE__}" +end