diff --git a/.env.example b/.env.example index 7ccb1b1b..1c50cfe9 100644 --- a/.env.example +++ b/.env.example @@ -44,3 +44,7 @@ REACT_APP_EOS_API_PROTOCOL=https REACT_APP_EOS_CHAIN_ID=2a02a0053e5a8cf73a56ba0fda11e4d92e0238a4a2aa74fccf46d5a910746840 REACT_APP_BLOCK_EXPLORER=https://jungle3.bloks.io REACT_APP_NETWORK_MONITOR_URL=https://jungle.eosio.online/ +REACT_APP_VERSION=v1.4.21 +REACT_APP_MAINNET_VERSION=v1.4.21 +REACT_APP_EDEN_CONTRACT=genesisdeden +REACT_APP_UAL_APP_NAME=EOSRate diff --git a/contracts/rateproducer/CMakeLists.txt b/contracts/rateproducer/CMakeLists.txt index 596c5afc..b302c416 100644 --- a/contracts/rateproducer/CMakeLists.txt +++ b/contracts/rateproducer/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(demo) +project(rateproducer) set(CMAKE_CXX_STANDARD 20) diff --git a/contracts/rateproducer/include/rateproducer.hpp b/contracts/rateproducer/include/rateproducer.hpp index cb9be16c..b2d4a2bf 100644 --- a/contracts/rateproducer/include/rateproducer.hpp +++ b/contracts/rateproducer/include/rateproducer.hpp @@ -25,6 +25,7 @@ #include #include #include "utils.hpp" +#include "../ricardian/rateproducer-ricardian.cpp" #define MINVAL 0 #define MAXVAL 10 @@ -43,7 +44,7 @@ using eosio::public_key; */ namespace eosio { constexpr name system_account{"eosio"_n}; - constexpr name eden_account{"genesis.eden"_n}; + constexpr name eden_account{"genesisdeden"_n}; constexpr name eden_scope{"eden"_n}; /* @@ -233,18 +234,6 @@ namespace eosio { } // namespace eosio namespace eoscostarica { - extern const char* rate_ricardian; - extern const char* erase_ricardian; - extern const char* wipe_ricardian; - extern const char* rminactive_ricardian; - extern const char* rmrate_ricardian; - - extern const char* datastorage_clause; - extern const char* datausage_clause; - extern const char* dataownership_clause; - extern const char* datadistribution_clause; - extern const char* datafuture_clause; - /* * Stores the rate average stats for a block producer */ @@ -272,6 +261,10 @@ namespace eoscostarica { ) typedef eosio::multi_index<"stats"_n, stats > stats_table; + uint128_t create_uniq_rating(const uint64_t &user, const uint64_t &bp) { + return (static_cast(user) << 64) | bp; + } + /* * Stores the rate vote for a block producer */ @@ -308,6 +301,38 @@ namespace eoscostarica { indexed_by<"bp"_n, const_mem_fun> > ratings_table; + /* + * Stores the rate vote for a block producer + */ + struct ratings_v2 { + uint64_t id; + name user; + name bp; + uint8_t transparency; + uint8_t infrastructure; + uint8_t trustiness; + uint8_t development; + uint8_t community; + uint64_t primary_key() const { return id; } + uint128_t by_uniq_rating() const { return create_uniq_rating(user.value, bp.value); } + uint64_t by_bp() const { return bp.value; } + }; + EOSIO_REFLECT( + ratings_v2, + id, + user, + bp, + transparency, + infrastructure, + trustiness, + development, + community + ) + typedef eosio::multi_index<"rating"_n, ratings_v2, + indexed_by<"uniqrating"_n, const_mem_fun>, + indexed_by<"bp"_n, const_mem_fun> + > ratings_table_v2; + /* * Stores contract config for migration versioning */ @@ -410,7 +435,7 @@ namespace eoscostarica { */ void save_bp_stats ( name scope, - name user, + name ram_payer, name bp_name, float transparency, float infrastructure, @@ -471,7 +496,7 @@ namespace eoscostarica { */ void update_bp_stats ( name scope, - name * user, + name * ram_payer, name * bp_name, float * transparency, float * infrastructure, @@ -569,19 +594,40 @@ namespace eoscostarica { /** * - * Load existing eden member rates into rateproducer scope + * NOTE: This function should be removed after migration run + * Erase a rate made for a specific account + * to a specific block producer + * + * @param scope - Table scope, + * @param user - Voter account name, + * @param bp - Block Producer account name + * + */ + void update_stats_migration(name bp); + + /** + * + * Update the current logic to newest + * + */ + void migrate(); + + /** + * + * Liberate the ram used on ratings table under rateproducer and eden scope * */ - void loadedens(); + void freeupram(); }; EOSIO_ACTIONS(rateproducer, "rateproducer"_n, - action(rate, user, bp, transparency, infrastructure, trustiness, community, development), - action(erase, bp_name), - action(wipe), - action(rminactive), - action(rmrate, user, bp), - action(loadedens)) + action(rate, user, bp, transparency, infrastructure, trustiness, community, development, ricardian_contract(rate_ricardian)), + action(erase, bp_name, ricardian_contract(erase_ricardian)), + action(wipe, ricardian_contract(wipe_ricardian)), + action(rminactive, ricardian_contract(rminactive_ricardian)), + action(rmrate, user, bp, ricardian_contract(rmrate_ricardian)), + action(migrate, ricardian_contract(migrate_ricardian)), + action(freeupram, ricardian_contract(freeupram_ricardian))) } // namespace eoscostarica \ No newline at end of file diff --git a/contracts/rateproducer/rateproducer.abi b/contracts/rateproducer/rateproducer.abi index 4bab3f41..cafb1af8 100644 --- a/contracts/rateproducer/rateproducer.abi +++ b/contracts/rateproducer/rateproducer.abi @@ -71,22 +71,23 @@ ] }, { - "name": "loadedens", + "name": "migrate", "base": "", "fields": [] }, { - "name": "ratings", + "name": "freeupram", + "base": "", + "fields": [] + }, + { + "name": "ratings_v2", "base": "", "fields": [ { "name": "id", "type": "uint64" }, - { - "name": "uniq_rating", - "type": "uint128" - }, { "name": "user", "type": "name" @@ -97,23 +98,23 @@ }, { "name": "transparency", - "type": "float32" + "type": "uint8" }, { "name": "infrastructure", - "type": "float32" + "type": "uint8" }, { "name": "trustiness", - "type": "float32" + "type": "uint8" }, { "name": "development", - "type": "float32" + "type": "uint8" }, { "name": "community", - "type": "float32" + "type": "uint8" } ] }, @@ -165,7 +166,7 @@ { "name": "erase", "type": "erase", - "ricardian_contract": "---\spec_version: 0.1.0\ntitle: Erase Block Producer Stats\nsummary: The intent of the `{{ erase }}` action is to provide a ways to clear all data related with a specific block producer.\n---" + "ricardian_contract": "---\nspec_version: 0.1.0\ntitle: Erase Block Producer Stats\nsummary: The intent of the `{{ erase }}` action is to provide a ways to clear all data related with a specific block producer.\n---" }, { "name": "wipe", @@ -183,18 +184,23 @@ "ricardian_contract": "---\nspec_version: 0.1.0\ntitle: Remove a especific rate\nsummary: The intent of the `{{ rmrate }}` action is to remove a rate made from an especific account.\n---" }, { - "name": "loadedens", - "type": "loadedens", - "ricardian_contract": "---\nspec_version: 0.1.0\ntitle: Load existing eden members\nsummary: The intent of the `{{ loadedens }}` action is to migrate and load existing rates made by eden members into eden scope.\n---" + "name": "migrate", + "type": "migrate", + "ricardian_contract": "---\nspec_version: 0.1.0\ntitle: Update the current logic to newest\nsummary: The intent of the `{{ migrate }}` action is to update the current logic to newest.\n---" + }, + { + "name": "freeupram", + "type": "freeupram", + "ricardian_contract": "---\nspec_version: 0.1.0\ntitle: Free up RAM\nsummary: The intent of the `{{ freeupram }}` action is to remove all records from old ratings table including the rateproducer and eden scope.\n---" } ], "tables": [ { - "name": "ratings", + "name": "rating", "index_type": "i64", "key_names": [], "key_types": [], - "type": "ratings" + "type": "ratings_v2" }, { "name": "stats", @@ -206,23 +212,23 @@ ], "ricardian_clauses": [ { - "id": "Data Storage", - "body": "The affiliate application values the security of personal data. We may process only minimal user data as much as it is necessary to maintain the affiliate application running. We only receive and store any information you knowingly provide to us when you create an account, or fill using the app." + "id": "datastorage", + "body": "The rateproducer application values the security of personal data. We may process only minimal user data as much as it is necessary to maintain the rateproducer application running. We only receive and store any information you knowingly provide to us when you create an account, or fill using the app." }, { - "id": "Data Usage", - "body": "This smart contract will process user data to keep the affiliate application running. Any of the information we collect from you may be used for these purposes:\n - Create and manage user accounts.\n - Run and operate the affiliate application." + "id": "datausage", + "body": "This smart contract will process user data to keep the rateproducer application running. Any of the information we collect from you may be used for these purposes:\n- Create and manage user accounts.\n- Run and operate the rateproducer application." }, { - "id": "Data Ownership", - "body": "The user of this smart contract verifies that the smart contract owns the data and that it can use the data in accordance with the terms defined in the Ricardian contract.\nYou can delete certain personal information you shared with the affiliate application. When you delete personal information, we may maintain a copy of the unrevised personal information in our records for the duration necessary to comply with our obligations to our affiliates and partners, and for the purposes described below. If you would like to delete your personal information or permanently delete your account, you can do so on your account's profile page in the affiliate application.\nWe will retain and use your personal information for the period necessary to comply with our legal obligations, resolve disputes, and enforce our agreements unless a more extended retention period is required or permitted by law. We may use any aggregated data derived from or incorporating your personal information after you update or delete it, but not in a manner that would identify you personally. Once the retention period expires, personal information shall be deleted." + "id": "dataownership", + "body": "The user of this smart contract verifies that the smart contract owns the data and that it can use the data in accordance with the terms defined in the Ricardian contract.\nYou can delete certain personal information you shared with the rateproducer application. When you delete personal information, we may maintain a copy of the unrevised personal information in our records for the duration necessary to comply with our obligations to our affiliates and partners, and for the purposes described below. If you would like to delete your personal information or permanently delete your account, you can do so on your account's profile page in the rateproducer application.\nWe will retain and use your personal information for the period necessary to comply with our legal obligations, resolve disputes, and enforce our agreements unless a more extended retention period is required or permitted by law. We may use any aggregated data derived from or incorporating your personal information after you update or delete it, but not in a manner that would identify you personally. Once the retention period expires, personal information shall be deleted." }, { - "id": "Data Distribution", - "body": "The smart contract promises not actively to share or distribute the address data. The smart contract user understands that data stored in a multi-index table is not private and can be accessed by any user of the blockchain.\nDepending on your location, data transfers may involve transferring and storing your information in a country other than your own. Moreover, to keep affiliate running, we must share necessary personal data such as your name with the authorized blood donation centers and sponsors. We do not store any information regarding your blood type, health conditions, or any other confidential information between you and the donation centers." + "id": "datadistribution", + "body": "The smart contract promises not actively to share or distribute the address data. The smart contract user understands that data stored in a multi-index table is not private and can be accessed by any user of the blockchain.\nDepending on your location, data transfers may involve transferring and storing your information in a country other than your own. Moreover, to keep rateproducer running, we must share necessary personal data such as your name with the authorized blood donation centers and sponsors. We do not store any information regarding your blood type, health conditions, or any other confidential information between you and the donation centers." }, { - "id": "Data Future", + "id": "datafuture", "body": "The smart contract promises to only use the data following the terms defined in the Ricardian contract, now and at all future dates. You may exercise certain rights regarding your information processed by us. In particular, you have the right to do the following: (i) you have the right to withdraw consent where you have previously given your consent to the processing of your information; (ii) you have the right to object to the processing of your information if the processing is carried out on a legal basis other than consent; (iii) you have the right to learn if information is being processed by us, obtain disclosure regarding certain aspects of the processing and obtain a copy of the information undergoing processing; (iv) you have the right to verify the accuracy of your information and ask for it to be updated or corrected; (v) you have the right, under certain circumstances, to restrict the processing of your information, in which case, we will not process your information for any purpose other than storing it; (vi) you have the right, under certain circumstances, to obtain the erasure of your Personal Information from us; (vii) you have the right to receive your information in a structured, commonly used and machine readable format and, if technically feasible, to have it transmitted to another controller without any hindrance. This provision is applicable provided that your information is processed by automated means and that the processing is based on your consent, on a contract you are part of or on pre-contractual obligations thereof." } ], diff --git a/contracts/rateproducer/rateproducer.wasm b/contracts/rateproducer/rateproducer.wasm index 2c7b11e1..f65a49c3 100755 Binary files a/contracts/rateproducer/rateproducer.wasm and b/contracts/rateproducer/rateproducer.wasm differ diff --git a/contracts/rateproducer/ricardian/rateproducer-ricardian.cpp b/contracts/rateproducer/ricardian/rateproducer-ricardian.cpp index 9aaa4b26..57b94d96 100644 --- a/contracts/rateproducer/ricardian/rateproducer-ricardian.cpp +++ b/contracts/rateproducer/ricardian/rateproducer-ricardian.cpp @@ -1,70 +1,61 @@ -#include "../include/rateproducer.hpp" - - -// CONTRACTS -const char* eoscostarica::rate_ricardian = R"( -spec-version: 0.1.0 +namespace eoscostarica { + // CONTRACTS + const char* rate_ricardian = R"(--- +spec_version: 0.1.0 title: Rate a block producer summary: The intent of the `{{ rate }}` action is to allow the `issuer` account to rate a blockproducer into five categories: Community, Development, Infraestructure, Transparency, Trustiness. -)"; +---)"; -const char* eoscostarica::erase_ricardian = R"( -spec-version: 0.1.0 + const char* erase_ricardian = R"(--- +spec_version: 0.1.0 title: Erase Block Producer Stats summary: The intent of the `{{ erase }}` action is to provide a ways to clear all data related with a specific block producer. -)"; +---)"; -const char* eoscostarica::wipe_ricardian = R"( -spec-version: 0.1.0 + const char* wipe_ricardian = R"(--- +spec_version: 0.1.0 title: Wipe all contract's tables summary: The intent of the `{{ wipe }}` action is to provide a way to release the stored data within the contract. -)"; +---)"; -const char* eoscostarica::rminactive_ricardian = R"( -spec-version: 0.1.0 + const char* rminactive_ricardian = R"(--- +spec_version: 0.1.0 title: Erase innactive Block Producer summary: The intent of the `{{ rminactive }}` action is to provide a method to purge stats related with inactive block producers. -)"; +---)"; -const char* eoscostarica::rmrate_ricardian = R"( -spec-version: 0.1.0 + const char* rmrate_ricardian = R"(--- +spec_version: 0.1.0 title: Remove a especific rate -summary: The intent of the `{{ rmrate }}` action is remove a rate made from an especific account. -)"; +summary: The intent of the `{{ rmrate }}` action is to remove a rate made from an especific account. +---)"; + +const char* migrate_ricardian = R"(--- +spec_version: 0.1.0 +title: Update the current logic to newest +summary: The intent of the `{{ migrate }}` action is to update the current logic to newest. +---)"; + +const char* freeupram_ricardian = R"(--- +spec_version: 0.1.0 +title: Free up RAM +summary: The intent of the `{{ freeupram }}` action is to remove all records from old ratings table including the rateproducer and eden scope. +---)"; -// CLAUSES -const char* eoscostarica::datastorage_clause = R"( -spec-version: 0.1.0 -title: General Data Storage -summary: The rateproducer application values the security of personal data. We may process only minimal user data as much as it is necessary to maintain the rateproducer application running. We only receive and store any information you knowingly provide to us when you create an account, or fill using the app. -)"; + // CLAUSES + const char* datastorage_clause = R"(The rateproducer application values the security of personal data. We may process only minimal user data as much as it is necessary to maintain the rateproducer application running. We only receive and store any information you knowingly provide to us when you create an account, or fill using the app.)"; -const char* eoscostarica::datausage_clause = R"( -spec-version: 0.1.0 -title: General Data Use -summary: This smart contract will process user data to keep the rateproducer application running. Any of the information we collect from you may be used for these purposes: - - Create and manage user accounts. - - Run and operate the rateproducer application. -)"; + const char* datausage_clause = R"(This smart contract will process user data to keep the rateproducer application running. Any of the information we collect from you may be used for these purposes: +- Create and manage user accounts. +- Run and operate the rateproducer application.)"; -const char* eoscostarica::dataownership_clause = R"( -spec-version: 0.1.0 -title: Data Ownership -summary: The user of this smart contract verifies that the smart contract owns the data and that it can use the data in accordance with the terms defined in the Ricardian contract. + const char* dataownership_clause = R"(The user of this smart contract verifies that the smart contract owns the data and that it can use the data in accordance with the terms defined in the Ricardian contract. You can delete certain personal information you shared with the rateproducer application. When you delete personal information, we may maintain a copy of the unrevised personal information in our records for the duration necessary to comply with our obligations to our affiliates and partners, and for the purposes described below. If you would like to delete your personal information or permanently delete your account, you can do so on your account's profile page in the rateproducer application. -We will retain and use your personal information for the period necessary to comply with our legal obligations, resolve disputes, and enforce our agreements unless a more extended retention period is required or permitted by law. We may use any aggregated data derived from or incorporating your personal information after you update or delete it, but not in a manner that would identify you personally. Once the retention period expires, personal information shall be deleted. -)"; +We will retain and use your personal information for the period necessary to comply with our legal obligations, resolve disputes, and enforce our agreements unless a more extended retention period is required or permitted by law. We may use any aggregated data derived from or incorporating your personal information after you update or delete it, but not in a manner that would identify you personally. Once the retention period expires, personal information shall be deleted.)"; -const char* eoscostarica::datadistribution_clause = R"( -spec-version: 0.1.0 -title: Data Distribution -summary: The smart contract promises not actively to share or distribute the address data. The smart contract user understands that data stored in a multi-index table is not private and can be accessed by any user of the blockchain. -Depending on your location, data transfers may involve transferring and storing your information in a country other than your own. Moreover, to keep rateproducer running, we must share necessary personal data such as your name with the authorized blood donation centers and sponsors. We do not store any information regarding your blood type, health conditions, or any other confidential information between you and the donation centers. -)"; + const char* datadistribution_clause = R"(The smart contract promises not actively to share or distribute the address data. The smart contract user understands that data stored in a multi-index table is not private and can be accessed by any user of the blockchain. +Depending on your location, data transfers may involve transferring and storing your information in a country other than your own. Moreover, to keep rateproducer running, we must share necessary personal data such as your name with the authorized blood donation centers and sponsors. We do not store any information regarding your blood type, health conditions, or any other confidential information between you and the donation centers.)"; -const char* eoscostarica::datafuture_clause = R"( -spec-version: 0.1.0 -title: Data Future -summary: The smart contract promises to only use the data following the terms defined in the Ricardian contract, now and at all future dates. You may exercise certain rights regarding your information processed by us. In particular, you have the right to do the following: (i) you have the right to withdraw consent where you have previously given your consent to the processing of your information; (ii) you have the right to object to the processing of your information if the processing is carried out on a legal basis other than consent; (iii) you have the right to learn if information is being processed by us, obtain disclosure regarding certain aspects of the processing and obtain a copy of the information undergoing processing; (iv) you have the right to verify the accuracy of your information and ask for it to be updated or corrected; (v) you have the right, under certain circumstances, to restrict the processing of your information, in which case, we will not process your information for any purpose other than storing it; (vi) you have the right, under certain circumstances, to obtain the erasure of your Personal Information from us; (vii) you have the right to receive your information in a structured, commonly used and machine readable format and, if technically feasible, to have it transmitted to another controller without any hindrance. This provision is applicable provided that your information is processed by automated means and that the processing is based on your consent, on a contract you are part of or on pre-contractual obligations thereof. -)"; \ No newline at end of file + const char* datafuture_clause = R"(The smart contract promises to only use the data following the terms defined in the Ricardian contract, now and at all future dates. You may exercise certain rights regarding your information processed by us. In particular, you have the right to do the following: (i) you have the right to withdraw consent where you have previously given your consent to the processing of your information; (ii) you have the right to object to the processing of your information if the processing is carried out on a legal basis other than consent; (iii) you have the right to learn if information is being processed by us, obtain disclosure regarding certain aspects of the processing and obtain a copy of the information undergoing processing; (iv) you have the right to verify the accuracy of your information and ask for it to be updated or corrected; (v) you have the right, under certain circumstances, to restrict the processing of your information, in which case, we will not process your information for any purpose other than storing it; (vi) you have the right, under certain circumstances, to obtain the erasure of your Personal Information from us; (vii) you have the right to receive your information in a structured, commonly used and machine readable format and, if technically feasible, to have it transmitted to another controller without any hindrance. This provision is applicable provided that your information is processed by automated means and that the processing is based on your consent, on a contract you are part of or on pre-contractual obligations thereof.)"; +} \ No newline at end of file diff --git a/contracts/rateproducer/src/rateproducer.cpp b/contracts/rateproducer/src/rateproducer.cpp index d87ad90d..5466a683 100644 --- a/contracts/rateproducer/src/rateproducer.cpp +++ b/contracts/rateproducer/src/rateproducer.cpp @@ -1,6 +1,5 @@ #include "../include/rateproducer.hpp" - namespace eoscostarica { void rateproducer::rate( name user, @@ -11,8 +10,8 @@ namespace eoscostarica { int8_t community, int8_t development) { require_auth(user); - rate_aux(_self, user, bp, transparency, infrastructure, trustiness, community, development); - if(is_eden(user)) rate_aux(eden_scope, user, bp, transparency, infrastructure, trustiness, community, development); + name scope = is_eden(user) ? eden_scope : _self; + rate_aux(scope, user, bp, transparency, infrastructure, trustiness, community, development); } void rateproducer::rate_aux( @@ -24,31 +23,27 @@ namespace eoscostarica { int8_t trustiness, int8_t community, int8_t development) { - check( (transparency+infrastructure+trustiness+community+development), "Error vote must have value for at least one category"); - check( (MINVAL<= transparency && transparency<=MAXVAL ), "Error transparency value out of range"); - check( (MINVAL<= infrastructure && infrastructure<=MAXVAL ), "Error infrastructure value out of range" ); - check( (MINVAL<= trustiness && trustiness<=MAXVAL ), "Error trustiness value out of range" ); - check( (MINVAL<= development && development <=MAXVAL ), "Error development value out of range" ); - check( (MINVAL<= community && community<=MAXVAL ), "Error community value out of range" ); + check( (transparency + infrastructure + trustiness + community + development), "Error vote must have value for at least one category" ); + check( (MINVAL <= transparency && transparency <= MAXVAL), "Error transparency value out of range" ); + check( (MINVAL <= infrastructure && infrastructure <= MAXVAL), "Error infrastructure value out of range" ); + check( (MINVAL <= trustiness && trustiness <= MAXVAL), "Error trustiness value out of range" ); + check( (MINVAL <= development && development <= MAXVAL), "Error development value out of range" ); + check( (MINVAL <= community && community <= MAXVAL), "Error community value out of range" ); - bool isEden = is_eden(user); + bool isEden = scope.value == eden_scope.value; + name stats_ram_payer = isEden ? _self : user; - // checks if the bp is active check( is_blockproducer(bp), "votes are allowed only for registered block producers" ); - eosio::name proxy_name = get_proxy(user); + name proxy_name = get_proxy(user); if(proxy_name.length()) { - // active proxy?? check(is_active_proxy(proxy_name), "votes are allowed only for active proxies" ); - // account votes through a proxy if(!isEden) check( MIN_VOTERS <= get_voters(proxy_name), "delegated proxy does not have enough voters" ); } else { - // acount must vote for at least 21 bp if(!isEden) check( MIN_VOTERS <= get_voters(user), "account does not have enough voters" ); } - // upsert bp rating - ratings_table _ratings(_self, scope.value); + ratings_table_v2 _ratings(_self, scope.value); auto uniq_rating = (static_cast(user.value) << 64) | bp.value; auto uniq_rating_index = _ratings.get_index(); @@ -57,18 +52,17 @@ namespace eoscostarica { if( existing_rating == uniq_rating_index.end() ) { _ratings.emplace(user, [&]( auto& row ) { row.id = _ratings.available_primary_key(); - row.uniq_rating = uniq_rating; row.user = user; row.bp = bp; row.transparency = transparency; row.infrastructure = infrastructure; row.trustiness = trustiness; row.community = community; - row.development = development ; + row.development = development; }); - //save stats + save_bp_stats(scope, - user, + stats_ram_payer, bp, transparency, infrastructure, @@ -76,26 +70,22 @@ namespace eoscostarica { community, development); - } else { - //the voter update its vote uniq_rating_index.modify(existing_rating, user, [&]( auto& row ) { - row.user = user; - row.bp = bp; row.transparency = transparency; row.infrastructure = infrastructure; row.trustiness = trustiness; row.community = community; row.development = development ; }); - //update bp stats + float bp_transparency = 0; float bp_infrastructure = 0; float bp_trustiness = 0; float bp_community = 0; float bp_development = 0; - uint32_t bp_ratings_cntr = 0; - float bp_average = 0; + uint32_t bp_ratings_cntr = 0; + float bp_average = 0; calculate_bp_stats (scope, bp, &bp_transparency, @@ -106,7 +96,7 @@ namespace eoscostarica { &bp_ratings_cntr, &bp_average); update_bp_stats (scope, - &user, + &stats_ram_payer, &bp, &bp_transparency, &bp_infrastructure, @@ -120,7 +110,7 @@ namespace eoscostarica { void rateproducer::save_bp_stats ( name scope, - name user, + name ram_payer, name bp_name, float transparency, float infrastructure, @@ -133,7 +123,7 @@ namespace eoscostarica { float sum = 0; if(itr == _stats.end()) { //new entry - _stats.emplace(user, [&]( auto& row ) { + _stats.emplace(ram_payer, [&]( auto& row ) { if (transparency) { row.transparency = transparency; counter++; @@ -173,7 +163,7 @@ namespace eoscostarica { }); } else { //update the entry - _stats.modify(itr, user, [&]( auto& row ) { + _stats.modify(itr, ram_payer, [&]( auto& row ) { if (transparency) { sum += transparency; if(row.transparency) { @@ -253,7 +243,7 @@ namespace eoscostarica { float development_cntr = 0; uint32_t voters_cntr = 0; - ratings_table _ratings(_self, scope.value); + ratings_table_v2 _ratings(_self, scope.value); auto bps_index = _ratings.get_index(); auto bps_it = bps_index.find(bp_name.value); @@ -318,7 +308,7 @@ namespace eoscostarica { void rateproducer::update_bp_stats ( name scope, - name * user, + name * ram_payer, name * bp_name, float * transparency, float * infrastructure, @@ -339,7 +329,7 @@ namespace eoscostarica { *community + *development) { - _stats.modify(itr,*user, [&]( auto& row ) { + _stats.modify(itr,*ram_payer, [&]( auto& row ) { row.transparency = *transparency; row.infrastructure = *infrastructure; row.trustiness = *trustiness; @@ -363,7 +353,7 @@ namespace eoscostarica { require_auth(_self); - ratings_table _ratings(_self, scope.value); + ratings_table_v2 _ratings(_self, scope.value); auto itr = _ratings.begin(); while (itr != _ratings.end()) { if(itr->bp == bp_name) { @@ -386,7 +376,7 @@ namespace eoscostarica { void rateproducer::wipe_aux(name scope) { require_auth(_self); - ratings_table _ratings(_self, scope.value); + ratings_table_v2 _ratings(_self, scope.value); auto itr = _ratings.begin(); while (itr != _ratings.end()) { itr = _ratings.erase(itr); @@ -400,7 +390,7 @@ namespace eoscostarica { } void rateproducer::erase_bp_info(name scope, std::set * bps_to_clean) { - ratings_table _ratings(_self, scope.value); + ratings_table_v2 _ratings(_self, scope.value); stats_table _stats(_self, scope.value); std::set::iterator it; @@ -441,14 +431,13 @@ namespace eoscostarica { } void rateproducer::rmrate(name user, name bp) { - rmrate_aux(_self, user, bp); - if(is_eden(user)) rmrate_aux(eden_scope, user, bp); + require_auth(user); + name scope = is_eden(user) ? eden_scope : _self; + rmrate_aux(scope, user, bp); } void rateproducer::rmrate_aux(name scope, name user, name bp) { - require_auth(user); - - ratings_table _ratings(_self, scope.value); + ratings_table_v2 _ratings(_self, scope.value); auto uniq_rating = (static_cast(user.value) << 64) | bp.value; auto uniq_rating_index = _ratings.get_index(); @@ -492,42 +481,117 @@ namespace eoscostarica { &bp_average); } - void rateproducer::loadedens() { + void rateproducer::update_stats_migration(name bp) { + name default_scope = _self; + name ram_payer = _self; + + //update bp stats + float bp_transparency = 0; + float bp_infrastructure = 0; + float bp_trustiness = 0; + float bp_community = 0; + float bp_development = 0; + uint32_t bp_ratings_cntr = 0; + float bp_average = 0; + + //re-calculate stats for the bp + calculate_bp_stats (default_scope, + bp, + &bp_transparency, + &bp_infrastructure, + &bp_trustiness, + &bp_community, + &bp_development, + &bp_ratings_cntr, + &bp_average); + + float totalStats = + bp_transparency + + bp_infrastructure + + bp_trustiness + + bp_community + + bp_development; + + name stats_ram_payer =_self; + stats_table _stats(_self, default_scope.value); + auto itr = _stats.find(bp.value); + if(itr != _stats.end()) { + if(totalStats) { + _stats.modify(itr, stats_ram_payer, [&]( auto& row ) { + row.transparency = bp_transparency; + row.infrastructure = bp_infrastructure; + row.trustiness = bp_trustiness; + row.development = bp_community; + row.community = bp_development; + row.ratings_cntr = bp_ratings_cntr; + row.average = bp_average; + }); + } else _stats.erase(itr); + } else { + if(totalStats) { + _stats.emplace(stats_ram_payer, [&]( auto& row ) { + row.bp = bp; + row.transparency = bp_transparency; + row.infrastructure = bp_infrastructure; + row.trustiness = bp_trustiness; + row.development = bp_community; + row.community = bp_development; + row.ratings_cntr = bp_ratings_cntr; + row.average = bp_average; + }); + } + } + } + + void rateproducer::migrate() { config c = cfg.get_or_create(_self, config{.owner = _self, .version = 0}); require_auth(c.owner); - // assert we only run once // the comparison value needs to be hard-coded with each new migration - eosio::check(c.version < 1, "Migration already ran"); - + eosio::check(c.version < 2, "Migration already ran"); ratings_table _ratings_self(_self, _self.value); - ratings_table _ratings_eden(_self, eden_scope.value); - + ratings_table_v2 _ratings_self_v2(_self, _self.value); + ratings_table_v2 _ratings_eden_v2(_self, eden_scope.value); for(auto itr = _ratings_self.begin(); itr != _ratings_self.end(); itr++) { - if(is_eden(itr->user)) { - _ratings_eden.emplace(_self, [&]( auto& row ) { - row.id = itr->id; - row.uniq_rating = itr->uniq_rating; - row.user = itr->user; - row.bp = itr->bp; - row.transparency = itr->transparency; - row.infrastructure = itr->infrastructure; - row.trustiness = itr->trustiness; - row.community = itr->community; - row.development = itr->development ; - }); - //save stats - save_bp_stats(eden_scope, - _self, - itr->bp, - itr->transparency, - itr->infrastructure, - itr->trustiness, - itr->community, - itr->development); - } + auto emplace_rating = [&]( auto& row ) -> auto { + row.id = itr->id; + row.user = itr->user; + row.bp = itr->bp; + row.transparency = itr->transparency; + row.infrastructure = itr->infrastructure; + row.trustiness = itr->trustiness; + row.community = itr->community; + row.development = itr->development; + }; + + name temp_scope = is_eden(itr->user) ? eden_scope : _self; + if(temp_scope.value == eden_scope.value) _ratings_eden_v2.emplace(_self, emplace_rating); + else _ratings_self_v2.emplace(_self, emplace_rating); + update_stats_migration(itr->bp); + } + + c.version++; + cfg.set(c, c.owner); + } + + void rateproducer::freeupram() { + config c = cfg.get_or_create(_self, config{.owner = _self, .version = 0}); + require_auth(_self); + + eosio::check(c.version < 3, "Make sure to run `migrate` action before run this action"); + + ratings_table _ratings_general(_self, _self.value); + auto general_itr = _ratings_general.begin(); + while (general_itr != _ratings_general.end()) { + general_itr = _ratings_general.erase(general_itr); } + ratings_table _ratings_eden(_self, eden_scope.value); + auto eden_itr = _ratings_eden.begin(); + while (eden_itr != _ratings_eden.end()) { + eden_itr = _ratings_eden.erase(eden_itr); + } + c.version++; cfg.set(c, c.owner); } @@ -536,6 +600,13 @@ namespace eoscostarica { EOSIO_ACTION_DISPATCHER(eoscostarica::actions) -EOSIO_ABIGEN(actions(eoscostarica::actions), - table("ratings"_n, eoscostarica::ratings), - table("stats"_n, eoscostarica::stats)) \ No newline at end of file +EOSIO_ABIGEN( + actions(eoscostarica::actions), + table("rating"_n, eoscostarica::ratings_v2), + table("stats"_n, eoscostarica::stats), + ricardian_clause("datastorage", eoscostarica::datastorage_clause), + ricardian_clause("datausage", eoscostarica::datausage_clause), + ricardian_clause("dataownership", eoscostarica::dataownership_clause), + ricardian_clause("datadistribution", eoscostarica::datadistribution_clause), + ricardian_clause("datafuture", eoscostarica::datafuture_clause) +) \ No newline at end of file diff --git a/hapi/src/config/server.config.js b/hapi/src/config/server.config.js index 79a4fd5f..6f8b9c28 100644 --- a/hapi/src/config/server.config.js +++ b/hapi/src/config/server.config.js @@ -1,8 +1,7 @@ - module.exports = { host: process.env.HAPI_POSTGRES_HOST || 'postgres', port: process.env.HAPI_POSTGRES_PORT || 5432, database: process.env.HAPI_POSTGRES_DB || 'eosrate', user: process.env.HAPI_POSTGRES_USER || 'eoscr', password: process.env.HAPI_POSTGRES_PASSWORD || 'password' -} \ No newline at end of file +} diff --git a/hapi/src/index.js b/hapi/src/index.js index aa1f6017..1a705087 100644 --- a/hapi/src/index.js +++ b/hapi/src/index.js @@ -16,7 +16,7 @@ const init = async () => { server.route({ method: 'GET', path: '/', - handler: function() { + handler: function () { return '

EOS Rate HTTP API service

' } }) @@ -24,7 +24,7 @@ const init = async () => { server.route({ method: 'POST', path: '/ratebp', - handler: async req => { + handler: async (req) => { try { const { payload: { input } @@ -33,7 +33,7 @@ const init = async () => { if (!input) throw new Error('Invalid ratebp Input') const { - ratingInput: { user, producer, transaction } + ratingInput: { user, producer, transaction, isEden } } = input const isValidAccountName = accountValidation([ { name: user, type: 'user account' }, @@ -44,7 +44,12 @@ const init = async () => { throw new Error(isValidAccountName.message) const resultEden = await updateBpStats(producer) - const result = await updateUserRatings(user, producer, transaction) + const result = await updateUserRatings( + user, + producer, + transaction, + isEden + ) return { resultEden: resultEden, ...result } } catch (error) { @@ -57,10 +62,12 @@ const init = async () => { await server.start() console.log(`🚀 Server ready at ${server.info.uri}`) - server.table().forEach(route => console.log(`${route.method}\t${route.path}`)) + server + .table() + .forEach((route) => console.log(`${route.method}\t${route.path}`)) } -process.on('unhandledRejection', err => { +process.on('unhandledRejection', (err) => { console.log(err) process.exit(1) }) diff --git a/hapi/src/libs/sync-bps.js b/hapi/src/libs/sync-bps.js index 3e0e0a16..7ce7d565 100644 --- a/hapi/src/libs/sync-bps.js +++ b/hapi/src/libs/sync-bps.js @@ -47,7 +47,8 @@ const getBlockProducersData = async () => { { owner: producer.owner, system: { ...producer }, - bpJson: {} + bpJson: {}, + candidateName: null } ] }, []) @@ -65,6 +66,9 @@ const getBlockProducersData = async () => { }) if (bp['producer_account_name'] && bp['producer_account_name'] !== '') { producer['bpJson'] = bp + producer['candidateName'] = bp.org + ? (bp.org.candidate_name || '').toLowerCase() + : null producersBPJSON.push(producer) } } catch (err) { @@ -83,8 +87,8 @@ const updateBlockProducersData = async () => { const producersData = await getBlockProducersData() producersData.forEach(async (bp) => { - const { owner, system, bpJson: bpjson } = bp - const bpData = { owner, system, bpjson } + const { owner, system, bpJson: bpjson, candidateName } = bp + const bpData = { owner, system, bpjson, candidate_name: candidateName } try { const saveBPResult = await (await massiveDB).producers.save(bpData) diff --git a/hapi/src/libs/sync-proxies.js b/hapi/src/libs/sync-proxies.js index 49943fe6..d3a7e9a6 100644 --- a/hapi/src/libs/sync-proxies.js +++ b/hapi/src/libs/sync-proxies.js @@ -4,10 +4,10 @@ const EosApi = require('eosjs-api') const fetch = require('node-fetch') const { massiveDB } = require('../config') -const HAPI_EOS_API_ENDPOINT = process.env.HAPI_EOS_API_ENDPOINT || 'https://jungle.eosio.cr' +const HAPI_EOS_API_ENDPOINT = + process.env.HAPI_EOS_API_ENDPOINT || 'https://jungle.eosio.cr' const HAPI_PROXY_CONTRACT = process.env.HAPI_PROXY_CONTRACT || 'proxyaccount' - const getProxiesData = async () => { console.log('==== Updating proxies ====') const eos = new JsonRpc(HAPI_EOS_API_ENDPOINT, { fetch }) @@ -19,7 +19,7 @@ const getProxiesData = async () => { let proxies try { - ({rows: proxies} = await eos.get_table_rows({ + ;({ rows: proxies } = await eos.get_table_rows({ json: true, code: HAPI_PROXY_CONTRACT, scope: HAPI_PROXY_CONTRACT, @@ -28,7 +28,7 @@ const getProxiesData = async () => { reverse: false, show_payer: false })) - } catch (err) { + } catch (err) { console.log(`Database connection error ${err}`) return [] } @@ -38,11 +38,25 @@ const getProxiesData = async () => { if (account && account.voter_info && account.voter_info.is_proxy) { proxy.voter_info = account.voter_info + try { - const resultProxySave = await (await massiveDB).proxies.save(proxy) - const dbResult = resultProxySave ? resultProxySave : await (await massiveDB).proxies.insert(proxy) - console.log(`Save or insert of ${proxy.owner} was ${dbResult ? 'SUCCESSFULL' : 'UNSUCCESSFULL'}`) - } catch (err) { console.log(`Error: ${err}`) } + const resultProxySave = await ( + await massiveDB + ).proxies.save({ + ...proxy, + filter_name: (proxy.name || null).toLowerCase() + }) + const dbResult = resultProxySave + ? resultProxySave + : await (await massiveDB).proxies.insert(proxy) + console.log( + `Save or insert of ${proxy.owner} was ${ + dbResult ? 'SUCCESSFULL' : 'UNSUCCESSFULL' + }` + ) + } catch (err) { + console.log(`Error: ${err}`) + } } else console.log(`${proxy.owner} is not a proxy`) }) } diff --git a/hapi/src/libs/sync-ratings.js b/hapi/src/libs/sync-ratings.js index 9cf9654d..f8d0b9ac 100644 --- a/hapi/src/libs/sync-ratings.js +++ b/hapi/src/libs/sync-ratings.js @@ -1,39 +1,43 @@ #!/usr/bin/env node const { JsonRpc } = require('eosjs') const fetch = require('node-fetch') -const { massiveDB } = require('../config') +const { + generalContractScope, + edenContractScope, + massiveDB +} = require('../config') -const HAPI_EOS_API_ENDPOINT = process.env.HAPI_EOS_API_ENDPOINT || 'https://jungle.eosio.cr' +const HAPI_EOS_API_ENDPOINT = + process.env.HAPI_EOS_API_ENDPOINT || 'https://jungle.eosio.cr' const HAPI_RATING_CONTRACT = process.env.HAPI_RATING_CONTRACT || 'rateproducer' -const getUserRatings = async () => { +const getUserRatings = async (scope) => { const eos = new JsonRpc(HAPI_EOS_API_ENDPOINT, { fetch }) try { const ratings = await eos.get_table_rows({ json: true, code: HAPI_RATING_CONTRACT, - scope: HAPI_RATING_CONTRACT, - table: 'ratings', + scope: scope, + table: 'rating', limit: 1000, reverse: false, show_payer: false }) return ratings - } catch (err) { + } catch (err) { console.log(`Database connection error ${err}`) return [] } } -const updateUserRatings = async () => { - console.log('==== Updating ratings ====') - const userRatings = await getUserRatings() +const updateUserRatingsAux = async (scope) => { + console.log(`==== Updating ratings for ${scope} ====`) + const userRatings = await getUserRatings(scope) userRatings.rows.forEach(async (rating) => { const ratingsCore = { - uniq_rating: rating.uniq_rating, user: rating.user, bp: rating.bp, ratings: { @@ -46,11 +50,26 @@ const updateUserRatings = async () => { } try { - const resultRatingsSave = await (await massiveDB).user_ratings.save(ratingsCore) - const dbResult = resultRatingsSave ? resultRatingsSave : await (await massiveDB).user_ratings.insert(ratingsCore) - console.log(`Save or insert of ${ratingsCore.uniq_rating} was ${dbResult ? 'SUCCESSFULL' : 'UNSUCCESSFULL'}`) - } catch (err) { console.log(`Error: ${err}`) } + const resultRatingsSave = await ( + await massiveDB + ).user_ratings.save(ratingsCore) + const dbResult = resultRatingsSave + ? resultRatingsSave + : await (await massiveDB).user_ratings.insert(ratingsCore) + console.log( + `Save or insert of ${ratingsCore.user}-${ratingsCore.bp} was ${ + dbResult ? 'SUCCESSFULL' : 'UNSUCCESSFULL' + }` + ) + } catch (err) { + console.log(`Error: ${err}`) + } }) -}; +} + +const updateUserRatings = () => { + updateUserRatingsAux(generalContractScope) + updateUserRatingsAux(edenContractScope) +} -updateUserRatings() +updateUserRatings() \ No newline at end of file diff --git a/hapi/src/libs/sync-user-rating.js b/hapi/src/libs/sync-user-rating.js index a2273c61..f11c5765 100644 --- a/hapi/src/libs/sync-user-rating.js +++ b/hapi/src/libs/sync-user-rating.js @@ -4,18 +4,19 @@ const fetch = require('node-fetch') const { massiveDB } = require('../config') -const HAPI_EOS_API_ENDPOINT = process.env.HAPI_EOS_API_ENDPOINT || 'https://jungle.eosio.cr' +const HAPI_EOS_API_ENDPOINT = + process.env.HAPI_EOS_API_ENDPOINT || 'https://jungle.eosio.cr' const HAPI_RATING_CONTRACT = process.env.HAPI_RATING_CONTRACT || 'rateproducer' // gets data from blockchain -const getUserRatings = async () => { +const getUserRatings = async (isEden) => { const eos = new JsonRpc(HAPI_EOS_API_ENDPOINT, { fetch }) let ratings = await eos.get_table_rows({ json: true, code: HAPI_RATING_CONTRACT, - scope: HAPI_RATING_CONTRACT, - table: 'ratings', + scope: isEden ? 'eden' : HAPI_RATING_CONTRACT, + table: 'rating', limit: 1000, reverse: false, show_payer: false @@ -24,11 +25,16 @@ const getUserRatings = async () => { } // updates the postgresdb -const updateUserRatings = async (userAccount, bpAccount, transaction) => { +const updateUserRatings = async ( + userAccount, + bpAccount, + transaction, + isEden +) => { console.log('==== Updating user ratings ====') try { - const userRatings = await getUserRatings() + const userRatings = await getUserRatings(isEden) if (!userAccount || !bpAccount) throw new Error('User Account and Block Producer owner are required!') @@ -47,8 +53,9 @@ const updateUserRatings = async (userAccount, bpAccount, transaction) => { community: blockProducer.community || 0 } - const result = await (await massiveDB).user_ratings.save({ - uniq_rating: blockProducer.uniq_rating, + const result = await ( + await massiveDB + ).user_ratings.save({ user: blockProducer.user, bp: blockProducer.bp, ratings: ratings, @@ -56,8 +63,9 @@ const updateUserRatings = async (userAccount, bpAccount, transaction) => { }) if (!result) { - const insertResult = await (await massiveDB).user_ratings.insert({ - uniq_rating: blockProducer.uniq_rating, + const insertResult = await ( + await massiveDB + ).user_ratings.insert({ user: blockProducer.user, bp: blockProducer.bp, ratings, @@ -65,11 +73,12 @@ const updateUserRatings = async (userAccount, bpAccount, transaction) => { }) if (!insertResult) - throw new Error(`Could not save or insert ${blockProducer.uniq_rating}`) + throw new Error( + `Could not save or insert ${blockProducer.user}-${blockProducer.bp}` + ) } return { - uniq_rating: blockProducer.uniq_rating, user: blockProducer.user, bp: blockProducer.bp, ratings, diff --git a/hapi/yarn.lock b/hapi/yarn.lock index 2976f26b..15495c77 100644 --- a/hapi/yarn.lock +++ b/hapi/yarn.lock @@ -56,9 +56,9 @@ "@babel/types" "^7.15.4" "@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== "@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": version "7.14.5" @@ -70,9 +70,9 @@ js-tokens "^4.0.0" "@babel/parser@^7.15.4", "@babel/parser@^7.3.1": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.6.tgz#043b9aa3c303c0722e5377fef9197f4cf1796549" - integrity sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q== + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" + integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== "@babel/template@^7.15.4": version "7.15.4" diff --git a/hasura/metadata/actions.graphql b/hasura/metadata/actions.graphql index 6e51e00a..847b0208 100644 --- a/hasura/metadata/actions.graphql +++ b/hasura/metadata/actions.graphql @@ -6,6 +6,7 @@ type Mutation { input RatingInput { user: String! + isEden: Boolean! producer: String! transaction: jsonb! } @@ -13,7 +14,6 @@ input RatingInput { type RatingOutput { message: String! resultEden: jsonb - uniq_rating: String user: String bp: String ratings: jsonb diff --git a/hasura/metadata/databases/default/tables/public_producers.yaml b/hasura/metadata/databases/default/tables/public_producers.yaml index 3e856471..4736b5b2 100644 --- a/hasura/metadata/databases/default/tables/public_producers.yaml +++ b/hasura/metadata/databases/default/tables/public_producers.yaml @@ -5,6 +5,7 @@ select_permissions: - permission: columns: - bpjson + - candidate_name - general_info - owner - system diff --git a/hasura/metadata/databases/default/tables/public_producers_list.yaml b/hasura/metadata/databases/default/tables/public_producers_list.yaml index 5ad3726a..6be1900e 100644 --- a/hasura/metadata/databases/default/tables/public_producers_list.yaml +++ b/hasura/metadata/databases/default/tables/public_producers_list.yaml @@ -1,23 +1,3 @@ table: name: producers_list schema: public -select_permissions: -- permission: - columns: - - owner - - bpjson - - system - - candidate_name - - total_votes - - eden_average - - eden_ratings_cntr - - average - - transparency - - infrastructure - - trustiness - - community - - development - - ratings_cntr - - general_info - filter: {} - role: anonymous diff --git a/hasura/metadata/databases/default/tables/public_proxies.yaml b/hasura/metadata/databases/default/tables/public_proxies.yaml index 24b9f599..8bcd84ad 100644 --- a/hasura/metadata/databases/default/tables/public_proxies.yaml +++ b/hasura/metadata/databases/default/tables/public_proxies.yaml @@ -3,8 +3,10 @@ table: schema: public select_permissions: - permission: + allow_aggregations: true columns: - background + - filter_name - logo_256 - name - owner diff --git a/hasura/metadata/databases/default/tables/public_user_ratings.yaml b/hasura/metadata/databases/default/tables/public_user_ratings.yaml index a3ec7572..f2763fcc 100644 --- a/hasura/metadata/databases/default/tables/public_user_ratings.yaml +++ b/hasura/metadata/databases/default/tables/public_user_ratings.yaml @@ -7,7 +7,6 @@ select_permissions: - bp - ratings - tx_data - - uniq_rating - user filter: {} role: anonymous @@ -18,7 +17,6 @@ update_permissions: - bp - ratings - tx_data - - uniq_rating - user filter: {} role: anonymous diff --git a/hasura/migrations/default/1632090744903_alter_table_public_producers_add_column_candidate_name/down.sql b/hasura/migrations/default/1632090744903_alter_table_public_producers_add_column_candidate_name/down.sql new file mode 100644 index 00000000..a9e835d5 --- /dev/null +++ b/hasura/migrations/default/1632090744903_alter_table_public_producers_add_column_candidate_name/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."producers" add column "candidate_name" text +-- null; diff --git a/hasura/migrations/default/1632090744903_alter_table_public_producers_add_column_candidate_name/up.sql b/hasura/migrations/default/1632090744903_alter_table_public_producers_add_column_candidate_name/up.sql new file mode 100644 index 00000000..0d3e3614 --- /dev/null +++ b/hasura/migrations/default/1632090744903_alter_table_public_producers_add_column_candidate_name/up.sql @@ -0,0 +1,2 @@ +alter table "public"."producers" add column "candidate_name" text + null; diff --git a/hasura/migrations/default/1632094823972_alter_table_public_proxies_add_column_filter_name/down.sql b/hasura/migrations/default/1632094823972_alter_table_public_proxies_add_column_filter_name/down.sql new file mode 100644 index 00000000..47328017 --- /dev/null +++ b/hasura/migrations/default/1632094823972_alter_table_public_proxies_add_column_filter_name/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."proxies" add column "filter_name" text +-- null; diff --git a/hasura/migrations/default/1632094823972_alter_table_public_proxies_add_column_filter_name/up.sql b/hasura/migrations/default/1632094823972_alter_table_public_proxies_add_column_filter_name/up.sql new file mode 100644 index 00000000..62ea5024 --- /dev/null +++ b/hasura/migrations/default/1632094823972_alter_table_public_proxies_add_column_filter_name/up.sql @@ -0,0 +1,2 @@ +alter table "public"."proxies" add column "filter_name" text + null; diff --git a/hasura/migrations/default/1633651553068_alter_table_public_user_ratings_add_column_id/down.sql b/hasura/migrations/default/1633651553068_alter_table_public_user_ratings_add_column_id/down.sql new file mode 100644 index 00000000..d891475b --- /dev/null +++ b/hasura/migrations/default/1633651553068_alter_table_public_user_ratings_add_column_id/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."user_ratings" add column "id" serial +-- not null unique; diff --git a/hasura/migrations/default/1633651553068_alter_table_public_user_ratings_add_column_id/up.sql b/hasura/migrations/default/1633651553068_alter_table_public_user_ratings_add_column_id/up.sql new file mode 100644 index 00000000..db9def86 --- /dev/null +++ b/hasura/migrations/default/1633651553068_alter_table_public_user_ratings_add_column_id/up.sql @@ -0,0 +1,2 @@ +alter table "public"."user_ratings" add column "id" serial + not null unique; diff --git a/hasura/migrations/default/1633651564624_modify_primarykey_public_user_ratings/down.sql b/hasura/migrations/default/1633651564624_modify_primarykey_public_user_ratings/down.sql new file mode 100644 index 00000000..736da1df --- /dev/null +++ b/hasura/migrations/default/1633651564624_modify_primarykey_public_user_ratings/down.sql @@ -0,0 +1,4 @@ +alter table "public"."user_ratings" drop constraint "user_ratings_pkey"; +alter table "public"."user_ratings" + add constraint "user_ratings_pkey" + primary key ("uniq_rating"); diff --git a/hasura/migrations/default/1633651564624_modify_primarykey_public_user_ratings/up.sql b/hasura/migrations/default/1633651564624_modify_primarykey_public_user_ratings/up.sql new file mode 100644 index 00000000..494f2c5d --- /dev/null +++ b/hasura/migrations/default/1633651564624_modify_primarykey_public_user_ratings/up.sql @@ -0,0 +1,6 @@ +BEGIN TRANSACTION; +ALTER TABLE "public"."user_ratings" DROP CONSTRAINT "user_ratings_pkey"; + +ALTER TABLE "public"."user_ratings" + ADD CONSTRAINT "user_ratings_pkey" PRIMARY KEY ("id"); +COMMIT TRANSACTION; diff --git a/hasura/migrations/default/1633651780354_alter_table_public_user_ratings_drop_column_uniq_rating/down.sql b/hasura/migrations/default/1633651780354_alter_table_public_user_ratings_drop_column_uniq_rating/down.sql new file mode 100644 index 00000000..89ece80c --- /dev/null +++ b/hasura/migrations/default/1633651780354_alter_table_public_user_ratings_drop_column_uniq_rating/down.sql @@ -0,0 +1,3 @@ +alter table "public"."user_ratings" add constraint "user_ratings_uniq_rating_key" unique (uniq_rating); +alter table "public"."user_ratings" alter column "uniq_rating" drop not null; +alter table "public"."user_ratings" add column "uniq_rating" text; diff --git a/hasura/migrations/default/1633651780354_alter_table_public_user_ratings_drop_column_uniq_rating/up.sql b/hasura/migrations/default/1633651780354_alter_table_public_user_ratings_drop_column_uniq_rating/up.sql new file mode 100644 index 00000000..4ced5771 --- /dev/null +++ b/hasura/migrations/default/1633651780354_alter_table_public_user_ratings_drop_column_uniq_rating/up.sql @@ -0,0 +1 @@ +alter table "public"."user_ratings" drop column "uniq_rating" cascade; diff --git a/hasura/migrations/default/1633699031493_update_producer_list_view/down.sql b/hasura/migrations/default/1633699031493_update_producer_list_view/down.sql new file mode 100644 index 00000000..eb01d97f --- /dev/null +++ b/hasura/migrations/default/1633699031493_update_producer_list_view/down.sql @@ -0,0 +1,29 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- DROP VIEW "public"."producers_list"; +-- +-- CREATE OR REPLACE VIEW "public"."producers_list" AS +-- SELECT producers.owner, +-- producers.bpjson, +-- producers.system, +-- ((producers.bpjson -> 'org'::text) ->> 'candidate_name'::text) AS candidate_name, +-- (producers.system ->> 'total_votes'::text) AS total_votes, +-- ratings_stats.average, +-- ratings_stats.transparency, +-- ratings_stats.infrastructure, +-- ratings_stats.trustiness, +-- ratings_stats.community, +-- ratings_stats.development, +-- ratings_stats.ratings_cntr, +-- -- Eden Ratings Stats +-- eden_ratings_stats.average AS eden_average, +-- eden_ratings_stats.transparency AS eden_transparency, +-- eden_ratings_stats.infrastructure AS eden_infrastructure, +-- eden_ratings_stats.trustiness AS eden_trustiness, +-- eden_ratings_stats.community AS eden_community, +-- eden_ratings_stats.development AS eden_development, +-- eden_ratings_stats.ratings_cntr AS eden_ratings_cntr, +-- producers.general_info +-- FROM ((producers +-- FULL JOIN ratings_stats ON (((ratings_stats.bp)::text = producers.owner))) +-- FULL JOIN eden_ratings_stats ON (((eden_ratings_stats.bp)::text = producers.owner))); diff --git a/hasura/migrations/default/1633699031493_update_producer_list_view/up.sql b/hasura/migrations/default/1633699031493_update_producer_list_view/up.sql new file mode 100644 index 00000000..a52db834 --- /dev/null +++ b/hasura/migrations/default/1633699031493_update_producer_list_view/up.sql @@ -0,0 +1,27 @@ +DROP VIEW "public"."producers_list"; + +CREATE OR REPLACE VIEW "public"."producers_list" AS + SELECT producers.owner, + producers.bpjson, + producers.system, + ((producers.bpjson -> 'org'::text) ->> 'candidate_name'::text) AS candidate_name, + (producers.system ->> 'total_votes'::text) AS total_votes, + ratings_stats.average, + ratings_stats.transparency, + ratings_stats.infrastructure, + ratings_stats.trustiness, + ratings_stats.community, + ratings_stats.development, + ratings_stats.ratings_cntr, + -- Eden Ratings Stats + eden_ratings_stats.average AS eden_average, + eden_ratings_stats.transparency AS eden_transparency, + eden_ratings_stats.infrastructure AS eden_infrastructure, + eden_ratings_stats.trustiness AS eden_trustiness, + eden_ratings_stats.community AS eden_community, + eden_ratings_stats.development AS eden_development, + eden_ratings_stats.ratings_cntr AS eden_ratings_cntr, + producers.general_info + FROM ((producers + FULL JOIN ratings_stats ON (((ratings_stats.bp)::text = producers.owner))) + FULL JOIN eden_ratings_stats ON (((eden_ratings_stats.bp)::text = producers.owner))); diff --git a/hasura/migrations/default/1633699032028_update_producer_list_view/down.sql b/hasura/migrations/default/1633699032028_update_producer_list_view/down.sql new file mode 100644 index 00000000..eb01d97f --- /dev/null +++ b/hasura/migrations/default/1633699032028_update_producer_list_view/down.sql @@ -0,0 +1,29 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- DROP VIEW "public"."producers_list"; +-- +-- CREATE OR REPLACE VIEW "public"."producers_list" AS +-- SELECT producers.owner, +-- producers.bpjson, +-- producers.system, +-- ((producers.bpjson -> 'org'::text) ->> 'candidate_name'::text) AS candidate_name, +-- (producers.system ->> 'total_votes'::text) AS total_votes, +-- ratings_stats.average, +-- ratings_stats.transparency, +-- ratings_stats.infrastructure, +-- ratings_stats.trustiness, +-- ratings_stats.community, +-- ratings_stats.development, +-- ratings_stats.ratings_cntr, +-- -- Eden Ratings Stats +-- eden_ratings_stats.average AS eden_average, +-- eden_ratings_stats.transparency AS eden_transparency, +-- eden_ratings_stats.infrastructure AS eden_infrastructure, +-- eden_ratings_stats.trustiness AS eden_trustiness, +-- eden_ratings_stats.community AS eden_community, +-- eden_ratings_stats.development AS eden_development, +-- eden_ratings_stats.ratings_cntr AS eden_ratings_cntr, +-- producers.general_info +-- FROM ((producers +-- FULL JOIN ratings_stats ON (((ratings_stats.bp)::text = producers.owner))) +-- FULL JOIN eden_ratings_stats ON (((eden_ratings_stats.bp)::text = producers.owner))); diff --git a/hasura/migrations/default/1633699032028_update_producer_list_view/up.sql b/hasura/migrations/default/1633699032028_update_producer_list_view/up.sql new file mode 100644 index 00000000..a52db834 --- /dev/null +++ b/hasura/migrations/default/1633699032028_update_producer_list_view/up.sql @@ -0,0 +1,27 @@ +DROP VIEW "public"."producers_list"; + +CREATE OR REPLACE VIEW "public"."producers_list" AS + SELECT producers.owner, + producers.bpjson, + producers.system, + ((producers.bpjson -> 'org'::text) ->> 'candidate_name'::text) AS candidate_name, + (producers.system ->> 'total_votes'::text) AS total_votes, + ratings_stats.average, + ratings_stats.transparency, + ratings_stats.infrastructure, + ratings_stats.trustiness, + ratings_stats.community, + ratings_stats.development, + ratings_stats.ratings_cntr, + -- Eden Ratings Stats + eden_ratings_stats.average AS eden_average, + eden_ratings_stats.transparency AS eden_transparency, + eden_ratings_stats.infrastructure AS eden_infrastructure, + eden_ratings_stats.trustiness AS eden_trustiness, + eden_ratings_stats.community AS eden_community, + eden_ratings_stats.development AS eden_development, + eden_ratings_stats.ratings_cntr AS eden_ratings_cntr, + producers.general_info + FROM ((producers + FULL JOIN ratings_stats ON (((ratings_stats.bp)::text = producers.owner))) + FULL JOIN eden_ratings_stats ON (((eden_ratings_stats.bp)::text = producers.owner))); diff --git a/webapp/.babelrc b/webapp/.babelrc new file mode 100644 index 00000000..b4fb7817 --- /dev/null +++ b/webapp/.babelrc @@ -0,0 +1,16 @@ +{ + "plugins": ["@babel/plugin-proposal-optional-chaining"], + "presets": [ + [ + "@babel/preset-env", + { + "loose": true, + "targets": { "esmodules": true }, + "useBuiltIns": "usage", + "corejs": 3, + "modules": false + } + ], + "@babel/preset-react" + ] +} diff --git a/webapp/.prettierrc b/webapp/.prettierrc new file mode 100644 index 00000000..1719afbd --- /dev/null +++ b/webapp/.prettierrc @@ -0,0 +1,13 @@ +{ + "trailingComma": "none", + "endOfLine": "auto", + "tabWidth": 2, + "singleQuote": true, + "semi": false, + "arrowParens": "avoid", + "printWidth": 80, + "useTabs": false, + "bracketSpacing": true, + "jsxBracketSameLine": false, + "jsxSingleQuote": true +} diff --git a/webapp/config-overrides.js b/webapp/config-overrides.js index 82cbba15..78877463 100644 --- a/webapp/config-overrides.js +++ b/webapp/config-overrides.js @@ -1,8 +1,3 @@ -const { compose } = require('react-app-rewired') -const rewireEslint = require('react-app-rewire-eslint') -const rewireReactHotLoader = require('react-app-rewire-hot-loader') +const { useBabelRc, override } = require('customize-cra') -module.exports = compose( - rewireEslint, - rewireReactHotLoader -) +module.exports = override(useBabelRc()) diff --git a/webapp/jsconfig.json b/webapp/jsconfig.json deleted file mode 100644 index 5875dc5b..00000000 --- a/webapp/jsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "src" - }, - "include": ["src"] -} diff --git a/webapp/package.json b/webapp/package.json index 478a3e81..b5a81940 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -17,17 +17,20 @@ }, "husky": { "hooks": { - "pre-commit": "lint-staged" + "pre-commit": "lint-staged && CI=true yarn test" } }, "dependencies": { + "@apollo/client": "^3.3.21", + "@date-io/date-fns": "^2.11.0", + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", "@eoscostarica/eoscr-components": "^3.5.4", - "@material-ui/core": "^4.12.1", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.60", - "@reach/router": "^1.3.3", - "@rematch/core": "^2.0.0", - "@rematch/persist": "^2.0.0", + "@eoscostarica/ual-reactjs-renderer": "^0.3.1", + "@mui/icons-material": "^5.0.1", + "@mui/lab": "^5.0.0-alpha.48", + "@mui/material": "^5.0.1", + "@mui/styles": "^5.0.1", "apollo-cache-inmemory": "^1.6.5", "apollo-client": "^2.6.8", "apollo-link": "^1.2.13", @@ -35,38 +38,47 @@ "apollo-link-ws": "^1.0.19", "apollo-utilities": "^1.3.3", "chart.js": "^3.5.1", - "classnames": "^2.3.1", + "core-js": "^3.15.2", + "date-fns": "^2.24.0", "env-cmd": "^10.1.0", "eosjs": "^22.1.0", + "eosjs-api": "^7.0.4", "filter-objects": "^2.1.1", "graphql": "^15.5.1", "graphql-tag": "^2.12.5", + "highcharts": "^9.2.2", + "highcharts-react-official": "^3.0.0", + "history": "^5.0.0", "i18n-iso-countries": "^6.8.0", - "i18next": "^20.3.3", + "i18next": "^20.3.4", "i18next-browser-languagedetector": "^6.1.2", "lodash.get": "^4.4.2", "lodash.isempty": "^4.4.0", "lodash.set": "^4.3.2", "lodash.uniq": "^4.5.0", "node-fetch": "^2.6.2", + "polished": "^4.1.3", + "prop-types": "^15.7.2", "qs": "^6.10.1", "random-color-rgb": "^1.1.1", "rc-slider": "^9.7.2", - "react": "17.0.2", + "react": "~17.0.2", "react-apollo": "^3.1.3", "react-autosuggest": "^10.1.0", - "react-chartjs-2": "^3.0.4", - "react-dom": "17.0.2", + "react-dom": "~17.0.2", + "react-feather": "^2.0.9", "react-ga": "^3.3.0", "react-helmet": "^6.1.0", "react-highlighter": "^0.4.3", - "react-i18next": "^11.11.2", + "react-i18next": "^11.11.3", + "react-is": "^17.0.2", + "react-perfect-scrollbar": "^1.5.8", "react-placeholder": "^4.0.0", - "react-redux": "^7.2.4", - "react-router": "^5.2.1", - "redux": "^4.1.0", - "redux-persist": "^6.0.0", + "react-router": "^5.2.0", + "react-router-dom": "^5.2.0", + "react-scripts": "^4.0.3", "serve": "^12.0.0", + "string-to-color": "^2.2.2", "subscriptions-transport-ws": "^0.9.19", "text-encoding": "^0.7.0", "ual-anchor": "^1.0.6", @@ -79,18 +91,25 @@ "yup": "0.32.9" }, "devDependencies": { - "eslint-config-prettier": "^8.3.0", - "eslint-config-standard": "^16.0.3", + "@babel/eslint-parser": "^7.13.10", + "@babel/plugin-proposal-optional-chaining": "^7.13.8", + "@babel/preset-env": "^7.13.10", + "@babel/preset-react": "^7.12.13", + "customize-cra": "^1.0.0", + "env-cmd": "^10.1.0", + "eslint": "^7.22.0", + "eslint-config-prettier": "^8.1.0", + "eslint-config-standard": "^16.0.2", "eslint-config-standard-react": "^11.0.1", - "eslint-plugin-node": "^11.0.0", - "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-standard": "^5.0.0", - "husky": "^7.0.1", - "lint-staged": "^11.0.1", - "prettier": "^2.3.2", - "pretty-quick": "^3.1.1", - "react-scripts": "4.0.3", - "snazzy": "^9.0.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^3.3.1", + "eslint-plugin-promise": "^4.3.1", + "eslint-plugin-react": "^7.22.0", + "husky": "4.3.8", + "lint-staged": "^10.5.4", + "prettier": "^2.2.1", + "react-app-rewired": "^2.1.8", "standard": "^16.0.3" }, "resolutions": { @@ -105,16 +124,10 @@ "git add" ] }, - "browserslist": { - "development": [ - "last 2 chrome versions", - "last 2 firefox versions", - "last 2 edge versions" - ], - "production": [ - ">0.25%", - "not op_mini all", - "ie 11" - ] - } + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] } diff --git a/webapp/public/index.html b/webapp/public/index.html index 381e7da0..969420e7 100644 --- a/webapp/public/index.html +++ b/webapp/public/index.html @@ -14,7 +14,7 @@ diff --git a/webapp/src/App.test.js b/webapp/src/App.test.js new file mode 100644 index 00000000..1e51268e --- /dev/null +++ b/webapp/src/App.test.js @@ -0,0 +1,11 @@ +import React from 'react' +import ReactDOM from 'react-dom' + +import App from './App' + +// eslint-disable-next-line no-undef +it('renders without crashing', () => { + const div = document.createElement('div') + ReactDOM.render(, div) + ReactDOM.unmountComponentAtNode(div) +}) diff --git a/webapp/src/app.js b/webapp/src/app.js index 0fb830b4..7a25fe56 100644 --- a/webapp/src/app.js +++ b/webapp/src/app.js @@ -1,33 +1,48 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { useSelector } from 'react-redux' -import { Router } from '@reach/router' +import React, { Suspense, useMemo } from 'react' +import { BrowserRouter, Route, Switch } from 'react-router-dom' +import AdapterDateFns from '@mui/lab/AdapterDateFns' +import LocalizationProvider from '@mui/lab/LocalizationProvider' +import { ThemeProvider } from '@mui/material/styles' +import CssBaseline from '@mui/material/CssBaseline' -import Spinner from 'components/spinner' -import Layout from 'components/layout' -import NotFound from 'routes/not-found' -import routes from 'routes' +import routes from './routes' +import Loader from './components/Loader' +import DashboardLayout from './layouts/Dashboard' +import { useSharedState } from './context/state.context' +import getTheme from './theme' +import './i18n' -const App = ({ ual }) => { - const { isContentLoading } = useSelector((state) => state.isLoading) +const App = () => { + const [state] = useSharedState() - return ( - <> - - - - {(routes || []).map(({ path, Component }) => ( - - ))} - - - - + const renderRoute = ({ component: Component, ...route }, index) => ( + + + ) -} -App.propTypes = { - ual: PropTypes.object + const userRoutes = useMemo(() => routes()) + + const theme = useMemo(() => getTheme(state.useDarkMode), [state.useDarkMode]) + + return ( + + + + + + }> + {userRoutes.browser.map(renderRoute)} + + + + + + ) } export default App diff --git a/webapp/src/components/bp-chip-avatar/index.js b/webapp/src/components/BpChipAvatar/index.js similarity index 79% rename from webapp/src/components/bp-chip-avatar/index.js rename to webapp/src/components/BpChipAvatar/index.js index a3ac4565..facedd10 100644 --- a/webapp/src/components/bp-chip-avatar/index.js +++ b/webapp/src/components/BpChipAvatar/index.js @@ -1,9 +1,10 @@ import React, { memo } from 'react' import PropTypes from 'prop-types' -import Chip from '@material-ui/core/Chip' -import Avatar from '@material-ui/core/Avatar' +import clsx from 'clsx' +import Chip from '@mui/material/Chip' +import Avatar from '@mui/material/Avatar' import _get from 'lodash.get' -import { makeStyles } from '@material-ui/core/styles' +import { makeStyles } from '@mui/styles' import styles from './styles' @@ -17,14 +18,14 @@ const ProducerChipAvatar = ({ defaultName, isProxy }) => { - const backgroundColor = _get(data, 'data.pointBackgroundColor', '#597a81') + const backgroundColor = _get(data, 'data.color', '#597a81') const classes = useStyles({ color: backgroundColor }) return ( <> {isProxy && ( {!imageURL ? ( @@ -39,7 +40,7 @@ const ProducerChipAvatar = ({ )} {!isProxy && ( {!imageURL ? ( diff --git a/webapp/src/components/BpChipAvatar/styles.js b/webapp/src/components/BpChipAvatar/styles.js new file mode 100644 index 00000000..cb0913b5 --- /dev/null +++ b/webapp/src/components/BpChipAvatar/styles.js @@ -0,0 +1,9 @@ +export default props => ({ + rootChip: { + marginBottom: '8px !important', + color: 'white !important', + justifyContent: 'space-around !important', + width: 158, + backgroundColor: props => `${props.color} !important` + } +}) diff --git a/webapp/src/components/card/index.js b/webapp/src/components/Card/index.js similarity index 60% rename from webapp/src/components/card/index.js rename to webapp/src/components/Card/index.js index 12062d9a..4fa13944 100644 --- a/webapp/src/components/card/index.js +++ b/webapp/src/components/Card/index.js @@ -1,24 +1,26 @@ -import React, { useState, forwardRef, useEffect } from 'react' +import React, { useState, forwardRef } from 'react' import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/styles' -import { useTheme } from '@material-ui/core/styles' -import useMediaQuery from '@material-ui/core/useMediaQuery' -import Card from '@material-ui/core/Card' -import Box from '@material-ui/core/Box' -import CardHeader from '@material-ui/core/CardHeader' +import clsx from 'clsx' +import { makeStyles } from '@mui/styles' +import { useTheme } from '@mui/material/styles' import { useTranslation } from 'react-i18next' -import Typography from '@material-ui/core/Typography' -import CardActions from '@material-ui/core/CardActions' -import Avatar from '@material-ui/core/Avatar' -import Button from '@material-ui/core/Button' -import Help from '@material-ui/icons/HelpOutlineRounded' -import Error from '@material-ui/icons/Error' -import Tooltip from '@material-ui/core/Tooltip' -import Grid from '@material-ui/core/Grid' -import { Link } from '@reach/router' -import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight' +import useMediaQuery from '@mui/material/useMediaQuery' +import Card from '@mui/material/Card' +import Box from '@mui/material/Box' +import CardHeader from '@mui/material/CardHeader' +import Typography from '@mui/material/Typography' +import CardActions from '@mui/material/CardActions' +import Avatar from '@mui/material/Avatar' +import Button from '@mui/material/Button' +import Help from '@mui/icons-material/HelpOutlineRounded' +import Error from '@mui/icons-material/Error' +import Tooltip from '@mui/material/Tooltip' +import Grid from '@mui/material/Grid' +import { Link } from 'react-router-dom' +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight' -import Radar from 'components/radar' +import PolarChart from '../PolarChart' +import formatNumber from '../../utils/format-number' import styles from './styles' @@ -53,25 +55,26 @@ const CardData = ({ average, rate, showOptions, - isNewRate, - ...props + isNewRate }) => { const { t } = useTranslation('translations') const [open, setOpen] = useState(false) const classes = useStyles() const theme = useTheme() const isMobile = useMediaQuery(theme.breakpoints.only('xs')) - const isDesktop = useMediaQuery('(min-width:770px)') - const [sizes, setSizes] = useState() - const handleTooltip = (e) => { + const handleTooltip = e => { setOpen(!open) e.preventDefault() } - useEffect(() => { - setSizes(isDesktop ? 400 : '95%') - }, [isDesktop]) + const formatRadarData = rateData => [ + parseFloat(formatNumber(rateData?.community || 0, 1)), + parseFloat(formatNumber(rateData?.development || 0, 1)), + parseFloat(formatNumber(rateData?.development || 0, 1)), + parseFloat(formatNumber(rateData?.transparency || 0, 1)), + parseFloat(formatNumber(rateData?.trustiness || 0, 1)) + ] return ( @@ -93,29 +96,31 @@ const CardData = ({ } title={ -
+ {title || owner} -
+ } subheader={ -
- {owner} - + + + {owner} + + {t('view')} -
+ } /> -
-
+ + {!title && ( )} -
- + + + + {showOptions && ( - + {`${t('rateCard')}:`} - {rate || 0} + + {rate || 0} + {`${t('averageCard')}:`} - {average} + + {average} + )} -
+ {useRateButton && ( <> @@ -193,9 +199,10 @@ const CardData = ({ {!useRateButton && ( <> + + + )} + {!isProxy && ( + + + + setIsCollapsedView(event.target.checked) + } + value='isCollapsedView' + /> + } + label={t('compareToolCollapsedSwitch')} + /> + + + )} + + + {selected.length > 0 ? ( + + ) : ( + + {t('noSelectedBP')} + + )} + + + + + {selected.length > 0 ? ( + + ) : ( + + {t('noSelectedBP')} + + )} + + + {!isProxy && ( + + + + + )} + + ) +} + +CompareGraphView.propTypes = { + removeBP: PropTypes.func.isRequired, + selected: PropTypes.array.isRequired, + isProxy: PropTypes.bool, + userInfo: PropTypes.object, + handleOnClear: PropTypes.func, + handleOnClose: PropTypes.func, + onHandleVote: PropTypes.func, + setIsCollapsedView: PropTypes.func, + isCollapsedView: PropTypes.bool +} + +CompareGraphView.defaultProps = { + isProxy: false, + userInfo: { proxy: '', producers: [], isUser: false }, + onHandleVote: () => {}, + handleOnClear: () => {}, + handleOnClose: () => {}, + setIsCollapsedView: () => {}, + isCollapsedView: true +} + +CompareBodyList.propTypes = { + isProxy: PropTypes.bool, + selectedData: PropTypes.array, + classes: PropTypes.object.isRequired, + removeBP: PropTypes.func.isRequired +} + +TooltipWrapper.propTypes = { + classes: PropTypes.object, + isClickable: PropTypes.bool, + open: PropTypes.bool, + onHandleTooltip: PropTypes.func, + t: PropTypes.any, + userHasVote: PropTypes.bool, + isUser: PropTypes.bool.apply +} + +export default CompareGraphView diff --git a/webapp/src/components/CompareTool/CompareSliderView.js b/webapp/src/components/CompareTool/CompareSliderView.js new file mode 100644 index 00000000..c4699885 --- /dev/null +++ b/webapp/src/components/CompareTool/CompareSliderView.js @@ -0,0 +1,78 @@ +import React from 'react' +import { makeStyles } from '@mui/styles' +import CloseIcon from '@mui/icons-material/Close' +import { useTranslation } from 'react-i18next' +import PropTypes from 'prop-types' +import Typography from '@mui/material/Typography' +import Box from '@mui/material/Box' +import _get from 'lodash.get' +import clsx from 'clsx' + +import PolarChart from '../PolarChart' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const CompareSliderView = ({ + selected, + className, + isProxy, + optionalLabel, + handleOnClose +}) => { + const { t } = useTranslation('translations') + const classes = useStyles() + + return ( + + + + + + {isProxy ? optionalLabel : t('compareToolTitle')} + + + + + + + + + {selected.map((bp, index) => { + if (!bp) return null + + const name = isProxy + ? _get(bp, 'owner') + : _get(bp, 'bpjson.producer_account_name') + + return ( + + + + + + {name} + + + ) + })} + + + ) +} + +CompareSliderView.propTypes = { + selected: PropTypes.array.isRequired, + className: PropTypes.string, + isProxy: PropTypes.bool, + handleOnClose: PropTypes.func, + optionalLabel: PropTypes.string +} + +CompareSliderView.defaultProps = {} + +export default CompareSliderView diff --git a/webapp/src/components/compare-tool/index.js b/webapp/src/components/CompareTool/index.js similarity index 60% rename from webapp/src/components/compare-tool/index.js rename to webapp/src/components/CompareTool/index.js index 71c1f022..5be3ceb4 100644 --- a/webapp/src/components/compare-tool/index.js +++ b/webapp/src/components/CompareTool/index.js @@ -1,21 +1,26 @@ -import React, { useState } from 'react' +import React, { useState, forwardRef } from 'react' import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/core/styles' -import Button from '@material-ui/core/Button' -import FormControlLabel from '@material-ui/core/FormControlLabel' +import { makeStyles } from '@mui/styles' import { useTranslation } from 'react-i18next' +import Button from '@mui/material/Button' +import Box from '@mui/material/Box' +import FormControlLabel from '@mui/material/FormControlLabel' import _get from 'lodash.get' -import Switch from '@material-ui/core/Switch' -import Snackbar from '@material-ui/core/Snackbar' -import MuiAlert from '@material-ui/lab/Alert' +import Switch from '@mui/material/Switch' +import Snackbar from '@mui/material/Snackbar' +import MuiAlert from '@mui/material/Alert' import clsx from 'clsx' -import CompareGraphView from './compare-graph-view' -import CompareSliderView from './compare-slider-view' +import CompareGraphView from './CompareGraphView' +import CompareSliderView from './CompareSliderView' import styles from './styles' const useStyles = makeStyles(styles) +const Alert = forwardRef(function Alert(props, ref) { + return +}) + const CompareTool = ({ removeBP, list, @@ -34,7 +39,7 @@ const CompareTool = ({ const { t } = useTranslation('translations') const classes = useStyles() const [isCollapsedView, setIsCollapsedView] = useState(true) - const selectedData = selected.map((name) => + const selectedData = selected.map(name => list.find(({ owner }) => name === owner) ) const { proxy, producers } = _get(userInfo, 'voter_info', { @@ -42,11 +47,7 @@ const CompareTool = ({ producers: [] }) - function Alert(props) { - return - } - - const handleClose = (event, reason) => { + const handleClose = (e, reason) => { if (reason === 'clickaway') { return } @@ -61,27 +62,25 @@ const CompareTool = ({ : selectedData return ( -
+ -
+
) } return ( -
+ {isCollapsedView ? ( ) : ( - - )} -
- {!isCollapsedView && ( - <> + + + setIsCollapsedView(event.target.checked)} + onChange={event => setIsCollapsedView(event.target.checked)} value='isCollapsedView' + color={isCollapsedView ? 'primary' : 'secondary'} + /> + } + label={t('compareToolCollapsedSwitch')} + /> + + + setIsCollapsedView(event.target.checked)} + value='isCollapsedView' + color={isCollapsedView ? 'primary' : 'secondary'} /> } label={t('compareToolCollapsedSwitch')} /> - @@ -119,19 +134,19 @@ const CompareTool = ({ onClick={onHandleVote} className={classes.btnRate} variant='contained' - size='large' + color='secondary' > {t('voteToolToggle')} - - )} -
+
+ + )} - + {message.txError} @@ -140,11 +155,15 @@ const CompareTool = ({ autoHideDuration={4000} onClose={handleClose} > - + {t('success')} -
+ ) } diff --git a/webapp/src/components/CompareTool/styles.js b/webapp/src/components/CompareTool/styles.js new file mode 100644 index 00000000..07537573 --- /dev/null +++ b/webapp/src/components/CompareTool/styles.js @@ -0,0 +1,338 @@ +export default theme => ({ + // index + root: { + padding: theme.spacing(2), + background: theme.palette.surface.main, + width: '100%', + position: 'relative', + overflow: 'hidden' + }, + compareSliderView: { + width: '100%', + display: 'flex', + alignItems: 'center', + flexDirection: 'column' + }, + boxSliderView: { + height: '100%', + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + overflow: 'hidden', + alignItems: 'center' + }, + sliderBody: { + display: 'flex', + width: '100%', + flexDirection: 'column', + alignItems: 'center' + }, + compareGraphView: { + paddingTop: 0, + height: '100vh', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + overflow: 'hidden', + alignItems: 'center', + [theme.breakpoints.up('sm')]: { + height: '100%' + } + }, + wrapperDesktop: { + height: 'calc(100% - 174px)', + display: 'flex', + flexDirection: 'column', + overflow: 'auto', + [theme.breakpoints.up('sm')]: { + paddingTop: theme.spacing(1), + flexDirection: 'row', + overflow: 'hidden', + height: '100%', + width: '100%', + maxWidth: 1024 + } + }, + btnClear: { + textAlign: 'center', + width: 200 + }, + footer: { + display: 'flex', + paddingTop: theme.spacing(2), + flexDirection: 'column', + width: '100%', + height: 'calc(50% - 170px)', + justifyContent: 'space-between', + alignItems: 'center', + [theme.breakpoints.up('md')]: { + flexDirection: 'row', + justifyContent: 'space-evenly', + margin: 'auto', + bottom: 0, + width: 'calc(50% - 16px)' + } + }, + modalHeader: { + display: 'flex', + flexDirection: 'column', + width: '100%', + maxWidth: 1024, + [theme.breakpoints.up('mdg')]: { + marginLeft: 24 + } + }, + switchBox: { + textAlign: 'center', + height: 60 + }, + btnRate: { + width: 100, + [theme.breakpoints.up('md')]: { + float: 'right', + marginRight: 20, + '&:hover': { + backgroundColor: theme.palette.secondary.dark + } + } + }, + chipMessage: { + [theme.breakpoints.up('sm')]: { + float: 'right', + marginTop: 5, + marginRight: 5 + } + }, + errorColor: { + backgroundColor: theme.palette.error.main + }, + errorChip: { + border: `1px solid ${theme.palette.error.main}` + }, + labelErrorColor: { + color: theme.palette.error.main + }, + // slider view + bpName: { + marginTop: '-40px !important', + textAlign: 'center' + }, + slider: { + width: '100%', + maxWidth: 1024, + display: 'flex', + flexWrap: 'nowrap', + overflowX: 'auto', + '-webkit-overflow-scrolling': 'touch', + '&::-webkit-scrollbar': { + display: 'none' + } + }, + sliderCard: { + flex: '0 0 auto', + width: 360, + display: 'flex', + flexDirection: 'column', + overflow: 'hidden' + }, + chartWrapperSliderView: { + width: '100%', + '& .highcharts-container ': { + height: '400px !important', + width: '100% !important', + '& > svg': { + height: '400px !important', + width: '100% !important' + } + } + }, + // graph view + bpItem: { + width: '75%', + padding: '0 0 0 10px', + display: 'flex', + justifyContent: 'space-between', + '&:hover': { + backgroundColor: theme.palette.primary.submenu + } + }, + bpNameWrapper: { + height: 48, + paddingTop: 14 + }, + bpColorCode: { + display: 'inline-block', + width: 15, + height: 15, + verticalAlign: 'text-bottom' + }, + title: { + textDecoration: 'none', + color: theme.palette.primary.main + }, + avatar: { + backgroundColor: theme.palette.surface.main + }, + helpIcon: { + width: '90%', + height: '90%' + }, + cardHeader: { + borderBottom: `1px solid ${theme.palette.primary.light}` + }, + titleLock: { + display: 'flex', + justifyContent: 'stretch', + alignItems: 'center' + }, + headerVotingCompare: { + display: 'flex', + justifyContent: 'space-between', + width: '100%' + }, + marginRightElem: { + marginRight: 10 + }, + icon: { + color: theme.palette.primary.submenu, + fontSize: 30, + '&:hover': { + cursor: 'pointer' + } + }, + containerList: { + display: 'flex', + justifyContent: 'space-between', + height: '100%', + width: '100%', + minHeight: 50, + flexWrap: 'wrap', + [theme.breakpoints.up('sm')]: { + height: 'fit-content', + justifyContent: 'space-evenly' + }, + [theme.breakpoints.up('md')]: { + justifyContent: 'space-between', + marginBottom: 0 + } + }, + centerBox: { + margin: 'auto', + width: '100%', + padding: '5px' + }, + buttonsBox: { + position: 'absolute', + bottom: 0, + justifyContent: 'space-between', + display: 'flex', + alignItems: 'center', + width: 'calc(100% - 32px)', + backgroundColor: theme.palette.surface.main, + padding: theme.spacing(2, 0), + [theme.breakpoints.up('sm')]: { + width: '100%', + maxWidth: 1024, + position: 'initial', + justifyContent: 'flex-start' + } + }, + boxCloseIcon: { + justifyContent: 'flex-end', + display: 'flex', + height: '100%', + alignItems: 'flex-start' + }, + btnRateProxies: { + backgroundColor: theme.palette.secondary.main, + color: '#ffffff', + width: '100px', + padding: '5px 20px 5px 20px', + [theme.breakpoints.up('sm')]: { + '&:hover': { + backgroundColor: theme.palette.secondary.dark + } + } + }, + reliefGrid: { + [theme.breakpoints.up('md')]: { + border: '1px solid #f8f8f8', + boxShadow: + 'inset 2px 2px 2px #fff, inset -1px 0 2px rgba(0,0,0,.1), 1px 3px 3px rgba(0,0,0,.1)', + backgroundColor: '#fff' + } + }, + compareBodyListDesktop: { + display: 'none', + [theme.breakpoints.up('sm')]: { + display: 'flex' + } + }, + compareBodyListMobile: { + display: 'flex', + [theme.breakpoints.up('sm')]: { + display: 'none' + } + }, + noBPSelected: { + padding: theme.spacing(4, 4, 0, 3), + textAlign: 'center' + }, + bodyModalView: { + height: '100%', + display: 'flex', + justifyContent: 'flex-start', + flexDirection: 'column' + }, + topModalView: { + marginBottom: theme.spacing(2) + }, + btnBox: { + width: '100%', + maxWidth: 1024, + display: 'flex', + justifyContent: 'space-between', + [theme.breakpoints.up('sm')]: { + justifyContent: 'flex-end', + marginTop: theme.spacing(2) + } + }, + alert: { + width: '100%' + }, + proxyVote: { + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center' + }, + chartWrapper: { + width: '100%', + '& .highcharts-container ': { + height: '300px !important', + width: '100% !important', + '& > svg': { + marginTop: '-60px !important', + height: '400px !important', + width: '100% !important' + } + } + }, + overrideBreakpoint: { + [theme.breakpoints.up('sm')]: { + margin: `${theme.spacing(0, 1, 1, 1)} !important` + } + }, + hiddenMobile: { + display: 'none !important', + [theme.breakpoints.up('sm')]: { + display: 'flex !important' + } + }, + hiddenDesktop: { + display: 'flex !important', + [theme.breakpoints.up('sm')]: { + display: 'none !important' + } + } +}) diff --git a/webapp/src/components/FilterBanner/index.js b/webapp/src/components/FilterBanner/index.js new file mode 100644 index 00000000..023bc458 --- /dev/null +++ b/webapp/src/components/FilterBanner/index.js @@ -0,0 +1,85 @@ +import React, { useState } from 'react' +import PropTypes from 'prop-types' +import clsx from 'clsx' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import FilterListIcon from '@mui/icons-material/FilterList' +import Box from '@mui/material/Box' +import Menu from '@mui/material/Menu' +import MenuItem from '@mui/material/MenuItem' + +import { filtersConfig } from '../../config' +import { useSharedState } from '../../context/state.context' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const FilterBanner = ({ title, page, onFilterChange, hideFilter }) => { + const { t } = useTranslation('sortInput') + const classes = useStyles() + const [state, { setSortBy }] = useSharedState() + const [anchorEl, setAnchorEl] = useState(null) + const open = Boolean(anchorEl) + + const handleClick = e => { + setAnchorEl(e.currentTarget) + } + + const handleClose = filter => { + if (filter.value) { + setSortBy(filter, page) + onFilterChange(filter.sort) + } + + setAnchorEl(null) + } + + return ( + + {title} + + + {filtersConfig.filters.map(filter => ( + handleClose(filter)}> + {t(filter.value)} + + ))} + + + ) +} + +FilterBanner.propTypes = { + title: PropTypes.string, + page: PropTypes.string, + onFilterChange: PropTypes.func, + hideFilter: PropTypes.bool +} + +FilterBanner.defaultProps = { + onFilterChange: () => {}, + hideFilter: false +} + +export default FilterBanner diff --git a/webapp/src/components/FilterBanner/styles.js b/webapp/src/components/FilterBanner/styles.js new file mode 100644 index 00000000..9921e72f --- /dev/null +++ b/webapp/src/components/FilterBanner/styles.js @@ -0,0 +1,18 @@ +export default theme => ({ + filterBanner: { + display: 'flex', + justifyContent: 'space-between', + padding: theme.spacing(1, 2, 0, 2), + alignItems: 'center', + fontSize: '1rem !important' + }, + pageTitle: { + textTransform: 'uppercase', + fontWeight: '500 !important', + lineHeight: 'normal', + letterSpacing: '0.08px' + }, + visibilityHidden: { + visibility: 'hidden !important' + } +}) diff --git a/webapp/src/components/main-footer/index.js b/webapp/src/components/Footer/index.js similarity index 60% rename from webapp/src/components/main-footer/index.js rename to webapp/src/components/Footer/index.js index fc378f6c..cddfa99a 100644 --- a/webapp/src/components/main-footer/index.js +++ b/webapp/src/components/Footer/index.js @@ -1,24 +1,24 @@ -import React from 'react' -import { makeStyles } from '@material-ui/styles' -import AppBar from '@material-ui/core/AppBar' -import Toolbar from '@material-ui/core/Toolbar' -import Typography from '@material-ui/core/Typography' +import React, { memo } from 'react' import { useTranslation } from 'react-i18next' -import IconButton from '@material-ui/core/IconButton' - -import TelegramIcon from 'components/telegram-icon' -import GithubIcon from 'components/github-icon' +// import AppBar from '@mui/material/AppBar' +import Toolbar from '@mui/material/Toolbar' +import Typography from '@mui/material/Typography' +import IconButton from '@mui/material/IconButton' +import GitHubIcon from '@mui/icons-material/GitHub' +import TelegramIcon from '@mui/icons-material/Telegram' +import Box from '@mui/material/Box' +import { makeStyles } from '@mui/styles' import styles from './styles' const useStyles = makeStyles(styles) -const MainFooter = () => { - const { t } = useTranslation('footer') +const Footer = () => { const classes = useStyles() + const { t } = useTranslation('footer') return ( - + { className={classes.eoscostaricaLogo} /> -
+ { target='_blank' color='inherit' > - + - + - + ) } -export default MainFooter +export default memo(Footer) diff --git a/webapp/src/components/Footer/styles.js b/webapp/src/components/Footer/styles.js new file mode 100644 index 00000000..ee158934 --- /dev/null +++ b/webapp/src/components/Footer/styles.js @@ -0,0 +1,38 @@ +export default theme => ({ + root: { + padding: theme.spacing(1), + backgroundColor: theme.palette.primary.main + }, + listItem: { + display: 'inline-block', + width: 'auto', + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2), + '&:hover, &:active:': { + color: theme.palette.action.selected + } + }, + grow: { + flexGrow: 1 + }, + eoscostaricaLogo: { + height: 36, + width: 'auto' + }, + link: { + color: theme.palette.common.white, + textDecoration: 'none' + }, + legend: { + display: 'flex', + width: 150, + lineHeight: '1.4 !important', + fontSize: '8px !important', + fontWeight: '500 !important', + fontStretch: 'normal', + letterSpacing: '1.1px !important', + textAlign: 'right !important', + color: 'rgba(255, 255, 255, 0.6)', + paddingRight: theme.spacing(2) + } +}) diff --git a/webapp/src/components/Header/index.js b/webapp/src/components/Header/index.js new file mode 100644 index 00000000..ebf153d1 --- /dev/null +++ b/webapp/src/components/Header/index.js @@ -0,0 +1,209 @@ +import React, { memo, useState, useEffect } from 'react' +import { makeStyles } from '@mui/styles' +import PropTypes from 'prop-types' +import { useTranslation } from 'react-i18next' +import { useHistory, Link } from 'react-router-dom' +import AppBar from '@mui/material/AppBar' +import IconButton from '@mui/material/IconButton' +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import SearchIcon from '@material-ui/icons/Search' +import Toolbar from '@mui/material/Toolbar' +import Tooltip from '@material-ui/core/Tooltip' +import MenuIcon from '@mui/icons-material/Menu' +import FingerprintIcon from '@mui/icons-material/Fingerprint' +import ExitIcon from '@mui/icons-material/ExitToApp' +import LockOpenOutlinedIcon from '@material-ui/icons/LockOpenOutlined' +import LockOutlinedIcon from '@material-ui/icons/LockOutlined' + +import { useSharedState } from '../../context/state.context' +import MobileSearch from '../../components/MobileSearch' + +import InputAutocomplete from '../InputAutocomplete' +import LanguageSelector from '../LanguageSelector' +import { mainConfig } from '../../config' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const AuthButton = memo(({ user, onLogin, onSignOut }) => { + const { t } = useTranslation('translations') + const classes = useStyles() + + return ( + <> + {user && ( + + + {t('signOut')} + + )} + {!user && ( + + + + {t('appBarSignIn')} + + + )} + + ) +}) + +AuthButton.displayName = 'AuthButton' + +AuthButton.propTypes = { + user: PropTypes.any, + onLogin: PropTypes.func, + onSignOut: PropTypes.func +} + +const SpecialTooltip = props => { + const classes = useStyles() + return ( + + ) +} + +const UserInformationByType = memo(({ user }) => { + const { t } = useTranslation('translations') + const classes = useStyles() + const [mayVote, setMayVote] = useState(false) + + useEffect(() => { + if (!user) setMayVote(false) + else if ( + user.userData.voter_info && + (user.userData.voter_info.producers.length > 20 || + user.userData.voter_info.proxy.length > 0) + ) + setMayVote(true) + }, [user]) + + if (!user) return <> + + return ( + <> + {!user.userData.edenMember ? ( + + {mayVote ? : } + + ) : ( + + eden icon + + )} + + ) +}) + +UserInformationByType.displayName = 'UserInformationByType' + +UserInformationByType.propTypes = { + user: PropTypes.object +} + +const Header = memo(({ onDrawerToggle }) => { + const classes = useStyles() + const history = useHistory() + const [state, { login, logout }] = useSharedState() + const [isSearchOpen, setIsSearchOpen] = useState() + + const handleLogin = () => { + login() + } + + const handleSignOut = () => { + logout() + history.push('/') + } + + const handleOpenSearch = () => { + setIsSearchOpen(true) + } + + const handleCloseSearch = () => { + setIsSearchOpen(false) + } + + return ( + + + + + + + + EOS Rate + + + + + + + + + + + + + + + + + + + + + + + + + + ) +}) + +Header.displayName = 'Header' + +Header.propTypes = { + onDrawerToggle: PropTypes.func +} + +export default Header diff --git a/webapp/src/components/Header/styles.js b/webapp/src/components/Header/styles.js new file mode 100644 index 00000000..0bdee7fa --- /dev/null +++ b/webapp/src/components/Header/styles.js @@ -0,0 +1,105 @@ +export default theme => ({ + appBar: { + boxShadow: theme.shadows[0], + borderBottom: `1px solid ${theme.palette.divider}`, + [theme.breakpoints.up('md')]: { + boxShadow: theme.shadows[4], + borderBottom: 0 + } + }, + toolbar: { + padding: 0, + justifyContent: 'space-between', + paddingLeft: `${theme.spacing(1)} !important`, + paddingRight: `${theme.spacing(1)} !important`, + [theme.breakpoints.up('md')]: { + padding: theme.spacing(0, 2) + } + }, + typography: { + color: theme.palette.text.primary, + flexGrow: 1 + }, + desktopSection: { + display: 'none', + height: 54, + alignItems: 'center', + justifyContent: 'space-between', + '& svg, & span': { + color: theme.palette.common.white + }, + [theme.breakpoints.up('md')]: { + display: 'flex' + } + }, + mobileSection: { + display: 'flex', + [theme.breakpoints.up('md')]: { + display: 'none' + } + }, + boxLogo: { + display: 'flex', + '& svg': { + color: theme.palette.common.white + }, + '& img': { + width: 145 + }, + [theme.breakpoints.up('md')]: { + '& img': { + width: 180 + } + } + }, + boxSearch: { + display: 'none', + [theme.breakpoints.up('md')]: { + display: 'flex' + } + }, + onSignOut: { + '& svg': { + color: theme.palette.common.white + } + }, + onLogin: { + '& svg': { + color: theme.palette.common.white + } + }, + textBtn: { + display: 'none', + [theme.breakpoints.up('md')]: { + display: 'flex', + color: theme.palette.common.white, + fontFamily: 'Roboto', + fontStyle: 'normal', + fontWeight: 'normal', + fontSize: 20, + lineHeight: '23px', + marginLeft: `${theme.spacing(0.5)} !important` + } + }, + link: { + display: 'flex' + }, + mobileSearch: { + '& svg': { + color: theme.palette.common.white + } + }, + arrow: { + color: 'rgba(97, 97, 97, 0.9)', + marginLeft: 30 + }, + tooltip: { + boxShadow: theme.shadows[1], + width: 140, + fontSize: 14, + textAlign: 'center' + }, + logoTypeUSerSize: { + width: 28 + } +}) diff --git a/webapp/src/components/input-autocomplete/index.js b/webapp/src/components/InputAutocomplete/index.js similarity index 57% rename from webapp/src/components/input-autocomplete/index.js rename to webapp/src/components/InputAutocomplete/index.js index 8e23156e..0cc7ca58 100644 --- a/webapp/src/components/input-autocomplete/index.js +++ b/webapp/src/components/InputAutocomplete/index.js @@ -1,18 +1,21 @@ import React, { useEffect, useState } from 'react' +import { useLazyQuery } from '@apollo/client' import PropTypes from 'prop-types' -import { useDispatch, useSelector } from 'react-redux' -import { navigate } from '@reach/router' +import { useHistory } from 'react-router-dom' import Highlight from 'react-highlighter' import Autosuggest from 'react-autosuggest' -import filterObjects from 'filter-objects' -import { makeStyles } from '@material-ui/styles' +import { makeStyles } from '@mui/styles' import { useTranslation } from 'react-i18next' -import SearchIcon from '@material-ui/icons/Search' -import TextField from '@material-ui/core/TextField' -import InputAdornment from '@material-ui/core/InputAdornment' -import Paper from '@material-ui/core/Paper' +import SearchIcon from '@mui/icons-material/Search' +import TextField from '@mui/material/TextField' +import InputAdornment from '@mui/material/InputAdornment' +import Paper from '@mui/material/Paper' +import Box from '@mui/material/Box' import _get from 'lodash.get' -import MenuItem from '@material-ui/core/MenuItem' +import MenuItem from '@mui/material/MenuItem' + +import useDebounce from '../../hooks/useDebounce' +import { GET_ITEM_BY_NAME } from '../../gql' import styles from './styles' @@ -20,61 +23,63 @@ const useStyles = makeStyles(styles) const InputAutocomplete = ({ ...props }) => { const classes = useStyles() + const history = useHistory() const { t } = useTranslation('translations') - const dispatch = useDispatch() - const { list } = useSelector((state) => state.blockProducers) - const { proxies } = useSelector((state) => state.proxies) + const [searchText, setSearchText] = useState('') + const debouncedAccount = useDebounce(searchText, 300) + const [getData, { loading, data }] = useLazyQuery(GET_ITEM_BY_NAME, { + fetchPolicy: 'network-only' + }) const [suggestions, setSuggestions] = useState([]) - const [text, setText] = useState('') - const [data, setData] = useState([]) useEffect(() => { - const getData = async () => { - await dispatch.blockProducers.getBPs() - await dispatch.proxies.getProxies() + if (loading || !data) { + return } - getData() - }, []) - - useEffect(() => { - const bpsList = (list || []).map((bp) => { + const { producers, proxies } = data + const bpsList = (producers || []).map(bp => { const name = _get(bp, 'bpjson.org.candidate_name', bp.owner) - return { name, owner: bp.owner, path: '/block-producers/' } + return { owner: bp.owner, name, path: '/block-producers/' } }) - const proxiesList = (proxies || []).map((proxy) => { - const name = _get(proxy, 'name', proxy.owner) - - return { name, owner: proxy.owner, path: '/proxies/' } + const proxiesList = (proxies || []).map(proxy => { + return { ...proxy, path: '/proxies/' } }) - setData([...bpsList, ...proxiesList]) - }, [list, proxies]) + setSuggestions([...bpsList, ...proxiesList]) + }, [data, loading]) + + useEffect(() => { + const getDataAsync = async () => { + await getData({ variables: { name: `%${debouncedAccount}%` } }) + } + + if (debouncedAccount.length) { + getDataAsync(debouncedAccount) + } + }, [debouncedAccount]) - const renderInputComponent = (inputProps) => { + const renderInputComponent = inputProps => { const { inputRef = () => {}, ref, classes, ...other } = inputProps - const { hideSearchIcon, isFocused } = props + const { hideSearchIcon, isFocused = true } = props return ( { + inputRef: node => { ref(node) inputRef(node) }, - disableUnderline: true, + disableunderline: 'true', fullWidth: true, startAdornment: hideSearchIcon ? null : ( - ), - classes: { - input: classes.input - } + ) }} classes={{ root: classes.root @@ -96,52 +101,40 @@ const InputAutocomplete = ({ ...props }) => { ) - const getSuggestions = (list, value) => { - return filterObjects.filter( - { - name: new RegExp(`${value.trim()}`, 'gi') - }, - list - ) - } - const getSuggestionValue = ({ name }) => name - const handleSuggestionsFetchRequested = - (list) => - ({ value }) => - setSuggestions(getSuggestions(list, value)) + const handleSuggestionsFetchRequested = ({ value }) => { + setSearchText(value) + } const handleSuggestionsClearRequested = () => { - setText('') + setSearchText('') setSuggestions([]) } const handleSelected = (event, { newValue }) => { - setText(newValue) + setSearchText(newValue) } - const handleSelectedSuggestion = (event, { suggestion }) => { - navigate(`${suggestion.path}${suggestion.owner}`) + const handleSelectedSuggestion = (e, { suggestion }) => { + history.push(`${suggestion.path}${suggestion.owner}`) props.onItemSelected && props.onItemSelected() } return ( -
+ { - handleSuggestionsFetchRequested(data)(event) - }} + onSuggestionsFetchRequested={handleSuggestionsFetchRequested} onSuggestionsClearRequested={() => handleSuggestionsClearRequested()} getSuggestionValue={getSuggestionValue} renderSuggestion={renderSuggestion} inputProps={{ classes, placeholder: t('searchAutocomplete'), - value: text, + value: searchText, onChange: handleSelected }} theme={{ @@ -150,13 +143,13 @@ const InputAutocomplete = ({ ...props }) => { suggestionsList: classes.suggestionsList, suggestion: classes.suggestion }} - renderSuggestionsContainer={(options) => ( + renderSuggestionsContainer={options => ( {options.children} )} /> -
+ ) } diff --git a/webapp/src/components/InputAutocomplete/styles.js b/webapp/src/components/InputAutocomplete/styles.js new file mode 100644 index 00000000..03a2ffb3 --- /dev/null +++ b/webapp/src/components/InputAutocomplete/styles.js @@ -0,0 +1,62 @@ +export default theme => ({ + root: { + flexGrow: 1, + '& input': { + color: theme.palette.common.white, + fontFamily: 'Roboto', + fontStyle: 'normal', + fontWeight: 'normal', + fontSize: 20, + lineHeight: '23px' + }, + '& .MuiOutlinedInput-notchedOutline': { + borderColor: 'transparent !important' + } + }, + container: { + position: 'relative', + margin: 'auto', + borderRadius: 4, + width: '100%', + [theme.breakpoints.up('md')]: { + width: 344, + height: 58, + backgroundColor: 'rgba(0, 0, 0, 0.50)', + '&:hover': { + backgroundColor: 'rgba(0, 0, 0, 0.45)' + } + } + }, + suggestionsContainerOpen: { + position: 'absolute', + zIndex: 1, + marginTop: theme.spacing(1), + left: '-24px', + right: 0, + width: '100vw', + [theme.breakpoints.up('md')]: { + left: 0, + width: 'auto' + } + }, + highlightMatch: { + fontWeight: 600 + }, + suggestion: { + display: 'block' + }, + suggestionsList: { + margin: 0, + padding: 0, + listStyleType: 'none' + }, + inputAdornment: { + margin: '5px 25px 5px 0', + [theme.breakpoints.up('md')]: { + margin: '5px 25px' + } + }, + searchIcon: { + color: theme.palette.common.white + } +}) diff --git a/webapp/src/components/language-select/index.js b/webapp/src/components/LanguageSelector/index.js similarity index 68% rename from webapp/src/components/language-select/index.js rename to webapp/src/components/LanguageSelector/index.js index 94d3f96e..3af9a09e 100644 --- a/webapp/src/components/language-select/index.js +++ b/webapp/src/components/LanguageSelector/index.js @@ -1,27 +1,27 @@ -import React, { useState } from 'react' +import React, { useState, memo } from 'react' import PropTypes from 'prop-types' -import { Language as LanguageIcon } from '@material-ui/icons' +import LanguageIcon from '@mui/icons-material/Language' import { useTranslation } from 'react-i18next' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/styles' -import IconButton from '@material-ui/core/IconButton' -import Menu from '@material-ui/core/Menu' -import MenuItem from '@material-ui/core/MenuItem' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' +import IconButton from '@mui/material/IconButton' +import Menu from '@mui/material/Menu' +import MenuItem from '@mui/material/MenuItem' import styles from './styles' const useStyles = makeStyles(styles) -const LanguageSelect = ({ style, alt }) => { +const LanguageSelector = ({ style, alt }) => { const { i18n } = useTranslation('translations') const classes = useStyles() const [anchorEl, setAnchorEl] = useState(null) - const handleClick = (event) => { + const handleClick = event => { setAnchorEl(event.currentTarget) } - const handleClose = (item) => { + const handleClose = item => { setAnchorEl(null) if (typeof item === 'string') { localStorage.setItem('LANGUAGE', item) @@ -48,13 +48,13 @@ const LanguageSelect = ({ style, alt }) => { <> - + {(i18n.language || '').toLocaleUpperCase().substring(0, 2)} {languages.length && - languages.map((item) => ( + languages.map(item => ( handleClose(item.value)} @@ -67,9 +67,9 @@ const LanguageSelect = ({ style, alt }) => { ) } -LanguageSelect.propTypes = { +LanguageSelector.propTypes = { alt: PropTypes.string, style: PropTypes.any } -export default LanguageSelect +export default memo(LanguageSelector) diff --git a/webapp/src/components/LanguageSelector/styles.js b/webapp/src/components/LanguageSelector/styles.js new file mode 100644 index 00000000..723874c5 --- /dev/null +++ b/webapp/src/components/LanguageSelector/styles.js @@ -0,0 +1,23 @@ +export default theme => ({ + wrapper: { + color: 'inherit' + }, + languageText: { + display: 'none', + [theme.breakpoints.up('md')]: { + marginLeft: `${theme.spacing(0.5)} !important`, + display: 'inline', + color: theme.palette.common.white, + fontFamily: 'Roboto', + fontStyle: 'normal', + fontWeight: 'normal', + fontSize: 20, + lineHeight: '23px' + } + }, + iconLanguage: { + width: 24, + height: 24, + color: theme.palette.common.white + } +}) diff --git a/webapp/src/components/Loader/index.js b/webapp/src/components/Loader/index.js new file mode 100644 index 00000000..a680fb2b --- /dev/null +++ b/webapp/src/components/Loader/index.js @@ -0,0 +1,20 @@ +import React from 'react' +import { makeStyles } from '@mui/styles' +import CircularProgress from '@mui/material/CircularProgress' +import Box from '@mui/material/Box' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const Loader = () => { + const classes = useStyles() + + return ( + + + + ) +} + +export default Loader diff --git a/webapp/src/components/Loader/styles.js b/webapp/src/components/Loader/styles.js new file mode 100644 index 00000000..218ab7a8 --- /dev/null +++ b/webapp/src/components/Loader/styles.js @@ -0,0 +1,8 @@ +export default () => ({ + root: { + justifyContent: 'center', + alignItems: 'center', + display: 'flex', + minHeight: '100%' + } +}) diff --git a/webapp/src/components/Message/index.js b/webapp/src/components/Message/index.js new file mode 100644 index 00000000..06a1908c --- /dev/null +++ b/webapp/src/components/Message/index.js @@ -0,0 +1,48 @@ +import React, { useEffect, useState } from 'react' +import { makeStyles } from '@mui/styles' +import Snackbar from '@mui/material/Snackbar' +import Alert from '@mui/material/Alert' + +import { useSharedState } from '../../context/state.context' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const Message = () => { + const [open, setOpen] = useState(false) + const [{ message }, { hideMessage }] = useSharedState() + const classes = useStyles() + + const handleClose = (event, reason) => { + if (reason === 'clickaway') { + return + } + + setOpen(false) + hideMessage() + } + + useEffect(() => { + if (open === !!message) { + return + } + + setOpen(!!message) + }, [message]) + + return ( + + + {message?.content} + + + ) +} + +export default Message diff --git a/webapp/src/components/Message/styles.js b/webapp/src/components/Message/styles.js new file mode 100644 index 00000000..72e960da --- /dev/null +++ b/webapp/src/components/Message/styles.js @@ -0,0 +1,8 @@ +export default theme => ({ + alert: { + '& a': { + color: theme.palette.info.contrastText, + lineBreak: 'anywhere' + } + } +}) diff --git a/webapp/src/components/mobile-search/index.js b/webapp/src/components/MobileSearch/index.js similarity index 68% rename from webapp/src/components/mobile-search/index.js rename to webapp/src/components/MobileSearch/index.js index 2eb0c9b2..e19694c5 100644 --- a/webapp/src/components/mobile-search/index.js +++ b/webapp/src/components/MobileSearch/index.js @@ -1,14 +1,14 @@ import React, { forwardRef } from 'react' import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/styles' -import Dialog from '@material-ui/core/Dialog' -import AppBar from '@material-ui/core/AppBar' -import Toolbar from '@material-ui/core/Toolbar' -import IconButton from '@material-ui/core/IconButton' -import CloseIcon from '@material-ui/icons/Close' -import Slide from '@material-ui/core/Slide' +import { makeStyles } from '@mui/styles' +import Dialog from '@mui/material/Dialog' +import AppBar from '@mui/material/AppBar' +import Toolbar from '@mui/material/Toolbar' +import IconButton from '@mui/material/IconButton' +import CloseIcon from '@mui/icons-material/Close' +import Slide from '@mui/material/Slide' -import InputAutocomplete from 'components/input-autocomplete' +import InputAutocomplete from '../InputAutocomplete' import styles from './styles' @@ -46,4 +46,9 @@ MobileSearch.propTypes = { onClose: PropTypes.func } +MobileSearch.defaultProps = { + isOpen: false, + onClose: () => {} +} + export default MobileSearch diff --git a/webapp/src/components/mobile-search/styles.js b/webapp/src/components/MobileSearch/styles.js similarity index 100% rename from webapp/src/components/mobile-search/styles.js rename to webapp/src/components/MobileSearch/styles.js diff --git a/webapp/src/components/PageTitle/index.js b/webapp/src/components/PageTitle/index.js new file mode 100644 index 00000000..3cd0705a --- /dev/null +++ b/webapp/src/components/PageTitle/index.js @@ -0,0 +1,21 @@ +import React, { memo } from 'react' +import Helmet from 'react-helmet' +import PropTypes from 'prop-types' + +import { mainConfig } from '../../config' + +const PageTitle = ({ title }) => ( + + {title} + +) + +PageTitle.propTypes = { + title: PropTypes.string +} + +PageTitle.defaultProps = { + title: mainConfig.title +} + +export default memo(PageTitle) diff --git a/webapp/src/components/parameter-range-selector/index.js b/webapp/src/components/ParameterRangeSelector/index.js similarity index 87% rename from webapp/src/components/parameter-range-selector/index.js rename to webapp/src/components/ParameterRangeSelector/index.js index 385bb173..40d244da 100644 --- a/webapp/src/components/parameter-range-selector/index.js +++ b/webapp/src/components/ParameterRangeSelector/index.js @@ -1,5 +1,5 @@ import React from 'react' -import { useTheme } from '@material-ui/core/styles' +import { useTheme } from '@mui/material/styles' import Slider, { createSliderWithTooltip } from 'rc-slider' import './style.css' @@ -14,7 +14,7 @@ const ParameterRangeSelector = ({ ...props }) => { min={0} max={100} trackStyle={[{ backgroundColor: theme.palette.secondary.dark }]} - tipFormatter={(value) => `${value ? value / 10 : 0}`} + tipFormatter={value => `${value ? value / 10 : 0}`} handleStyle={[ { backgroundColor: theme.palette.secondary.main, diff --git a/webapp/src/components/parameter-range-selector/style.css b/webapp/src/components/ParameterRangeSelector/style.css similarity index 100% rename from webapp/src/components/parameter-range-selector/style.css rename to webapp/src/components/ParameterRangeSelector/style.css diff --git a/webapp/src/components/PolarChart/index.js b/webapp/src/components/PolarChart/index.js new file mode 100644 index 00000000..1d1341d4 --- /dev/null +++ b/webapp/src/components/PolarChart/index.js @@ -0,0 +1,54 @@ +import React, { useState } from 'react' +import PropTypes from 'prop-types' +import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' +import Box from '@mui/material/Box' +import HighchartsReact from 'highcharts-react-official' +import Highcharts from 'highcharts' +import HighchartsMore from 'highcharts/highcharts-more' + +import { polarCharConfig } from '../../config' + +import styles from './styles' + +HighchartsMore(Highcharts) + +const useStyles = makeStyles(styles) + +const PolarChart = ({ data = [], showLegend = false }) => { + const { t } = useTranslation('translations') + const classes = useStyles() + const [options] = useState(polarCharConfig.options) + + return ( + + + + ) +} + +PolarChart.propTypes = { + data: PropTypes.array, + showLegend: PropTypes.bool +} + +export default PolarChart diff --git a/webapp/src/components/PolarChart/styles.js b/webapp/src/components/PolarChart/styles.js new file mode 100644 index 00000000..f4572e3b --- /dev/null +++ b/webapp/src/components/PolarChart/styles.js @@ -0,0 +1,13 @@ +export default theme => ({ + highchartsFigure: { + margin: 0, + width: '100% !important', + '& .highcharts-container ': { + margin: 0, + [theme.breakpoints.down('md')]: { + margin: 0, + width: '100% !important' + } + } + } +}) diff --git a/webapp/src/components/rate-slider/index.js b/webapp/src/components/RateSlider/index.js similarity index 50% rename from webapp/src/components/rate-slider/index.js rename to webapp/src/components/RateSlider/index.js index 25920ab7..7c780793 100644 --- a/webapp/src/components/rate-slider/index.js +++ b/webapp/src/components/RateSlider/index.js @@ -1,14 +1,14 @@ -import { withStyles } from '@material-ui/core/styles' -import Slider from '@material-ui/core/Slider' +import { styled } from '@mui/material/styles' +import Slider from '@mui/material/Slider' -const RateSlider = withStyles({ - root: { - color: '#597a81', - height: 2, - padding: '15px 0' - }, - thumb: { - backgroundColor: '#597a81', +const RateSlider = styled(Slider)({ + color: '#443f56', + height: 2, + padding: '15px 0', + '& .MuiSlider-thumb': { + width: 15, + height: 15, + backgroundColor: '#443f56', boxShadow: '0 3px 1px rgba(0,0,0,0.1),0 4px 8px rgba(0,0,0,0.13),0 0 0 1px rgba(0,0,0,0.02)', '&:focus,&:hover,&$active': { @@ -21,33 +21,35 @@ const RateSlider = withStyles({ } } }, - active: {}, - valueLabel: { + '& .MuiSlider-valueLabel': { left: 'auto', - top: -15, + top: 0, + background: 'transparent', '& *': { background: 'transparent', - color: '#000' + color: '#000', + fontSize: 12, + fontWeight: '400' } }, - track: { - height: 2 + '& .MuiSlider-track': { + height: 0 }, - rail: { - height: 2, + '& .MuiSlider-rail': { + height: 4, opacity: 0.5, - backgroundColor: '#010318' + backgroundColor: '#9e9e9e' }, - mark: { - backgroundColor: '#010318', - height: 8, - width: 1, - marginTop: -3 + '& .MuiSlider-mark': { + backgroundColor: '#9e9e9e', + height: 16, + width: 2, + marginTop: 0 }, - markActive: { + '& .MuiSlider-markActive': { opacity: 1, backgroundColor: 'currentColor' } -})(Slider) +}) export default RateSlider diff --git a/webapp/src/components/Sidebar/eosrate256.png b/webapp/src/components/Sidebar/eosrate256.png new file mode 100644 index 00000000..b7fc5197 Binary files /dev/null and b/webapp/src/components/Sidebar/eosrate256.png differ diff --git a/webapp/src/components/Sidebar/index.js b/webapp/src/components/Sidebar/index.js new file mode 100644 index 00000000..ba0f4863 --- /dev/null +++ b/webapp/src/components/Sidebar/index.js @@ -0,0 +1,132 @@ +import React, { memo } from 'react' +import PropTypes from 'prop-types' +import { NavLink as RouterNavLink, useHistory } from 'react-router-dom' +import { useTranslation } from 'react-i18next' +import Box from '@mui/material/Box' +import Drawer from '@mui/material/Drawer' +import Divider from '@mui/material/Divider' +import List from '@mui/material/List' +import MuiListItem from '@mui/material/ListItem' +import ListItemIcon from '@mui/material/ListItemIcon' +import ListItemText from '@mui/material/ListItemText' +import Typography from '@mui/material/Typography' +import AccountIcon from '@mui/icons-material/AccountCircle' +import { makeStyles } from '@mui/styles' +import Scrollbar from 'react-perfect-scrollbar' +import 'react-perfect-scrollbar/dist/css/styles.css' + +import { useSharedState } from '../../context/state.context' + +import styles from './styles' +import eosrateImg from './eosrate256.png' + +const useStyles = makeStyles(styles) + +const NavLink = React.forwardRef((props, ref) => ( + +)) + +NavLink.displayName = 'NavLink' + +const ExternalLink = React.forwardRef(({ to, children, className }, ref) => ( + + {children} + +)) + +ExternalLink.displayName = 'NavLink' + +ExternalLink.propTypes = { + to: PropTypes.string, + children: PropTypes.node, + className: PropTypes.string +} + +const ListItem = ({ childrens, name, path, icon, isUserLogged }) => { + const classes = useStyles() + const { t } = useTranslation('translations') + + if (name === 'myAccount' && !isUserLogged) return <> + + return ( + + + {icon && {icon}} + + + + ) +} + +ListItem.propTypes = { + childrens: PropTypes.array, + name: PropTypes.string, + path: PropTypes.string, + icon: PropTypes.node, + isUserLogged: PropTypes.bool +} + +const Sidebar = ({ routes, ...props }) => { + const history = useHistory() + const classes = useStyles() + const [state] = useSharedState() + + return ( + + + {state.user ? ( + <> + + Welcome + + {state.user?.accountName || ''} + + + ) : ( + eos rate history.push('/')} + width={256} + height={75} + /> + )} + + + + + {routes.map((route, index) => ( + + ))} + + + + ) +} + +Sidebar.propTypes = { + routes: PropTypes.array +} + +export default memo(Sidebar) diff --git a/webapp/src/components/Sidebar/styles.js b/webapp/src/components/Sidebar/styles.js new file mode 100644 index 00000000..cde376c0 --- /dev/null +++ b/webapp/src/components/Sidebar/styles.js @@ -0,0 +1,98 @@ +export default theme => ({ + brand: { + backgroundColor: theme.palette.background.paper, + display: 'flex', + justifyContent: 'center', + flexDirection: 'column', + height: 169, + '& img': { + height: 'fit-content', + width: '95%' + }, + '& img:hover': { + cursor: 'pointer' + } + }, + scrollbar: { + backgroundColor: theme.palette.background.paper + }, + badge: { + fontWeight: theme.typography.fontWeightBold, + height: '20px', + backgroundColor: theme.palette.primary.main, + '& span.MuiChip-label, & span.MuiChip-label:hover': { + cursor: 'pointer', + color: theme.palette.primary.contrastText, + padding: theme.spacing(0, 1) + } + }, + listItem: { + display: 'flex', + flexDirection: 'column', + '& p': { + fonWeight: theme.typography.fontWeightBold, + paddingLeft: theme.spacing(2), + cursor: 'default' + }, + '& .MuiBox-root': { + width: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center' + }, + '& .MuiCollapse-container': { + width: '100%', + paddingLeft: theme.spacing(2) + }, + '& .MuiListItemText-root .MuiTypography-root': { + fontSize: theme.typography.subtitle2.fontSize + }, + '& .active': { + backgroundColor: theme.palette.action.selected, + borderRadius: 4 + }, + '& .MuiListItem-button:hover': { + borderRadius: 4 + } + }, + linkSidebar: { + padding: theme.spacing(2, 1), + '& > svg': { + display: 'none' + } + }, + navBox: { + paddingLeft: theme.spacing(1), + paddingRight: theme.spacing(1) + }, + subMenu: { + borderRadius: 4 + }, + subMenuWrapper: { + backgroundColor: theme.palette.surface.dark + }, + welcome: { + fontStyle: 'normal', + fontWeight: '500', + fontSize: '20px !important', + lineHeight: '23px', + letterSpacing: '0.15px', + color: 'rgba(0, 0, 0, 0.87)', + marginBottom: `${theme.spacing(1)} !important`, + marginLeft: `${theme.spacing(2)} !important` + }, + userName: { + fontStyle: 'normal', + fontWeight: 'normal', + fontSize: '14px !important', + lineHeight: '20px', + letterSpacing: '0.25px', + color: 'rgba(0, 0, 0, 0.6)', + marginLeft: `${theme.spacing(2)} !important` + }, + icon: { + fontSize: '48px !important', + marginBottom: theme.spacing(2), + marginLeft: theme.spacing(2) + } +}) diff --git a/webapp/src/components/table/index.js b/webapp/src/components/Table/index.js similarity index 71% rename from webapp/src/components/table/index.js rename to webapp/src/components/Table/index.js index 565448a2..64d6e2ca 100644 --- a/webapp/src/components/table/index.js +++ b/webapp/src/components/Table/index.js @@ -1,11 +1,11 @@ import React from 'react' import PropTypes from 'prop-types' -import Table from '@material-ui/core/Table' -import TableBody from '@material-ui/core/TableBody' -import TableCell from '@material-ui/core/TableCell' -import TableContainer from '@material-ui/core/TableContainer' -import TableHead from '@material-ui/core/TableHead' -import TableRow from '@material-ui/core/TableRow' +import Table from '@mui/material/Table' +import TableBody from '@mui/material/TableBody' +import TableCell from '@mui/material/TableCell' +import TableContainer from '@mui/material/TableContainer' +import TableHead from '@mui/material/TableHead' +import TableRow from '@mui/material/TableRow' const BasicTable = ({ rows, heads }) => { return ( @@ -13,7 +13,7 @@ const BasicTable = ({ rows, heads }) => { - {heads.map((head) => ( + {heads.map(head => ( { - {rows.map((row) => ( + {rows.map(row => ( {row.rater} {row.amount} diff --git a/webapp/src/components/video/index.js b/webapp/src/components/Video/index.js similarity index 100% rename from webapp/src/components/video/index.js rename to webapp/src/components/Video/index.js diff --git a/webapp/src/components/app-bar/index.js b/webapp/src/components/app-bar/index.js deleted file mode 100644 index 144fd232..00000000 --- a/webapp/src/components/app-bar/index.js +++ /dev/null @@ -1,202 +0,0 @@ -import React, { useEffect, useState } from 'react' -import PropTypes from 'prop-types' -import { useTranslation } from 'react-i18next' -import AccountCircleIcon from '@material-ui/icons/AccountCircle' -import { useDispatch, useSelector } from 'react-redux' -import AppBar from '@material-ui/core/AppBar' -import CircularProgress from '@material-ui/core/CircularProgress' -import FingerprintIcon from '@material-ui/icons/Fingerprint' -import IconButton from '@material-ui/core/IconButton' -import LogoutIcon from '@material-ui/icons/ExitToApp' -import MenuIcon from '@material-ui/icons/Menu' -import SearchIcon from '@material-ui/icons/Search' -import Toolbar from '@material-ui/core/Toolbar' -import Typography from '@material-ui/core/Typography' -import LockOpenOutlinedIcon from '@material-ui/icons/LockOpenOutlined' -import LockOutlinedIcon from '@material-ui/icons/LockOutlined' -import { alpha } from '@material-ui/core/styles' -import { makeStyles } from '@material-ui/styles' -import { Link } from '@reach/router' -import Tooltip from '@material-ui/core/Tooltip' -import Box from '@material-ui/core/Box' - -import InputAutocomplete from 'components/input-autocomplete' -import LanguageSelect from 'components/language-select' -import MobileSearch from 'components/mobile-search' -import { stage } from '../../config' - -import styles from './styles' - -const useStyles = makeStyles((theme) => styles(theme, alpha)) - -const MainTopBar = ({ - isSearchOpen, - handleDrawerToggle, - handleSearchDialogOpen, - handleSearchDialogClose, - ual -}) => { - const classes = useStyles() - const dispatch = useDispatch() - const { t } = useTranslation('translations') - const { data: user } = useSelector((state) => state.user) - const [mayVote, setMayVote] = useState(false) - - const handleSetUser = () => dispatch.user.removeBlockProducersVotedByUser() - - const StyleTooltip = makeStyles((theme) => ({ - arrow: { - color: 'rgba(97, 97, 97, 0.9)', - marginLeft: 30 - }, - tooltip: { - boxShadow: theme.shadows[1], - width: 140, - fontSize: 14, - textAlign: 'center' - } - })) - - function SpecialTooltip(props) { - const classes = StyleTooltip() - - return - } - - useEffect(() => { - const getData = async () => { - if (ual.activeUser) { - await dispatch.user.getUserChainData({ ual }) - } else { - handleSetUser() - } - } - - if (ual) getData() - }, [ual]) - - useEffect(async () => { - if (!user) setMayVote(false) - else if ( - user.voter_info && - (user.voter_info.producers.length > 20 || - user.voter_info.proxy.length > 0) - ) - setMayVote(true) - }, [user]) - - return ( - - - - - - - EOS Rate - -
-
- -
-
- - - - - {user && ( - <> - {!user.edenMember && ( - <> - {mayVote && ( - - - - )} - {!mayVote && ( - - - - )} - - )} - {user.edenMember && ( - - eden icon - - )} - - )} - - - {ual.activeUser ? ( - <> - - - - - {ual.activeUser.accountName} - - - - { - ual.logout() - handleSetUser() - }} - > - - - - ) : ( - <> - ual.showModal()}> - {ual.loading ? ( - - ) : ( - <> - - - {t('appBarSignIn')} - - - )} - - - )} - - - - ) -} - -MainTopBar.propTypes = { - handleDrawerToggle: PropTypes.func, - handleSearchDialogOpen: PropTypes.func, - handleSearchDialogClose: PropTypes.func, - isSearchOpen: PropTypes.bool, - ual: PropTypes.object -} - -export default MainTopBar diff --git a/webapp/src/components/app-bar/styles.js b/webapp/src/components/app-bar/styles.js deleted file mode 100644 index 9dbc02da..00000000 --- a/webapp/src/components/app-bar/styles.js +++ /dev/null @@ -1,82 +0,0 @@ -export default (theme, alpha) => ({ - root: { - flexGrow: 1 - }, - link: { - color: 'white', - textDecoration: 'none' - }, - linkHover: { - '&:hover': { - backgroundColor: 'rgba(255, 255, 255, 0.1)', - borderRadius: 10 - } - }, - grow: { - flexGrow: 1 - }, - title: { - width: 140, - [theme.breakpoints.up('sm')]: { - display: 'block', - width: 210 - } - }, - menuButton: { - marginLeft: -18, - [theme.breakpoints.up('sm')]: { - marginRight: 15 - } - }, - search: { - position: 'relative', - flexGrow: 1, - borderRadius: theme.shape.borderRadius, - backgroundColor: alpha(theme.palette.common.white, 0.15), - '&:hover': { - backgroundColor: alpha(theme.palette.common.white, 0.25) - }, - marginRight: theme.spacing(2), - marginLeft: 0, - width: '100%', - display: 'none', - [theme.breakpoints.up('md')]: { - display: 'block', - width: 'auto' - } - }, - mobileSearch: { - [theme.breakpoints.up('md')]: { - display: 'none' - } - }, - inputRoot: { - color: 'inherit', - width: '100%' - }, - inputInput: { - paddingTop: theme.spacing(1), - paddingRight: theme.spacing(1), - paddingBottom: theme.spacing(1), - paddingLeft: theme.spacing(10), - transition: theme.transitions.create('width'), - width: '100%', - [theme.breakpoints.up('md')]: { - width: 200 - } - }, - sessionText: { - marginLeft: 5, - display: 'none', - [theme.breakpoints.up('sm')]: { - display: 'inline' - } - }, - logoStyle: { - width: 110, - [theme.breakpoints.up('sm')]: { - display: 'block', - width: 180 - } - } -}) diff --git a/webapp/src/components/bottom-navbar/index.js b/webapp/src/components/bottom-navbar/index.js deleted file mode 100644 index 08919a63..00000000 --- a/webapp/src/components/bottom-navbar/index.js +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useState } from 'react' -import { makeStyles } from '@material-ui/styles' -import BottomNavigation from '@material-ui/core/BottomNavigation' -import BottomNavigationAction from '@material-ui/core/BottomNavigationAction' -import RestoreIcon from '@material-ui/icons/Restore' -import ShippingIcon from '@material-ui/icons/ControlPoint' -import { useTranslation } from 'react-i18next' -import SettingsIcon from '@material-ui/icons/Settings' -import { navigate } from '@reach/router' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const SimpleBottomNavigation = () => { - const [value] = useState(0) - const classes = useStyles() - const { t } = useTranslation('translations') - - const handleChange = (event, valueRoute) => { - event.preventDefault() - const routes = ['/recents', '/', '/settings'] - - navigate(routes[valueRoute]) - } - - return ( - <> - - } - /> - } - /> - } - /> - - - ) -} - -export default SimpleBottomNavigation diff --git a/webapp/src/components/bottom-navbar/styles.js b/webapp/src/components/bottom-navbar/styles.js deleted file mode 100644 index 6230aaef..00000000 --- a/webapp/src/components/bottom-navbar/styles.js +++ /dev/null @@ -1,9 +0,0 @@ -export default () => ({ - root: { - width: '100%', - background: '#fafafa', - position: 'fixed', - bottom: 0, - left: 0 - } -}) diff --git a/webapp/src/components/bp-chip-avatar/styles.js b/webapp/src/components/bp-chip-avatar/styles.js deleted file mode 100644 index 3007a7ca..00000000 --- a/webapp/src/components/bp-chip-avatar/styles.js +++ /dev/null @@ -1,9 +0,0 @@ -export default (props) => ({ - root: { - margin: 8, - color: 'white', - justifyContent: 'space-around', - width: 158, - backgroundColor: (props) => props.color - } -}) diff --git a/webapp/src/components/button/index.js b/webapp/src/components/button/index.js deleted file mode 100644 index 18c2dc7f..00000000 --- a/webapp/src/components/button/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react' -import { Button as MaterialButton } from '@material-ui/core' - -import FormControl from '../formControl' - -const Button = ({ ...props }) => ( - - - -) - -export default Button diff --git a/webapp/src/components/checkbox/index.js b/webapp/src/components/checkbox/index.js deleted file mode 100644 index 0e7fcc04..00000000 --- a/webapp/src/components/checkbox/index.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react' -import { Field } from 'formik' -import { InputLabel } from '@material-ui/core' -import { Checkbox as MaterialCheckbox } from 'formik-material-ui' -import PropTypes from 'prop-types' - -import FormControl from '../formControl' - -const Checkbox = ({ ...props }) => ( - - - {props.label} - -) - -Checkbox.propTypes = { - name: PropTypes.string.isRequired, - label: PropTypes.string.isRequired -} - -export default Checkbox diff --git a/webapp/src/components/compare-tool/compare-graph-view.js b/webapp/src/components/compare-tool/compare-graph-view.js deleted file mode 100644 index 4acf1088..00000000 --- a/webapp/src/components/compare-tool/compare-graph-view.js +++ /dev/null @@ -1,354 +0,0 @@ -import React, { useState, useEffect } from 'react' -import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/core/styles' -import Grid from '@material-ui/core/Grid' -import Typography from '@material-ui/core/Typography' -import FormControlLabel from '@material-ui/core/FormControlLabel' -import LockOpenIcon from '@material-ui/icons/LockOpenOutlined' -import LockIcon from '@material-ui/icons/LockOutlined' -import Button from '@material-ui/core/Button' -import Tooltip from '@material-ui/core/Tooltip' -import Box from '@material-ui/core/Box' -import withWidth from '@material-ui/core/withWidth' -import { useMediaQuery } from '@material-ui/core' -import { useTranslation } from 'react-i18next' -import Switch from '@material-ui/core/Switch' -import CloseIcon from '@material-ui/icons/Close' -import _get from 'lodash.get' - -import Radar from 'components/radar' -import ProducerChipAvatar from 'components/bp-chip-avatar' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const CompareBodyList = ({ isProxy, selectedData, classes, removeBP }) => { - if (!selectedData.length) return null - - if (isProxy) { - const proxy = selectedData[0] - const producers = _get(proxy, 'voter_info.producers', []) - - return ( - <> - {producers.map((producer) => { - const imageURL = _get(producer, 'bpjson.org.branding.logo_256', null) - - return ( - - ) - })} - - ) - } - - return ( -
- {selectedData.map((data) => { - const imageURL = _get(data, 'bpjson.org.branding.logo_256', null) - - return ( - - ) - })} -
- ) -} - -const TooltipWrapper = ({ - open, - onHandleTooltip, - isClickable, - t, - classes, - userHasVote, - isUser -}) => { - const message = userHasVote ? t('availableToRate') : t('notAvailableToRate') - - if (isClickable) { - return ( - - {userHasVote ? ( - - ) : ( - - )} - - ) - } - - return ( - - {userHasVote ? ( - - ) : ( - - )} - - ) -} - -const CompareGraphView = ({ - removeBP, - selected, - className, - isProxy, - userInfo, - width, - handleOnClear, - handleOnClose, - onHandleVote, - setIsCollapsedView, - isCollapsedView, - ...props -}) => { - const { t } = useTranslation('translations') - const classes = useStyles() - const isDesktop = useMediaQuery('(min-width:767px)') - const mobileMedium = useMediaQuery('(min-height:711px)') - const [sizes, setSizes] = useState() - - useEffect(() => { - setSizes(isDesktop ? 400 : '95%') - }, [isDesktop]) - - return ( - - - - - - {selected.length > 0 - ? `${t('voteToolTitle')} (${selected.length} ${t('chosen')})` - : `${t('voteToolTitle')} (${t('noBPSelected')})`} - - - {t('voteToolDescription')} - - - - - {isDesktop && ( - - - - - - )} - - - ({ - ...data, - backgroundColor: data.backgroundColor.replace('.9', '.2') - })) - }} - /> - - - - {isProxy && selected.length > 0 && ( - - - - {selected[0].name} - - - - - - - )} - {!isProxy && ( - - setIsCollapsedView(event.target.checked) - } - value='isCollapsedView' - /> - } - label={t('compareToolCollapsedSwitch')} - /> - )} - - - {!isDesktop && ( - - {selected.length > 0 ? ( - - ) : ( - - {t('noSelectedBP')} - - )} - - )} - {!isProxy && ( - - - - - - - - - - - - - )} - - {isDesktop && ( - - {selected.length > 0 ? ( - - ) : ( - - {t('noSelectedBP')} - - )} - - )} - - ) -} - -CompareGraphView.propTypes = { - width: PropTypes.oneOf(['lg', 'md', 'sm', 'xl', 'xs']).isRequired, - removeBP: PropTypes.func.isRequired, - selected: PropTypes.array.isRequired, - className: PropTypes.string, - isProxy: PropTypes.bool, - userInfo: PropTypes.object, - handleOnClear: PropTypes.func, - handleOnClose: PropTypes.func, - onHandleVote: PropTypes.func, - setIsCollapsedView: PropTypes.func, - isCollapsedView: PropTypes.bool -} - -CompareGraphView.defaultProps = { - className: '', - isProxy: false, - userInfo: { proxy: '', producers: [], isUser: false }, - onHandleVote: () => {}, - handleOnClear: () => {}, - handleOnClose: () => {}, - setIsCollapsedView: () => {}, - isCollapsedView: true -} - -CompareBodyList.propTypes = { - isProxy: PropTypes.bool, - selectedData: PropTypes.array, - classes: PropTypes.object.isRequired, - removeBP: PropTypes.func.isRequired -} - -TooltipWrapper.propTypes = { - classes: PropTypes.object, - isClickable: PropTypes.bool, - open: PropTypes.bool, - onHandleTooltip: PropTypes.func, - t: PropTypes.any, - userHasVote: PropTypes.bool, - isUser: PropTypes.bool.apply -} - -export default withWidth()(CompareGraphView) diff --git a/webapp/src/components/compare-tool/compare-slider-view.js b/webapp/src/components/compare-tool/compare-slider-view.js deleted file mode 100644 index cad38fd3..00000000 --- a/webapp/src/components/compare-tool/compare-slider-view.js +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useState, useEffect } from 'react' -import { makeStyles } from '@material-ui/core/styles' -import Typography from '@material-ui/core/Typography' -import { useMediaQuery } from '@material-ui/core' -import { useTranslation } from 'react-i18next' -import PropTypes from 'prop-types' -import _get from 'lodash.get' - -import Radar from 'components/radar' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const CompareSliderView = ({ - selected, - className, - isProxy, - optionalLabel, - ...props -}) => { - const { t } = useTranslation('translations') - const classes = useStyles() - const isDesktop = useMediaQuery('(min-width:767px)') - const [sizes, setSizes] = useState() - - useEffect(() => { - setSizes(isDesktop ? 400 : '95%') - }, [isDesktop]) - - return ( -
- - {isProxy ? optionalLabel : t('compareToolTitle')} - -
- {selected.map((bp) => { - if (!bp) return null - - const name = isProxy - ? _get(bp, 'owner') - : _get(bp, 'bpjson.producer_account_name') - - return ( -
- - - {name} - -
- ) - })} -
-
- ) -} - -CompareSliderView.propTypes = { - selected: PropTypes.array.isRequired, - className: PropTypes.string, - isProxy: PropTypes.bool, - optionalLabel: PropTypes.string -} - -CompareSliderView.defaultProps = {} - -export default CompareSliderView diff --git a/webapp/src/components/compare-tool/styles.js b/webapp/src/components/compare-tool/styles.js deleted file mode 100644 index cf0026b8..00000000 --- a/webapp/src/components/compare-tool/styles.js +++ /dev/null @@ -1,174 +0,0 @@ -export default (theme) => ({ - // index - root: { - padding: theme.spacing(2), - background: theme.palette.surface.main, - width: '100%', - position: 'relative' - }, - footer: { - display: 'flex', - flexDirection: 'row', - justifyContent: 'center', - width: '100%', - [theme.breakpoints.up('sm')]: { - flexDirection: 'row', - justifyContent: 'space-evenly', - margin: 'auto', - bottom: 0, - width: 'calc(50% - 16px)' - } - }, - switch: { - [theme.breakpoints.up('sm')]: { - float: 'right' - } - }, - btnRate: { - backgroundColor: theme.palette.secondary.main, - marginBottom: 5, - color: '#ffffff', - padding: '5px 20px 5px 20px', - [theme.breakpoints.up('sm')]: { - float: 'right', - marginRight: 20, - '&:hover': { - backgroundColor: theme.palette.secondary.dark - } - } - }, - chipMessage: { - [theme.breakpoints.up('sm')]: { - float: 'right', - marginTop: 5, - marginRight: 5 - } - }, - errorColor: { - backgroundColor: 'red' - }, - errorChip: { - border: '1px solid red' - }, - labelErrorColor: { - color: 'red' - }, - // slider view - bpName: { - paddingTop: 10, - textAlign: 'center' - }, - slider: { - display: 'flex', - flexWrap: 'nowrap', - overflowX: 'auto', - '-webkit-overflow-scrolling': 'touch', - '&::-webkit-scrollbar': { - display: 'none' - } - }, - sliderCard: { - flex: '0 0 auto', - width: 360, - paddingRight: 16 - }, - // graph view - bpItem: { - width: '75%', - padding: '0 0 0 10px', - display: 'flex', - justifyContent: 'space-between', - '&:hover': { - backgroundColor: theme.palette.primary.submenu - } - }, - bpNameWrapper: { - height: 48, - paddingTop: 14 - }, - bpColorCode: { - display: 'inline-block', - width: 15, - height: 15, - verticalAlign: 'text-bottom' - }, - title: { - textDecoration: 'none', - color: theme.palette.primary.main - }, - avatar: { - backgroundColor: theme.palette.surface.main - }, - helpIcon: { - width: '90%', - height: '90%' - }, - cardHeader: { - borderBottom: `1px solid ${theme.palette.primary.light}` - }, - titleLock: { - display: 'flex', - justifyContent: 'stretch', - alignItems: 'center' - }, - headerVotingCompare: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center' - }, - marginRightElem: { - marginRight: 10 - }, - icon: { - color: theme.palette.primary.submenu, - fontSize: 30, - '&:hover': { - cursor: 'pointer' - } - }, - containerList: { - height: '100%', - overflow: 'auto', - [theme.breakpoints.up('sm')]: { - marginBottom: 38 - } - }, - centerBox: { - margin: 'auto', - width: '45%', - padding: '5px', - [theme.breakpoints.down('sm')]: { - width: '100%' - } - }, - buttonsBox: { - [theme.breakpoints.down('sm')]: { - bottom: 0, - position: 'absolute', - left: 0 - } - }, - boxCloseIcon: { - justifyContent: 'flex-end', - display: 'flex', - alignItems: 'center', - height: '100%' - }, - btnRateProxies: { - backgroundColor: theme.palette.secondary.main, - color: '#ffffff', - width: '100px', - padding: '5px 20px 5px 20px', - [theme.breakpoints.up('sm')]: { - '&:hover': { - backgroundColor: theme.palette.secondary.dark - } - } - }, - reliefGrid: { - border: '1px solid #f8f8f8', - boxShadow: - 'inset 2px 2px 2px #fff, inset -1px 0 2px rgba(0,0,0,.1), 1px 3px 3px rgba(0,0,0,.1)', - backgroundColor: '#fff' - } -}) diff --git a/webapp/src/components/filter-select/index.js b/webapp/src/components/filter-select/index.js deleted file mode 100644 index eac51368..00000000 --- a/webapp/src/components/filter-select/index.js +++ /dev/null @@ -1,83 +0,0 @@ -import React, { useState, useEffect } from 'react' -import PropTypes from 'prop-types' -import { useTranslation } from 'react-i18next' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/styles' -import IconButton from '@material-ui/core/IconButton' -import Menu from '@material-ui/core/Menu' -import MenuItem from '@material-ui/core/MenuItem' -import FilterListIcon from '@material-ui/icons/FilterList' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const FilterSelect = ({ style, alt, onHandleApplySortBy }) => { - const { t, i18n } = useTranslation('sortInput') - const classes = useStyles() - const [anchorEl, setAnchorEl] = useState(null) - const [sort, setSort] = useState(t('sortby')) - - const handleClick = (event) => { - setAnchorEl(event.currentTarget) - } - - const handleClose = (item) => { - setAnchorEl(null) - - if (typeof item === 'string') { - setSort(t(item)) - onHandleApplySortBy(item) - } - } - - const filters = [ - { value: 'alphabetical', label: t('alphabetical') }, - { value: 'generalRate', label: t('generalRate') }, - { value: 'infrastructure', label: t('infrastructure') }, - { value: 'community', label: t('community') }, - { value: 'trustiness', label: t('trustiness') }, - { value: 'development', label: t('development') }, - { value: 'transparency', label: t('transparency') }, - { value: 'vote', label: t('vote') }, - { value: 'ratings', label: t('ratings') } - ] - - useEffect(() => { - setSort(t(sort)) - }, [i18n.language]) - - return ( - <> - - - - {sort || ''} - - - - {filters.length && - filters.map((item) => ( - handleClose(item.value)} - > - {item.label} - - ))} - - - ) -} - -FilterSelect.propTypes = { - alt: PropTypes.string, - style: PropTypes.any, - onHandleApplySortBy: PropTypes.func -} - -export default FilterSelect diff --git a/webapp/src/components/filter-select/styles.js b/webapp/src/components/filter-select/styles.js deleted file mode 100644 index e157e04f..00000000 --- a/webapp/src/components/filter-select/styles.js +++ /dev/null @@ -1,17 +0,0 @@ -export default (theme) => ({ - wrapper: { - color: 'inherit' - }, - sortText: { - fontSize: '1rem', - marginLeft: 3, - display: 'none', - [theme.breakpoints.up('sm')]: { - display: 'inline' - } - }, - iconFilter: { - width: 24, - height: 24 - } -}) diff --git a/webapp/src/components/formControl/index.js b/webapp/src/components/formControl/index.js deleted file mode 100644 index 1e5ea39d..00000000 --- a/webapp/src/components/formControl/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react' - -const FormControl = ({ ...props }) => ( -
-) - -export default FormControl diff --git a/webapp/src/components/github-icon/index.js b/webapp/src/components/github-icon/index.js deleted file mode 100644 index deb15905..00000000 --- a/webapp/src/components/github-icon/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import SvgIcon from '@material-ui/core/SvgIcon' - -const GithubIcon = () => ( - - - -) - -export default GithubIcon diff --git a/webapp/src/components/icon/communityIcon.js b/webapp/src/components/icon/communityIcon.js index 9e3dd354..4a50594a 100644 --- a/webapp/src/components/icon/communityIcon.js +++ b/webapp/src/components/icon/communityIcon.js @@ -1,12 +1,12 @@ -import React from 'react' -import SvgIcon from '@material-ui/core/SvgIcon' -import { makeStyles } from '@material-ui/core/styles' +import React, { memo } from 'react' +import SvgIcon from '@mui/material/SvgIcon' +import { makeStyles } from '@mui/styles' import styles from './styles' const useStyles = makeStyles(styles) -const CommunityIcon = (props) => { +const CommunityIcon = props => { const classes = useStyles() return ( @@ -28,4 +28,4 @@ const CommunityIcon = (props) => { ) } -export default CommunityIcon +export default memo(CommunityIcon) diff --git a/webapp/src/components/icon/developmentIcon.js b/webapp/src/components/icon/developmentIcon.js index 0b42b407..85530568 100644 --- a/webapp/src/components/icon/developmentIcon.js +++ b/webapp/src/components/icon/developmentIcon.js @@ -1,12 +1,12 @@ -import React from 'react' -import SvgIcon from '@material-ui/core/SvgIcon' -import { makeStyles } from '@material-ui/core/styles' +import React, { memo } from 'react' +import SvgIcon from '@mui/material/SvgIcon' +import { makeStyles } from '@mui/styles' import styles from './styles' const useStyles = makeStyles(styles) -const DevelopmentIcon = (props) => { +const DevelopmentIcon = props => { const classes = useStyles() return ( @@ -22,4 +22,4 @@ const DevelopmentIcon = (props) => { ) } -export default DevelopmentIcon +export default memo(DevelopmentIcon) diff --git a/webapp/src/components/icon/infrastructureIcon.js b/webapp/src/components/icon/infrastructureIcon.js index 22bc3888..44c65188 100644 --- a/webapp/src/components/icon/infrastructureIcon.js +++ b/webapp/src/components/icon/infrastructureIcon.js @@ -1,12 +1,12 @@ -import React from 'react' -import SvgIcon from '@material-ui/core/SvgIcon' -import { makeStyles } from '@material-ui/core/styles' +import React, { memo } from 'react' +import SvgIcon from '@mui/material/SvgIcon' +import { makeStyles } from '@mui/styles' import styles from './styles' const useStyles = makeStyles(styles) -const InfrastructureIcon = (props) => { +const InfrastructureIcon = props => { const classes = useStyles() return ( @@ -32,4 +32,4 @@ const InfrastructureIcon = (props) => { ) } -export default InfrastructureIcon +export default memo(InfrastructureIcon) diff --git a/webapp/src/components/icon/transparencyIcon.js b/webapp/src/components/icon/transparencyIcon.js index 954a6fd1..93d3322c 100644 --- a/webapp/src/components/icon/transparencyIcon.js +++ b/webapp/src/components/icon/transparencyIcon.js @@ -1,12 +1,12 @@ -import React from 'react' -import SvgIcon from '@material-ui/core/SvgIcon' -import { makeStyles } from '@material-ui/core/styles' +import React, { memo } from 'react' +import SvgIcon from '@mui/material/SvgIcon' +import { makeStyles } from '@mui/styles' import styles from './styles' const useStyles = makeStyles(styles) -const TransparencyIcon = (props) => { +const TransparencyIcon = props => { const classes = useStyles() return ( @@ -42,4 +42,4 @@ const TransparencyIcon = (props) => { ) } -export default TransparencyIcon +export default memo(TransparencyIcon) diff --git a/webapp/src/components/icon/trustinessIcon.js b/webapp/src/components/icon/trustinessIcon.js index 6d8db0b2..69361270 100644 --- a/webapp/src/components/icon/trustinessIcon.js +++ b/webapp/src/components/icon/trustinessIcon.js @@ -1,12 +1,12 @@ -import React from 'react' -import SvgIcon from '@material-ui/core/SvgIcon' -import { makeStyles } from '@material-ui/core/styles' +import React, { memo } from 'react' +import SvgIcon from '@mui/material/SvgIcon' +import { makeStyles } from '@mui/styles' import styles from './styles' const useStyles = makeStyles(styles) -const TrustinessIcon = (props) => { +const TrustinessIcon = props => { const classes = useStyles() return ( @@ -20,4 +20,4 @@ const TrustinessIcon = (props) => { ) } -export default TrustinessIcon +export default memo(TrustinessIcon) diff --git a/webapp/src/components/input-autocomplete/styles.js b/webapp/src/components/input-autocomplete/styles.js deleted file mode 100644 index 9116f94d..00000000 --- a/webapp/src/components/input-autocomplete/styles.js +++ /dev/null @@ -1,43 +0,0 @@ -export default (theme) => ({ - root: { - flexGrow: 1 - }, - container: { - position: 'relative' - }, - input: { - color: 'white' - }, - suggestionsContainerOpen: { - position: 'absolute', - zIndex: 1, - marginTop: theme.spacing(1), - left: '-24px', - right: 0, - width: '100vw', - [theme.breakpoints.up('md')]: { - left: 0, - width: 'auto' - } - }, - highlightMatch: { - fontWeight: 600 - }, - suggestion: { - display: 'block' - }, - suggestionsList: { - margin: 0, - padding: 0, - listStyleType: 'none' - }, - inputAdornment: { - margin: '5px 25px 5px 0', - [theme.breakpoints.up('md')]: { - margin: '5px 25px' - } - }, - searchIcon: { - fill: 'white' - } -}) diff --git a/webapp/src/components/language-select/styles.js b/webapp/src/components/language-select/styles.js deleted file mode 100644 index 29599438..00000000 --- a/webapp/src/components/language-select/styles.js +++ /dev/null @@ -1,17 +0,0 @@ -export default (theme) => ({ - wrapper: { - color: 'inherit' - }, - languageText: { - fontSize: '1rem', - marginLeft: theme.spacing(0.5), - display: 'none', - [theme.breakpoints.up('sm')]: { - display: 'inline' - } - }, - iconLanguage: { - width: 24, - height: 24 - } -}) diff --git a/webapp/src/components/layout/index.js b/webapp/src/components/layout/index.js deleted file mode 100644 index 4b6cc191..00000000 --- a/webapp/src/components/layout/index.js +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useState, useEffect } from 'react' -import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/styles' -import Hidden from '@material-ui/core/Hidden' -import classnames from 'classnames' - -import MainTopBar from 'components/app-bar' -import MainDrawer from 'components/main-drawer' -import MainFooter from 'components/main-footer' -import { InitGA, LogPageView } from 'config/google-analitycs-module' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const Layout = ({ children, ual }) => { - const classes = useStyles() - const [state, setState] = useState({ - isNavOpen: false, - isSearchOpen: false - }) - - const handleDrawerToggle = () => - setState({ ...state, isNavOpen: !state.isNavOpen }) - - const handleSearchDialogOpen = () => - setState({ ...state, isSearchOpen: true }) - - const handleSearchDialogClose = () => - setState({ ...state, isSearchOpen: false }) - - useEffect(() => { - InitGA() - LogPageView() - }, []) - - return ( -
- - - - - - - -
-
-
{children}
- -
-
- ) -} - -Layout.propTypes = { - children: PropTypes.object, - ual: PropTypes.object -} - -export default Layout diff --git a/webapp/src/components/layout/styles.js b/webapp/src/components/layout/styles.js deleted file mode 100644 index 944a28e8..00000000 --- a/webapp/src/components/layout/styles.js +++ /dev/null @@ -1,28 +0,0 @@ -export default (theme) => ({ - root: { - flexGrow: 1, - height: '100vh', - zIndex: 1, - overflow: 'hidden', - position: 'relative', - display: 'flex', - width: '100%' - }, - desktopDrawer: { - width: 240, - transition: 'width 225ms cubic-bezier(0, 0, 0.2, 1) 0ms' - }, - desktopDrawerHidden: { - width: 0 - }, - toolbar: theme.mixins.toolbar, - content: { - overflow: 'auto', - flexGrow: 1, - backgroundColor: theme.palette.background.default, - position: 'relative' - }, - contentWrapper: { - minHeight: 'calc(100vh - 128px)' - } -}) diff --git a/webapp/src/components/main-drawer/index.js b/webapp/src/components/main-drawer/index.js deleted file mode 100644 index 2ef20cf3..00000000 --- a/webapp/src/components/main-drawer/index.js +++ /dev/null @@ -1,190 +0,0 @@ -import React, { Fragment } from 'react' -import PropTypes from 'prop-types' -import { useSelector, useDispatch } from 'react-redux' -import Drawer from '@material-ui/core/Drawer' -import List from '@material-ui/core/List' -import Divider from '@material-ui/core/Divider' -import Box from '@material-ui/core/Box' -import Collapse from '@material-ui/core/Collapse' -import { makeStyles } from '@material-ui/styles' -import { useTheme } from '@material-ui/core/styles' -import ListItem from '@material-ui/core/ListItem' -import ListItemText from '@material-ui/core/ListItemText' -import Link from '@material-ui/core/Link' -import { useTranslation } from 'react-i18next' -import { appVersion } from '../../config' -import classnames from 'classnames' -import LaunchIcon from '@material-ui/icons/Launch' - -import routes from 'routes' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const Menu = ({ onClick, currentPathname, links, sortBy, setSortBy }) => { - const { t } = useTranslation('sortInput') - const classes = useStyles() - - return ( - - {links - .filter(({ label }) => label) - .map(({ to, label, target, collapsedItems }) => { - const isSelected = currentPathname === to - - return ( - - {(label === 'About' || label.includes('Versi')) && ( - - )} - onClick && onClick(!!collapsedItems)} - > - onClick && onClick(!!collapsedItems) - }} - selected={isSelected} - className={classnames({ [classes.linkSelected]: isSelected })} - > - {!label.includes('Versi') && } - {label.includes('Versi') && ( - <> - - - - )} - - - {collapsedItems && !!collapsedItems.length && ( - - {collapsedItems.map(({ value }, index) => ( - setSortBy(value)} - > - {t(value)} - - ))} - - )} - - ) - })} - - ) -} - -const MainDrawer = ({ - variant = 'desktop', - onClose, - open = false, - ...props -}) => { - const { t } = useTranslation('translations') - const classes = useStyles() - const theme = useTheme() - const dispatch = useDispatch() - const { sortBy } = useSelector((state) => state.blockProducers) - const { pathname: currentPathname } = useSelector((state) => state.location) - - const handleSortBy = (val) => dispatch.blockProducers.setSortBy(val) - - return ( - <> - - {variant === 'mobile' && ( - - { - if (!isCollapsible) { - onClose() - } - }} - currentPathname={currentPathname} - links={routes.map((route) => ({ - to: route.path, - label: - route.drawerLabel !== 'version' - ? t(route.drawerLabel) - : `${t(route.drawerLabel)} ${appVersion}`, - collapsedItems: route.drawerComponents, - target: route.target - }))} - sortBy={sortBy} - setSortBy={handleSortBy} - /> - - )} - {variant === 'desktop' && ( - - ({ - to: route.path, - label: - route.drawerLabel !== 'version' - ? t(route.drawerLabel) - : `${t(route.drawerLabel)} ${appVersion}`, - collapsedItems: route.drawerComponents, - target: route.target - }))} - sortBy={sortBy} - setSortBy={handleSortBy} - /> - - )} - - ) -} - -Menu.propTypes = { - links: PropTypes.array, - onClick: PropTypes.func, - currentPathname: PropTypes.string, - setSortBy: PropTypes.func, - sortBy: PropTypes.string -} - -MainDrawer.propTypes = { - theme: PropTypes.object, - variant: PropTypes.string, - onClose: PropTypes.func, - open: PropTypes.bool -} - -export default MainDrawer diff --git a/webapp/src/components/main-drawer/styles.js b/webapp/src/components/main-drawer/styles.js deleted file mode 100644 index 5764107a..00000000 --- a/webapp/src/components/main-drawer/styles.js +++ /dev/null @@ -1,47 +0,0 @@ -export default (theme) => ({ - toolbar: theme.mixins.toolbar, - drawerPaper: { - width: 240, - height: '100vh', - [theme.breakpoints.up('md')]: { - position: 'relative' - } - }, - innerList: { - backgroundColor: theme.palette.surface.main, - '& li': { - paddingLeft: theme.spacing(3), - '&:hover': { - cursor: 'pointer', - backgroundColor: '#adbcbf' - } - } - }, - heading: { - fontSize: theme.typography.pxToRem(15), - fontWeight: theme.typography.fontWeightRegular - }, - selectedItem: { - backgroundColor: theme.palette.surface.main - }, - link: { - textDecoration: 'none', - color: '#443f56' - }, - linkSelected: { - backgroundColor: '#ced7d8 !important', - color: '#443f5b' - }, - sortSelected: { - backgroundColor: '#adbcbf !important', - color: '#443f5b' - }, - divider: { - marginBottom: theme.spacing(2) - }, - iconLink: { - marginLeft: '10px', - width: '20px', - color: theme.palette.secondary.main - } -}) diff --git a/webapp/src/components/main-footer/styles.js b/webapp/src/components/main-footer/styles.js deleted file mode 100644 index 8b5bb79d..00000000 --- a/webapp/src/components/main-footer/styles.js +++ /dev/null @@ -1,30 +0,0 @@ -export default (theme) => ({ - root: { - position: 'static', - bottom: 0, - top: 'auto' - }, - grow: { - flexGrow: 1 - }, - eoscostaricaLogo: { - height: 36, - width: 'auto' - }, - link: { - color: theme.palette.common.white, - textDecoration: 'none' - }, - legend: { - display: 'flex', - width: 150, - lineHeight: 1.4, - fontSize: 8, - fontWeight: 500, - fontStretch: 'normal', - letterSpacing: 1.1, - textAlign: 'right', - color: 'rgba(255, 255, 255, 0.6)', - paddingRight: theme.spacing(2) - } -}) diff --git a/webapp/src/components/radar/index.js b/webapp/src/components/radar/index.js deleted file mode 100644 index 3147718d..00000000 --- a/webapp/src/components/radar/index.js +++ /dev/null @@ -1,122 +0,0 @@ -import React, { useEffect, useState } from 'react' -import PropTypes from 'prop-types' -import { useTranslation } from 'react-i18next' -import { Radar } from 'react-chartjs-2' - -import getRadarLabelName from 'utils/getRadarLabelName' - -const RadarData = ({ bpData, height, showLabel, width, ...props }) => { - const { t } = useTranslation('translations') - const labels = getRadarLabelName(t) - const [sizes, setSizes] = useState({ width: '100%', height: '100%' }) - const bpValidData = - bpData.datasets && bpData.datasets.length - ? { ...bpData, labels } - : { labels, datasets: [{ data: [0, 0, 0, 0, 0] }] } - - useEffect(() => { - if (!width && !height) return - - setSizes({ width, height }) - }, [width, height]) - - return ( - - `${data.labels[tooltipItem.index]}: ${ - data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] - }`, - title: (tooltipItem, data) => { - const titleModeled = tooltipItem.reduce( - (acc, current, index) => { - if (current.datasetIndex === acc.prevDatasetIndex) return acc - - const label = `${acc.title} ${index ? '||' : ''} ${ - data.datasets[current.datasetIndex].label - }` - - return { - title: label, - prevDatasetIndex: current.datasetIndex - } - }, - { title: '', prevDatasetIndex: null } - ) - - return titleModeled.title - } - } - } - }} - /> - ) -} - -RadarData.propTypes = { - bpData: PropTypes.object, - height: PropTypes.any, - width: PropTypes.any, - showLabel: PropTypes.bool -} - -RadarData.defaultProps = { - showLabel: false -} - -export default RadarData diff --git a/webapp/src/components/select/index.js b/webapp/src/components/select/index.js deleted file mode 100644 index 76d84959..00000000 --- a/webapp/src/components/select/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react' -import { Field } from 'components/checkbox/node_modules/formik' -import { InputLabel } from '@material-ui/core' -import { Select as MaterialSelect } from 'components/checkbox/node_modules/formik-material-ui' -import PropTypes from 'prop-types' - -import FormControl from '../formControl' - -const Select = ({ ...props }) => ( - - - {props.label} - - - -) - -Select.propTypes = { - name: PropTypes.string.isRequired, - label: PropTypes.string.isRequired -} - -export default Select diff --git a/webapp/src/components/sign-in-dialog/index.js b/webapp/src/components/sign-in-dialog/index.js deleted file mode 100644 index dbe60c8a..00000000 --- a/webapp/src/components/sign-in-dialog/index.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useEffect, useState } from 'react' -import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/core/styles' -import { useTranslation } from 'react-i18next' -import Button from '@material-ui/core/Button' -import DialogActions from '@material-ui/core/DialogActions' -import DialogContent from '@material-ui/core/DialogContent' -import DialogContentText from '@material-ui/core/DialogContentText' -import DialogTitle from '@material-ui/core/DialogTitle' -import Dialog from '@material-ui/core/Dialog' -import LinearProgress from '@material-ui/core/LinearProgress' -import red from '@material-ui/core/colors/red' - -import styles from './styles' - -const useStyles = makeStyles(() => styles(red)) - -const SignInDialog = ({ connecting, error, provider }) => { - const [errorDialogOpen, setErrorDialogOpen] = useState(Boolean(error)) - const { t } = useTranslation('translations') - const classes = useStyles() - - useEffect(() => setErrorDialogOpen(Boolean(error)), [error]) - - return ( - <> - - - {provider ? `${t('connectingWith')} ${provider}` : t('connecting')} - - - - - - - - {t('connectingErrorTitle')} - - - - {error} - - - - - - - - ) -} - -SignInDialog.propTypes = { - connecting: PropTypes.bool.isRequired, - error: PropTypes.string, - provider: PropTypes.string -} - -export default SignInDialog diff --git a/webapp/src/components/sign-in-dialog/styles.js b/webapp/src/components/sign-in-dialog/styles.js deleted file mode 100644 index 94d552ae..00000000 --- a/webapp/src/components/sign-in-dialog/styles.js +++ /dev/null @@ -1,5 +0,0 @@ -export default (red) => ({ - errorMsg: { - color: red[500] - } -}) diff --git a/webapp/src/components/sign-in-menu/index.js b/webapp/src/components/sign-in-menu/index.js deleted file mode 100644 index 06101976..00000000 --- a/webapp/src/components/sign-in-menu/index.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import Menu from '@material-ui/core/Menu' - -const SignInMenu = ({ anchorEl, handleClick, handleClose }) => { - return ( - - ) -} - -SignInMenu.propTypes = { - anchorEl: PropTypes.object, - handleClick: PropTypes.func.isRequired, - handleClose: PropTypes.func.isRequired -} - -export default SignInMenu diff --git a/webapp/src/components/spinner/index.js b/webapp/src/components/spinner/index.js deleted file mode 100644 index 30de5f62..00000000 --- a/webapp/src/components/spinner/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/styles' -import CircularProgress from '@material-ui/core/CircularProgress' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const IsLoading = ({ isLoading }) => { - const classes = useStyles() - - return isLoading ? ( -
-
-
-
- -
-
-
- ) : null -} - -IsLoading.propTypes = { - isLoading: PropTypes.bool -} - -export default IsLoading diff --git a/webapp/src/components/spinner/styles.js b/webapp/src/components/spinner/styles.js deleted file mode 100644 index bfd8850d..00000000 --- a/webapp/src/components/spinner/styles.js +++ /dev/null @@ -1,32 +0,0 @@ -export default (theme) => ({ - blockContainer: { - '&:focus': { - outline: 'none' - }, - bottom: 0, - cursor: 'wait', - height: '100%', - left: 0, - overflow: 'hidden', - position: 'fixed', - right: 0, - top: 0, - zIndex: 99999 - }, - blockOverlay: { - backgroundColor: '#fff', - height: '100%', - opacity: 0.3, - width: '100%' - }, - circularProgressContainer: { - alignContent: 'center', - background: 'transparent', - display: 'flex', - justifyContent: 'center', - position: 'absolute', - top: theme.spacing(10), - width: '100%', - zIndex: 999999 - } -}) diff --git a/webapp/src/components/telegram-icon/index.js b/webapp/src/components/telegram-icon/index.js deleted file mode 100644 index c6caea5f..00000000 --- a/webapp/src/components/telegram-icon/index.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react' -import SvgIcon from '@material-ui/core/SvgIcon' - -const TelegramIcon = () => ( - - - -) - -export default TelegramIcon diff --git a/webapp/src/components/textField/index.js b/webapp/src/components/textField/index.js deleted file mode 100644 index 23643068..00000000 --- a/webapp/src/components/textField/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' -import { Field } from 'formik' -import { TextField as MaterialTextField } from 'formik-material-ui' - -import FormControl from '../formControl' - -const TextField = (props) => ( - - - -) - -export default TextField diff --git a/webapp/src/components/title-page/index.js b/webapp/src/components/title-page/index.js deleted file mode 100644 index d959e4c3..00000000 --- a/webapp/src/components/title-page/index.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react' -import Helmet from 'react-helmet' -import PropTypes from 'prop-types' - -const TitlePage = ({ title }) => ( - - {title} - -) - -TitlePage.propTypes = { - title: PropTypes.string -} - -TitlePage.defaultProps = { - title: 'EOS RATE' -} - -export default TitlePage diff --git a/webapp/src/config/filters.js b/webapp/src/config/filters.js new file mode 100644 index 00000000..30a20f3d --- /dev/null +++ b/webapp/src/config/filters.js @@ -0,0 +1,12 @@ +export const filters = [ + { sort: 'candidate_name', value: 'alphabetical' }, + { sort: 'average', value: 'generalRate' }, + { sort: 'eden_average', value: 'edenRate' }, + { sort: 'infrastructure', value: 'infrastructure' }, + { sort: 'community', value: 'community' }, + { sort: 'trustiness', value: 'trustiness' }, + { sort: 'development', value: 'development' }, + { sort: 'transparency', value: 'transparency' }, + { sort: 'total_votes', value: 'vote' }, + { sort: 'ratings_cntr', value: 'ratings' } +] diff --git a/webapp/src/config/graphql.config.js b/webapp/src/config/graphql.config.js new file mode 100644 index 00000000..6f3e8d49 --- /dev/null +++ b/webapp/src/config/graphql.config.js @@ -0,0 +1 @@ +export const url = process.env.REACT_APP_GRAPHQL_HTTP_URL diff --git a/webapp/src/config/index.js b/webapp/src/config/index.js index c8d4a555..632429e5 100644 --- a/webapp/src/config/index.js +++ b/webapp/src/config/index.js @@ -1,14 +1,7 @@ -export const appName = 'EOSRate' -export const stage = process.env.REACT_APP_MAINNET_VERSION -export const contract = process.env.REACT_APP_RATING_CONTRACT || 'rateproducer' -export const appVersion = - process.env.REACT_APP_VERSION.split('/').pop() || '1.0.0' -export const contractEden = - process.env.REACT_APP_EDEN_CONTRACT || 'genesis.eden' -export const eosApiHost = process.env.REACT_APP_EOS_API_HOST -export const eosApiPort = process.env.REACT_APP_EOS_API_PORT -export const eosApiProtocol = process.env.REACT_APP_EOS_API_PROTOCOL -export const eosApiUri = `${process.env.REACT_APP_EOS_API_PROTOCOL}://${process.env.REACT_APP_EOS_API_HOST}:${process.env.REACT_APP_EOS_API_PORT}` -export const eosChainId = process.env.REACT_APP_EOS_CHAIN_ID -export const blockExplorer = process.env.REACT_APP_BLOCK_EXPLORER -export const networkMonitor = process.env.REACT_APP_NETWORK_MONITOR_URL +import * as graphqlConfig from './graphql.config' +import * as mainConfig from './main.config' +import * as ualConfig from './ual.config' +import * as polarCharConfig from './polar-radar-config' +import * as filtersConfig from './filters' + +export { graphqlConfig, mainConfig, ualConfig, polarCharConfig, filtersConfig } diff --git a/webapp/src/config/main.config.js b/webapp/src/config/main.config.js new file mode 100644 index 00000000..9e44c371 --- /dev/null +++ b/webapp/src/config/main.config.js @@ -0,0 +1,13 @@ +export const appVersion = process.env.REACT_APP_TAG || 'v1.0' +export const name = process.env.REACT_APP_NAME +export const title = process.env.REACT_APP_TITLE +export const stage = process.env.REACT_APP_MAINNET_VERSION +export const logo = process.env.REACT_APP_LOGO +export const footerLinks = JSON.parse( + process.env.REACT_APP_FOOTER_LINKS || '[]' +) +export const blockExplorer = process.env.REACT_APP_BLOCK_EXPLORER +export const contract = process.env.REACT_APP_RATING_CONTRACT || 'rateproducer' +export const contractEden = + process.env.REACT_APP_EDEN_CONTRACT || 'genesis.eden' +export const networkMonitor = process.env.REACT_APP_NETWORK_MONITOR_URL diff --git a/webapp/src/config/polar-radar-config.js b/webapp/src/config/polar-radar-config.js new file mode 100644 index 00000000..97dea2df --- /dev/null +++ b/webapp/src/config/polar-radar-config.js @@ -0,0 +1,66 @@ +export const options = { + chart: { + polar: true, + width: 350 + }, + credits: { + enabled: false + }, + legend: { + enabled: false + }, + exporting: { + enabled: false + }, + title: { + text: '' + }, + pane: { + startAngle: 0, + endAngle: 360 + }, + xAxis: { + gridLineWidth: 3, + gridLineColor: '#e5e5e5', + lineColor: '#e5e5e5', + categories: [ + 'Community', + 'Development', + 'Infrastructure', + 'Transparency', + 'Trustiness' + ], + lineWidth: 3, + startOnTick: true, + tickmarkPlacement: 'on', + labels: { + align: 'center', + style: { + fontSize: '12px' + } + } + }, + yAxis: { + gridLineWidth: 3, + gridLineColor: '#e5e5e5', + min: 0, + max: 10, + endOnTick: false, + tickInterval: 2, + gridLineInterpolation: 'circle', + labels: { + enabled: false + } + }, + + plotOptions: { + followPointer: true, + series: { + pointStart: 0 + }, + column: { + pointPadding: 0, + groupPadding: 0 + } + } +} diff --git a/webapp/src/config/radar-color-palette.js b/webapp/src/config/radar-color-palette.js deleted file mode 100644 index de592878..00000000 --- a/webapp/src/config/radar-color-palette.js +++ /dev/null @@ -1,20 +0,0 @@ -// Palette generated with http://vrl.cs.brown.edu/color - -export default [ - '#366d7a', - '#46a08a', - '#7dc384', - '#ffe6a7', - '#fc8c71', - '#fc2c44', - '#a6541d', - '#638123', - '#15b71e', - '#2975de', - '#08a9e5', - '#895ae7', - '#e978b1', - '#fa41c7', - '#b195b0', - '#9d1cf4' -] diff --git a/webapp/src/config/radar.js b/webapp/src/config/radar.js deleted file mode 100644 index 9278edb6..00000000 --- a/webapp/src/config/radar.js +++ /dev/null @@ -1,27 +0,0 @@ -import { Chart } from 'react-chartjs-2' -import get from 'lodash.get' - -const renderBackgroundColor = (chart) => { - const { ctx, config, scales } = chart - const { - r: { xCenter, yCenter, drawingArea: radius } - } = scales - const backgroundColor = get( - config, - 'options.chartArea.backgroundColor', - false - ) - - ctx.save() - ctx.arc(xCenter, yCenter, radius, 0, Math.PI * 2) - - if (backgroundColor) ctx.fillStyle = backgroundColor - - ctx.fill() - ctx.restore() -} - -Chart.register({ - id: Chart.name, - beforeDraw: renderBackgroundColor -}) diff --git a/webapp/src/config/theme.js b/webapp/src/config/theme.js deleted file mode 100644 index b7a085a3..00000000 --- a/webapp/src/config/theme.js +++ /dev/null @@ -1,73 +0,0 @@ -import { createTheme } from '@material-ui/core/styles' - -const theme = createTheme({ - typography: { - useNextVariants: true - }, - palette: { - type: 'light', - background: { - default: '#eeeeee' - }, - primary: { - light: '#787291', - main: '#443f56', - dark: '#221e38', - sectionBackground: '#ffffff', - submenu: '#597a81' - }, - secondary: { - light: '#8ba2a6', - main: '#597a81', - dark: '#222f32' - }, - surface: { - light: '#ffffff', - main: '#ffffff', - dark: '#f8f8f8' - } - }, - overrides: { - root: { - fontSize: '2em' - }, - MuiListItem: { - button: { - // color: 'black', - '&:hover': { - // backgroundColor: '#5cf68a', - // color: 'black' - } - }, - root: { - '&$selected': { - // color: 'black', - // backgroundColor: '#5cf68a' - } - } - }, - MuiListItemText: { - primary: { - // color: 'inherit' - } - }, - MuiSelect: { - root: { - paddingTop: 8 - } - }, - MuiInput: { - root: { - height: 50, - fontSize: 20 - } - }, - MuiButton: { - containedSecondary: { - // color: '#fff' - } - } - } -}) - -export default theme diff --git a/webapp/src/config/ual.config.js b/webapp/src/config/ual.config.js new file mode 100644 index 00000000..5caa0376 --- /dev/null +++ b/webapp/src/config/ual.config.js @@ -0,0 +1,32 @@ +import { TokenPocket } from 'ual-token-pocket' +import { Anchor } from 'ual-anchor' +import { Scatter } from 'ual-scatter' +import { Ledger } from 'ual-ledger' +import { Lynx } from 'ual-lynx' +import { MeetOne } from 'ual-meetone' + +export const endpoint = `${process.env.REACT_APP_EOS_API_PROTOCOL}://${ + process.env.REACT_APP_EOS_API_HOST +}${process.env.REACT_APP_EOS_API_PORT ? ':' : ''}${ + process.env.REACT_APP_EOS_API_PORT +}` +export const appName = process.env.REACT_APP_UAL_APP_NAME || 'app' +export const network = { + chainId: process.env.REACT_APP_EOS_CHAIN_ID || '', + rpcEndpoints: [ + { + blockchain: 'eos', + protocol: process.env.REACT_APP_EOS_API_PROTOCOL, + host: process.env.REACT_APP_EOS_API_HOST, + port: parseInt(process.env.REACT_APP_EOS_API_PORT) + } + ] +} +export const authenticators = [ + new TokenPocket([network]), + new Anchor([network], { appName }), + new Lynx([network]), + new Ledger([network]), + new MeetOne([network.chainId]), + new Scatter([network], { appName }) +] diff --git a/webapp/src/config/wallet-providers.js b/webapp/src/config/wallet-providers.js deleted file mode 100644 index 156b8fc4..00000000 --- a/webapp/src/config/wallet-providers.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * The order of the objects in this array is determinant and strictly related to the order of `walletProviders` declared - * for the `accessContext` in `hooks/wallet/index.js`, so please keep the same order here and there (alphabetical). - */ -export default [ - { - id: 'lynx', - name: 'Lynx' - }, - { - id: 'meetone', - name: 'MEET.ONE' - }, - { - id: 'scatter', - name: 'Scatter' - }, - { - id: 'tokenpocket', - name: 'Token Pocket' - } -] diff --git a/webapp/src/context/models/index.js b/webapp/src/context/models/index.js new file mode 100644 index 00000000..2440ef8c --- /dev/null +++ b/webapp/src/context/models/index.js @@ -0,0 +1,3 @@ +export * from './proxies' +export * from './user' +export * from './producers' diff --git a/webapp/src/context/models/producers.js b/webapp/src/context/models/producers.js new file mode 100644 index 00000000..baec8f30 --- /dev/null +++ b/webapp/src/context/models/producers.js @@ -0,0 +1,241 @@ +import { client } from '../../graphql' +import { + GET_BLOCK_PRODUCERS, + GET_PRODUCER_BY_OWNER, + QUERY_RATING, + MUTATION_UPDATE_RATING +} from '../../gql' +import getBpDataModeled from '../../utils/modeled-bp-data' +import { mainConfig } from '../../config' +import { getRpc } from '../../utils/eosjs-utils' + +export const getProducers = async (limit, orderBy) => { + const { + data: { list, info } + } = await client.query({ + variables: { limit, orderBy }, + query: GET_BLOCK_PRODUCERS, + fetchPolicy: 'network-only' + }) + + if (!list.length) return [] + + const resultProducers = list.map(producer => { + return getBpDataModeled({ + ...producer, + edenRate: { + average: producer.eden_average, + ratings_cntr: producer.eden_ratings_cntr, + community: producer.eden_community, + development: producer.eden_development, + infrastructure: producer.eden_infrastructure, + transparency: producer.eden_transparency, + trustiness: producer.eden_trustiness + } + }) + }) + + return { data: resultProducers, rows: info.producers.count } +} + +export const getBlockProducerRatingByOwner = async ( + { bp, userAccount }, + state +) => { + try { + const { + data: { user_ratings: userRatings } + } = await client.query({ + variables: { bp, user: userAccount }, + query: QUERY_RATING + }) + + return userRatings.length ? userRatings[0].ratings : null + } catch (error) { + console.error('getBlockProducerRatingByOwner', error) + } +} + +export const mutationInsertUserRating = async ( + { ual, user, bp, result, transaction, blockProducers, ...ratings }, + state +) => { + try { + const { + data: { rateProducer } + } = await client.mutate({ + variables: { + ratingInput: { + producer: bp, + isEden: state?.user?.userData?.edenMember, + user, + transaction: transaction + } + }, + mutation: MUTATION_UPDATE_RATING + }) + + const rpc = getRpc(ual) + + const { rows: rateStat } = await rpc.get_table_rows({ + json: true, + code: mainConfig.contract, + scope: mainConfig.contract, + table: 'stats', + lower_bound: bp, + limit: 1, + reverse: false, + show_payer: false + }) + + const producerUpdatedList = blockProducers.data.map(producer => { + if (rateStat.length && producer.owner === rateStat[0].bp) { + const parameters = { + community: rateStat[0].community, + development: rateStat[0].development, + infrastructure: rateStat[0].infrastructure, + transparency: rateStat[0].transparency, + trustiness: rateStat[0].trustiness + } + const graphData = Object.values(parameters) + + return { + ...producer, + average: rateStat[0].average, + ratings_cntr: rateStat[0].ratings_cntr, + system: { + ...producer.system, + parameters + }, + data: { + ...producer.data, + data: graphData + } + } + } + + return producer + }) + let currentBP = producerUpdatedList.find(producer => producer.owner === bp) + currentBP = { ...currentBP, ...rateProducer.resultEden } + const userRate = await getBlockProducerRatingByOwner({ + bp, + userAccount: user + }) + + return { + currentBP, + producerUpdatedList, + rateProducer, + userRate + } + } catch (error) { + console.error('mutationInsertUserRating', error) + } +} + +const calculateTotalStats = ({ + firstAverage, + secondAverage, + fieldsAmount, + firstCounter, + secondCounter +}) => { + const dividend = + firstAverage * (firstCounter * fieldsAmount) + + secondAverage * (secondCounter * fieldsAmount) + const divider = (firstCounter + secondCounter) * fieldsAmount + return dividend / divider +} + +export const getTotalStats = ({ + producerData, + edenStats, + statsAmount, + oneStat +}) => { + const average = calculateTotalStats({ + firstAverage: producerData.average, + secondAverage: edenStats.average, + firstCounter: producerData.ratings_cntr, + secondCounter: edenStats.ratings_cntr, + fieldsAmount: statsAmount + }) + + const community = calculateTotalStats({ + firstAverage: producerData.community, + secondAverage: edenStats.community, + firstCounter: producerData.ratings_cntr, + secondCounter: edenStats.ratings_cntr, + fieldsAmount: oneStat + }) + + const development = calculateTotalStats({ + firstAverage: producerData.development, + secondAverage: edenStats.development, + firstCounter: producerData.ratings_cntr, + secondCounter: edenStats.ratings_cntr, + fieldsAmount: oneStat + }) + + const infrastructure = calculateTotalStats({ + firstAverage: producerData.infrastructure, + secondAverage: edenStats.infrastructure, + firstCounter: producerData.ratings_cntr, + secondCounter: edenStats.ratings_cntr, + fieldsAmount: oneStat + }) + + const trustiness = calculateTotalStats({ + firstAverage: producerData.trustiness, + secondAverage: edenStats.trustiness, + firstCounter: producerData.ratings_cntr, + secondCounter: edenStats.ratings_cntr, + fieldsAmount: oneStat + }) + + const transparency = calculateTotalStats({ + firstAverage: producerData.trustiness, + secondAverage: edenStats.trustiness, + firstCounter: producerData.ratings_cntr, + secondCounter: edenStats.ratings_cntr, + fieldsAmount: oneStat + }) + + return { + average, + ratings_cntr: producerData.ratings_cntr + edenStats.ratings_cntr, + community, + development, + infrastructure, + trustiness, + transparency + } +} + +export const getProducer = async owner => { + const { + data: { producer } + } = await client.query({ + variables: { account: owner }, + query: GET_PRODUCER_BY_OWNER, + fetchPolicy: 'network-only' + }) + + if (!producer.length) return null + + const producerData = producer[0] + + return getBpDataModeled({ + ...producerData, + edenRate: { + average: producerData.eden_average, + ratings_cntr: producerData.eden_ratings_cntr, + community: producerData.eden_community, + development: producerData.eden_development, + infrastructure: producerData.eden_infrastructure, + transparency: producerData.eden_transparency, + trustiness: producerData.eden_trustiness + } + }) +} diff --git a/webapp/src/context/models/proxies.js b/webapp/src/context/models/proxies.js new file mode 100644 index 00000000..827e8f0d --- /dev/null +++ b/webapp/src/context/models/proxies.js @@ -0,0 +1,156 @@ +import _get from 'lodash.get' + +import { client } from '../../graphql' +import { + GET_PROXIES, + GET_PRODUCER_BY_PRODUCER_LIST, + GET_PROXY_BY_OWNER +} from '../../gql' +import calculateEosFromVotes from '../../utils/convert-votes-to-eos-votes' +import getBPRadarData from '../../utils/get-bp-radar-data' +import getBpDataModeled from '../../utils/modeled-bp-data' + +const getResultModeled = (proxies, promiseResolved) => + proxies.map((proxy, index) => { + const producers = promiseResolved[index].data.producerList + const rateInfo = [] + const proxiedVoteEOS = calculateEosFromVotes( + _get(proxy, 'voter_info.last_vote_weight', 0) + ) + const totalVoteEOS = calculateEosFromVotes( + _get(proxy, 'voter_info.proxied_vote_weight', 0) + ) + const producersDataModeled = producers.map(producer => { + const modeledBp = getBpDataModeled(producer) + + rateInfo.push(modeledBp.system.parameters) + + return modeledBp + }) + + const averageParams = rateInfo.reduce( + (acc, current, index) => { + const community = acc.community + current.community + const development = acc.development + current.development + const infrastructure = acc.infrastructure + current.infrastructure + const transparency = acc.transparency + current.transparency + const trustiness = acc.trustiness + current.trustiness + + if (index + 1 === rateInfo.length) { + return { + community: community / rateInfo.length, + development: development / rateInfo.length, + infrastructure: infrastructure / rateInfo.length, + transparency: transparency / rateInfo.length, + trustiness: trustiness / rateInfo.length + } + } + + return { + community, + development, + infrastructure, + transparency, + trustiness + } + }, + { + community: 0, + development: 0, + infrastructure: 0, + transparency: 0, + trustiness: 0 + } + ) + + return { + ...proxy, + voter_info: { + ...proxy.voter_info, + producers: producersDataModeled + }, + averageParams, + data: getBPRadarData({ + name: proxy.owner, + parameters: averageParams + }), + proxiedVoteEOS, + totalVoteEOS + } + }) + +export const getProxies = async limit => { + const { + data: { proxies, info } + } = await client.query({ + variables: { limit }, + query: GET_PROXIES, + fetchPolicy: 'network-only' + }) + + if (!proxies.length) return [] + + const promiseResolved = await Promise.all( + proxies.map(({ voter_info: voterInfo }) => { + if (!voterInfo.producers.length) { + return new Promise(resolve => { + setTimeout(resolve, 100, { + data: { + producerList: [] + } + }) + }) + } + + return client.query({ + variables: { + producerList: voterInfo.producers + }, + query: GET_PRODUCER_BY_PRODUCER_LIST, + fetchPolicy: 'network-only' + }) + }) + ) + + const resultProxies = getResultModeled(proxies, promiseResolved) + + return { data: resultProxies, rows: info.proxies.count } +} + +export const getProxy = async account => { + const { + data: { proxy } + } = await client.query({ + variables: { account }, + query: GET_PROXY_BY_OWNER, + fetchPolicy: 'network-only' + }) + + if (!proxy.length) return null + + const promiseResolved = await Promise.all( + proxy.map(({ voter_info: voterInfo }) => { + if (!voterInfo.producers.length) { + return new Promise(resolve => { + setTimeout(resolve, 100, { + data: { + producerList: [] + } + }) + }) + } + + return client.query({ + variables: { + producerList: voterInfo.producers + }, + query: GET_PRODUCER_BY_PRODUCER_LIST, + fetchPolicy: 'network-only' + }) + }) + ) + + const resultProxies = getResultModeled(proxy, promiseResolved) + + return resultProxies[0] +} diff --git a/webapp/src/context/models/user.js b/webapp/src/context/models/user.js new file mode 100644 index 00000000..76115855 --- /dev/null +++ b/webapp/src/context/models/user.js @@ -0,0 +1,96 @@ +import _get from 'lodash.get' + +import { getRpc, getAccountName } from '../../utils/eosjs-utils' +import { mainConfig } from '../../config' +import { client } from '../../graphql' +import { GET_USER_RATING, GET_PRODUCER_BY_PRODUCER_LIST } from '../../gql' + +export const getUserRates = ({ userRate, user }) => { + try { + const { message, ...bpRate } = userRate + const userRatesFiltered = user.userData.userRates.filter( + ({ owner }) => owner !== bpRate.bp + ) + + return { + ...user.data, + userRates: [...userRatesFiltered, bpRate] + } + } catch (error) { + console.error('getUserRates', error) + return null + } +} + +export const getUserDataModeled = async ual => { + let userRates = [] + let edenMember = false + let listBPAccount = [] + + const accountName = await getAccountName(ual) + const rpc = getRpc(ual) + + const account = await rpc.get_account(accountName) + const { rows: edenMembers } = await rpc.get_table_rows({ + json: true, + code: mainConfig.contractEden, + scope: 0, + table: 'member', + lower_bound: accountName, + limit: 1, + reverse: false, + show_payer: false + }) + + if ( + edenMembers.length > 0 && + edenMembers[0].value[1].account === accountName + ) { + edenMember = true + } + + const { + data: { userRatings } + } = await client.query({ + variables: { user: accountName }, + query: GET_USER_RATING, + fetchPolicy: 'network-only' + }) + + const producers = _get(account, 'voter_info.producers', []) + const proxy = _get(account, 'voter_info.proxy', '') + + if (userRatings.length) { + listBPAccount = userRatings.map(({ bp }) => bp) + const { + data: { producerList } + } = await client.query({ + variables: { + producerList: listBPAccount + }, + query: GET_PRODUCER_BY_PRODUCER_LIST, + fetchPolicy: 'network-only' + }) + + userRates = userRatings.map(bpRated => { + const item = (producerList || []).find( + ({ owner }) => bpRated.bp === owner + ) + + return { ...item, ...bpRated } + }) + } + + return { + ...ual.activeUser, + userData: { + ...account, + hasProxy: Boolean(proxy.length), + producersCount: producers.length, + userRates, + edenMember, + listBPAccount, + proxyAccount: proxy + } + } +} diff --git a/webapp/src/context/state.context.js b/webapp/src/context/state.context.js new file mode 100644 index 00000000..f487f576 --- /dev/null +++ b/webapp/src/context/state.context.js @@ -0,0 +1,358 @@ +import React, { useEffect } from 'react' +import PropTypes from 'prop-types' + +import { + getProxies, + getProxy, + getUserDataModeled, + getProducers, + getProducer, + mutationInsertUserRating, + getUserRates, + getTotalStats +} from './models' + +const SharedStateContext = React.createContext() + +const initialValue = { + useDarkMode: false, + user: null, + blockProducers: { data: [], rows: 0 }, + selectedProducers: [], + blockProducer: null, + transaction: null, + compareBPToolVisible: false, + sortBlockProducersBy: { sort: 'total_votes', value: 'vote' }, + proxies: { data: [], rows: 0 }, + selectedProxies: [], + proxy: null, + compareProxyToolVisible: false +} + +const sharedStateReducer = (state, action) => { + switch (action.type) { + case 'ual': + return { + ...state, + ual: action.ual + } + + case 'userChange': + return { + ...state, + user: action.user + } + + case 'set': { + return { + ...state, + ...action.payload + } + } + + case 'showMessage': + return { + ...state, + message: action.payload + } + + case 'hideMessage': + return { + ...state, + message: null + } + + case 'login': + state.ual.showModal() + + return state + + case 'logout': + state.ual.logout() + + return state + + case 'setProducers': + return { + ...state, + blockProducers: action.blockProducers + } + + case 'setProducer': + return { + ...state, + blockProducer: action.blockProducer + } + + case 'setSortProducersBy': + return { + ...state, + sortBlockProducersBy: action.sortBy + } + + case 'setCompareBPTool': + return { + ...state, + compareBPToolVisible: action.isVisible + } + + case 'setSelectedProducers': + return { + ...state, + selectedProducers: action.selectedProducers + } + + case 'setProxies': + return { + ...state, + proxies: action.proxies + } + + case 'setProxy': + return { + ...state, + proxy: action.proxy + } + + case 'setCompareProxyTool': + return { + ...state, + compareProxyToolVisible: action.isVisible + } + + case 'setSelectedProxies': + return { + ...state, + selectedProxies: action.selectedProxies + } + + case 'setLastTransaction': + return { + ...state, + transaction: action.transaction + } + + default: { + throw new Error(`Unsupported action type: ${action.type}`) + } + } +} + +export const SharedStateProvider = ({ children, ual, ...props }) => { + const [state, dispatch] = React.useReducer(sharedStateReducer, { + ...initialValue, + ual + }) + const value = React.useMemo(() => [state, dispatch], [state]) + + useEffect(() => { + const load = async () => { + if (ual.activeUser) { + const user = await getUserDataModeled(ual) + + dispatch({ type: 'userChange', user }) + } else { + dispatch({ type: 'userChange', user: ual.activeUser }) + dispatch({ type: 'setSelectedProducers', selectedProducers: [] }) + } + + dispatch({ type: 'ual', ual }) + } + + load() + }, [ual?.activeUser]) + + return ( + + {children} + + ) +} + +SharedStateProvider.propTypes = { + children: PropTypes.node, + ual: PropTypes.any +} + +export const useSharedState = () => { + const context = React.useContext(SharedStateContext) + + if (!context) { + throw new Error(`useSharedState must be used within a SharedStateContext`) + } + + const [state, dispatch] = context + const setState = payload => dispatch({ type: 'set', payload }) + const showMessage = payload => dispatch({ type: 'showMessage', payload }) + const hideMessage = () => dispatch({ type: 'hideMessage' }) + const login = () => dispatch({ type: 'login' }) + const logout = () => dispatch({ type: 'logout' }) + const setUser = async tempUser => { + let user = tempUser + + if (!user) { + user = await getUserDataModeled(state.ual) + } + + dispatch({ type: 'userChange', user }) + } + const setSortBy = (sortBy, page) => { + if (page === 'bp') { + dispatch({ type: 'setSortProducersBy', sortBy }) + } else { + // TODO: add logic to sort proxies + } + } + + // Block Producers Action + const setProducers = async (limit, orderBy = null, bpList) => { + const filter = orderBy || state.sortBlockProducersBy.sort + let blockProducers = bpList + + if (!blockProducers) + blockProducers = await getProducers(limit, [ + { [filter]: 'desc_nulls_last' }, + { bpjson: 'desc' } + ]) + + const allBps = [] + + blockProducers.data.forEach(bp => { + const totalStats = getTotalStats({ + producerData: { + ...bp?.system?.parameters, + average: bp?.average, + ratings_cntr: bp?.ratings_cntr + }, + edenStats: bp?.edenRate, + statsAmount: 5, + oneStat: 1 + }) + bp = { + ...bp, + totalStats + } + allBps.push(bp) + }) + + blockProducers = { ...blockProducers, data: allBps } + + dispatch({ type: 'setProducers', blockProducers }) + } + + const setProducer = async (item, saveDirectly = false) => { + let blockProducer = item + + if (!saveDirectly) { + blockProducer = await getProducer(item) + } + + const totalStats = getTotalStats({ + producerData: { + ...blockProducer?.system?.parameters, + average: blockProducer?.average || 0, + ratings_cntr: blockProducer?.ratings_cntr || 0 + }, + edenStats: blockProducer?.edenRate, + statsAmount: 5, + oneStat: 1 + }) + + blockProducer = { + ...blockProducer, + totalStats + } + + dispatch({ type: 'setProducer', blockProducer }) + } + + const handleMutationInsertUserRating = async ({ + ual, + user, + bp, + result, + ...ratings + }) => { + const ratingData = await mutationInsertUserRating({ + ual, + user, + bp, + result, + transaction: state.transaction, + blockProducers: state.blockProducers, + ...ratings + }) + + setProducer(ratingData.currentBP, true) + setProducers(30, null, { + ...state.blockProducers, + data: ratingData.producerUpdatedList + }) + + const userRates = getUserRates({ + userRate: { ...ratingData.rateProducer, ...ratingData.currentBP }, + user: state.user + }) + + setUser({ + ...state.user, + userData: { ...state.user.userData, ...userRates } + }) + } + + const setCompareBPTool = isVisible => { + dispatch({ type: 'setCompareBPTool', isVisible }) + } + + const setSelectedProducers = selectedProducers => + dispatch({ type: 'setSelectedProducers', selectedProducers }) + + const setLastTransaction = transaction => { + dispatch({ type: 'setLastTransaction', transaction }) + } + + // Proxies Actions + const setProxies = async limit => { + const proxies = await getProxies(limit) + + dispatch({ type: 'setProxies', proxies }) + } + const setProxy = async (data, saveDirectly = false) => { + let proxy = data + + if (!saveDirectly) { + proxy = await getProxy(data) + } + + dispatch({ type: 'setProxy', proxy }) + } + + const setCompareProxyTool = isVisible => + dispatch({ type: 'setCompareProxyTool', isVisible }) + + const setSelectedProxies = selectedProxies => + dispatch({ type: 'setSelectedProxies', selectedProxies }) + + return [ + state, + { + setState, + showMessage, + hideMessage, + login, + logout, + setUser, + setProducers, + setProducer, + handleMutationInsertUserRating, + setCompareBPTool, + setSelectedProducers, + setLastTransaction, + setSortBy, + setProxies, + setProxy, + setCompareProxyTool, + setSelectedProxies + } + ] +} diff --git a/webapp/src/gql/index.js b/webapp/src/gql/index.js new file mode 100644 index 00000000..361fcfc2 --- /dev/null +++ b/webapp/src/gql/index.js @@ -0,0 +1,4 @@ +export * from './search' +export * from './producers' +export * from './proxies' +export * from './user' diff --git a/webapp/src/gql/producers.js b/webapp/src/gql/producers.js new file mode 100644 index 00000000..ea5b7347 --- /dev/null +++ b/webapp/src/gql/producers.js @@ -0,0 +1,170 @@ +import { gql } from '@apollo/client' + +export const GET_BLOCK_PRODUCERS = gql` + query blockProducers($limit: Int = 15, $orderBy: [producers_list_order_by!]) { + info: producers_list_aggregate( + where: { system: { _contains: { is_active: 1 } } } + ) { + producers: aggregate { + count + } + } + list: producers_list( + where: { system: { _contains: { is_active: 1 } } } + limit: $limit + order_by: $orderBy + ) { + owner + system + bpjson + average + community + development + infrastructure + trustiness + transparency + ratings_cntr + general_info + eden_average + eden_ratings_cntr + eden_community + eden_development + eden_infrastructure + eden_transparency + eden_trustiness + } + } +` + +export const GET_PRODUCER_BY_OWNER = gql` + query blockProducers($account: String) { + producer: producers_list( + where: { + _and: [ + { system: { _contains: { is_active: 1 } } } + { owner: { _eq: $account } } + ] + } + ) { + owner + system + bpjson + average + community + development + infrastructure + trustiness + transparency + ratings_cntr + general_info + eden_average + eden_ratings_cntr + eden_community + eden_development + eden_infrastructure + eden_transparency + eden_trustiness + } + } +` + +export const GET_PRODUCER_BY_PRODUCER_LIST = gql` + query getProducerList($producerList: [String!]) { + producerList: producers_list(where: { owner: { _in: $producerList } }) { + owner + system + bpjson + average + community + development + infrastructure + trustiness + transparency + ratings_cntr + general_info + eden_average + eden_ratings_cntr + } + } +` + +export const MUTATION_INSERT_USER_RATING = gql` + mutation saveUserRating($objects: [user_ratings_insert_input!]!) { + insert_user_ratings(objects: $objects) { + returning { + user + bp + ratings + } + } + } +` + +export const MUTATION_UPDATE_RATING = gql` + mutation updateRating($ratingInput: RatingInput!) { + rateProducer(ratingInput: $ratingInput) { + message + resultEden + user + bp + ratings + } + } +` + +export const MUTATION_UPDATE_USER_RATING = gql` + mutation updateUserRating( + $userRating: user_ratings_set_input + $user: String + $bp: String + ) { + update_user_ratings( + _set: $userRating + where: { _and: [{ user: { _eq: $user } }, { bp: { _eq: $bp } }] } + ) { + returning { + user + bp + ratings + } + } + } +` + +export const QUERY_RATING = gql` + query getRating($user: String, $bp: String) { + user_ratings( + where: { _and: [{ user: { _eq: $user } }, { bp: { _eq: $bp } }] } + ) { + user + bp + ratings + tx_data + } + } +` + +export const QUERY_EDEN_RATING = gql` + query getEdenRating($bp: String) { + eden_ratings_stats(where: { bp: { _eq: $bp } }) { + bp + average + ratings_cntr + infrastructure + transparency + trustiness + development + community + } + } +` + +export const QUERY_PRODUCER = gql` + query getProducer($owner: String) { + producers(where: { owner: { _eq: $owner } }) { + bpjson + owner + system + } + } +` diff --git a/webapp/src/gql/proxies.js b/webapp/src/gql/proxies.js new file mode 100644 index 00000000..554a0ba9 --- /dev/null +++ b/webapp/src/gql/proxies.js @@ -0,0 +1,44 @@ +import { gql } from '@apollo/client' + +export const GET_PROXIES = gql` + query proxies($limit: Int = 15) { + info: proxies_aggregate { + proxies: aggregate { + count + } + } + proxies(limit: $limit) { + background + logo_256 + name + owner + philosophy + slogan + steemit + telegram + twitter + voter_info + website + wechat + } + } +` + +export const GET_PROXY_BY_OWNER = gql` + query proxy($account: String) { + proxy: proxies(where: { owner: { _eq: $account } }) { + background + logo_256 + name + owner + philosophy + slogan + steemit + telegram + twitter + voter_info + website + wechat + } + } +` diff --git a/webapp/src/gql/search.js b/webapp/src/gql/search.js new file mode 100644 index 00000000..83872fa9 --- /dev/null +++ b/webapp/src/gql/search.js @@ -0,0 +1,14 @@ +import { gql } from '@apollo/client' + +export const GET_ITEM_BY_NAME = gql` + query getProducerAndProxies($name: String) { + producers(where: { candidate_name: { _like: $name } }) { + owner + bpjson + } + proxies(where: { filter_name: { _like: $name } }) { + name + owner + } + } +` diff --git a/webapp/src/gql/user.js b/webapp/src/gql/user.js new file mode 100644 index 00000000..908f714a --- /dev/null +++ b/webapp/src/gql/user.js @@ -0,0 +1,37 @@ +import { gql } from '@apollo/client' + +export const GET_USER_RATING = gql` + query getRates($user: String) { + userRatings: user_ratings( + where: { user: { _eq: $user } } + order_by: { tx_data: asc } + ) { + bp + ratings + user + tx_data + } + } +` + +export const DELETE_USER_RATE = gql` + mutation deleteUserRate($user: String!, $bpName: String!) { + delete_user_ratings( + where: { _and: [{ user: { _eq: $user } }, { bp: { _eq: $bpName } }] } + ) { + affected_rows + } + } +` +export const GET_RATING_BY_BP = gql` + query getRating($user: String, $bp: String) { + userRatings: user_ratings( + where: { _and: [{ user: { _eq: $user } }, { bp: { _eq: $bp } }] } + ) { + user + bp + ratings + tx_data + } + } +` diff --git a/webapp/src/graphql.js b/webapp/src/graphql.js new file mode 100644 index 00000000..72068020 --- /dev/null +++ b/webapp/src/graphql.js @@ -0,0 +1,55 @@ +import { + split, + HttpLink, + ApolloLink, + ApolloClient, + InMemoryCache, + from +} from '@apollo/client' +import { getMainDefinition } from '@apollo/client/utilities' +import { WebSocketLink } from '@apollo/client/link/ws' + +import { graphqlConfig } from './config' + +const httpLink = new HttpLink({ + uri: graphqlConfig.url +}) + +const wsLink = new WebSocketLink({ + uri: graphqlConfig.url.replace(/^http?/, 'ws').replace(/^https?/, 'wss'), + options: { + lazy: true, + reconnect: true + } +}) + +const splitLink = split( + ({ query }) => { + const definition = getMainDefinition(query) + + return ( + definition.kind === 'OperationDefinition' && + definition.operation === 'subscription' + ) + }, + wsLink, + httpLink +) + +const authMiddleware = new ApolloLink((operation, forward) => { + operation.setContext(({ headers = {} }) => ({ + headers: { + ...headers, + Authorization: localStorage.getItem('token') + ? `Bearer ${localStorage.getItem('token')}` + : 'pasa' + } + })) + + return forward(operation) +}) + +export const client = new ApolloClient({ + link: from([authMiddleware, splitLink]), + cache: new InMemoryCache() +}) diff --git a/webapp/src/hooks/useDebounce/index.js b/webapp/src/hooks/useDebounce/index.js new file mode 100644 index 00000000..5bf99498 --- /dev/null +++ b/webapp/src/hooks/useDebounce/index.js @@ -0,0 +1,19 @@ +import { useState, useEffect } from 'react' + +const useDebounce = (value, delay) => { + const [debouncedValue, setDebouncedValue] = useState(value) + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value) + }, delay) + + return () => { + clearTimeout(handler) + } + }, [value, delay]) + + return debouncedValue +} + +export default useDebounce diff --git a/webapp/src/i18n.js b/webapp/src/i18n.js index 0ddd9673..46a38172 100644 --- a/webapp/src/i18n.js +++ b/webapp/src/i18n.js @@ -7,10 +7,10 @@ i18n .use(LanguageDetector) .use(initReactI18next) .init({ + load: 'unspecific', resources, + fallbackNS: 'common', fallbackLng: 'en', - lng: localStorage.getItem('LANGUAGE') || 'en', - caches: ['localStorage', 'cookie'], interpolation: { escapeValue: false } diff --git a/webapp/src/index.js b/webapp/src/index.js index 27a20817..815eb6b5 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -1,39 +1,32 @@ import React from 'react' -import ReactDOM from 'react-dom' -import { Provider } from 'react-redux' -import { getPersistor } from '@rematch/persist' -import { MuiThemeProvider, CssBaseline } from '@material-ui/core' -import { UALProvider, withUAL } from 'ual-reactjs-renderer' -import { PersistGate } from 'redux-persist/lib/integration/react' +import { render } from 'react-dom' +import { UALProvider, withUAL } from '@eoscostarica/ual-reactjs-renderer' +import { ApolloProvider } from '@apollo/client' -import { authenticators, network } from './utils/ualAuthenticators' -import store from './store' -import theme from './config/theme' import App from './app' +import { client } from './graphql' import * as serviceWorker from './serviceWorker' +import { ualConfig } from './config' +import { SharedStateProvider } from './context/state.context' -import './config/radar' -import './i18n' +const SharedStateProviderWithUAL = withUAL(SharedStateProvider) -const persistor = getPersistor() -const AppWithUAL = withUAL(App) - -ReactDOM.render( - - - - - - - - - - , +render( + + + + + + + , document.getElementById('root') ) -serviceWorker.unregister() +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: http://bit.ly/CRA-PWA +serviceWorker.register() diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json index a0d19c42..efda2855 100644 --- a/webapp/src/language/en.json +++ b/webapp/src/language/en.json @@ -42,7 +42,7 @@ "loginValidationPassword": "Password is required", "settingsTitle": "Settings", - "settingsLanguages": "English/Spanish", + "settingsLanguages": "English/Spanish/한국어", "settingsNotifications": "Notifications", "navigationRecents": "Recent", @@ -54,19 +54,20 @@ "notFound": "Not found", "noBpJson": "No BP.json file provided.", - "drawerLinkHome": "Home", - "drawerLinkAllBPs": "Block Producers", - "drawerLinkNetworkMonitor": "EOS Network Monitor", - "drawerLinkSettings": "Settings", - "drawerLinkAccount": "Account", - "drawerLinkAllProxies": "Proxies", - "drawerLinkAbout": "About", - "drawerLinkRicardianContract": "Ricardian Contract", - "drawerLinkHelp": "Help", + "home": "Home", + "myAccount": "My Account", + "blockProducers": "Block Producers", + "networkMonitor": "EOS Network Monitor", + "settings": "Settings", + "account": "Account", + "proxies": "Proxies", + "about": "About", + "ricardianContract": "Ricardian Contract", + "help": "Help", "lockedRating": "You must vote for at least 21 block producers or a proxy to unlock ratings", "edenMemberMessage": "Eden member. Ratings unlocked.", "unlockedRating": "You have voted for 21 bps or a proxy and have unlocked ratings", - "success" : "Success!", + "success": "Success!", "appBarSignIn": "Sign In", "connecting": "Connecting", @@ -74,10 +75,11 @@ "connectingErrorTitle": "Error", "connectingErrorActionBtn": "Ok", - "hideComparisonTool": "Hide comparison tool", - "showComparisonTool": "Show comparison tool", - "language": "language", - "version": "Version" + "hideComparisonTool": "Hide Comparison Tool", + "showComparisonTool": "Show Comparison Tool", + "language": "Language", + "version": "Version", + "signOut": "Sign Out" }, "sortInput": { @@ -165,36 +167,37 @@ "community": "Community", "development": "Development", "voteWithoutLogin": "You need to login to execute this action", - "success" : "Success!" + "success": "Success!" }, "bpRatePage": { "allBPs": "All Block Producers", - "subTitle": "Rate Block Producer", - "subText": "Use the sliders to rate the BP.", - "rateText": "If you feel that you do not have enough knowledge about a specific category you can disable it.", - "helpText": "Publish your BP rating by signing in with your favorite wallet.", + "subTitle": "Rate This Block Producer", + "helpText": "Drag the slider to rate each category. 1 means poor performance while 10 means outstanding performance. You can disable any category if you feel you want to do some research before rating it. Once you’re ready, you can publish your rating using your wallet.", "publishRatingButton": "Publish Rating", "updateRatingButton": "Update Rating", "cancelRatingButton": "Cancel", "transparency": "Transparency", - "transparencyTooltip": "Compliance with disclosure of ownership.", + "transparencyTooltip": "Compliance with disclosure of ownership, complete bp.json, use of rewards, and financial stats.", "infrastructure": "Infrastructure", "infrastructureTooltip": "Stability and reliability of the EOS infrastructure.", "trustiness": "Trustiness", "trustinessTooltip": "Collaboration and reputation among the EOS community.", "community": "Community", - "communityTooltip": "Community value creation through education, events, and other useful content.", + "communityTooltip": "Community value creation through education and promoting talks, chats, hackathons, conferences, seminars, developer spaces, and other useful content.", "development": "Development", "developmentTooltip": "Technical know-how and usage of open-source software, scripts, frameworks, wallets, voting portals, metrics, etc.", "globalRate": "General Rating", "myRate": "My Rating", "edenRates": "Eden Rating", + "totalRates": "Total Rating", "rateWithoutLogin": "You need to login to rate this block producer", "noBlockProducer": "This BP Does Not Exist.", - "success" : "Success!", + "success": "Success!", "title": "Rate EOS Block Producer Infrastructure and Community Reputation", - "infoMessage": "Support the network by voting for your favorite BPs or proxy, once you have voted for 21 BPs you can start rating." + "infoMessage": "Support the network by voting for your favorite BPs or proxy, once you have voted for 21 BPs you can start rating.", + "enabled": "Enabled", + "disabled": "Disabled" }, "footer": { @@ -205,6 +208,7 @@ "generalInformation": "General Information", "eosRates": "General Rating", "edenRates": "Eden Rating", + "totalRates": "Total Rating", "raters": "Raters", "amount": "Ratings", "rankings": "Rankings", @@ -237,7 +241,7 @@ "totalVotes": "Total Votes", "voteWithoutLogin": "You need to login to vote for this proxy", "labelTool": "votes for", - "success" : "Success!", + "success": "Success!", "title": "Block Producer Community Ratings for", "proxyProfile": "Reviews on EOS proxy account", "interview": "BP interview:", diff --git a/webapp/src/language/es.json b/webapp/src/language/es.json index e4a80567..98033743 100644 --- a/webapp/src/language/es.json +++ b/webapp/src/language/es.json @@ -54,15 +54,16 @@ "not-found": "Recurso no encontrado", "noBpJson": "No encontramos un bp.json!", - "drawerLinkHome": "Página Principal", - "drawerLinkAllBPs": "Productores de Bloques", - "drawerLinkNetworkMonitor": "Monitor de Red EOS", - "drawerLinkSettings": "Configuración", - "drawerLinkAccount": "Cuenta", - "drawerLinkAllProxies": "Proxies", - "drawerLinkAbout": "Acerca de EOS Rate", - "drawerLinkRicardianContract": "Contratos Ricardianos", - "drawerLinkHelp": "Ayuda", + "home": "Página Principal", + "myAccount": "Mi Cuenta", + "blockProducers": "Productores de Bloques", + "networkMonitor": "Monitor de Red EOS", + "settings": "Configuración", + "account": "Cuenta", + "proxies": "Proxies", + "about": "Acerca de EOS Rate", + "ricardianContract": "Contratos Ricardianos", + "help": "Ayuda", "lockedRating": "Debes votar por al menos 21 productores de bloques o un proxy para desbloquear calificaciones", "edenMemberMessage": "Miembro de Eden. Calificaciones desbloqueadas.", "unlockedRating": "Ha votado por 21 bps o un proxy y ha desbloqueado calificaciones", @@ -77,7 +78,8 @@ "hideComparisonTool": "Ocultar herramienta de comparación", "showComparisonTool": "Mostrar herramienta de comparación", "language": "Idioma", - "version": "Versión" + "version": "Versión", + "signOut": "Cerrar Sesión" }, "sortInput": { @@ -170,31 +172,32 @@ "bpRatePage": { "allBP": "Lista de Productores de Bloques", - "subTitle": "Califique este Productor de bloques EOS", - "subText": "Use los controles deslizantes para calificar.", - "rateText": "Si cree que no tiene suficiente conocimiento sobre una categoría específica, puede deshabilitarla.", + "subTitle": "Califique este productor de bloques", "helpText": "Publique su calificación iniciando sesión con tu billetera favorita.", "publishRatingButton": "Publicar Calificación", "updateRatingButton": "Actualizar Calificación", "cancelRatingButton": "Cancelar", "transparency": "Transparencia", - "transparencyTooltip": "Cumplimiento de la divulgación de la información.", + "transparencyTooltip": "Cumplimiento de la divulgación de propiedad, bp.json completo, uso de recompensas y estadísticas financieras.", "infrastructure": "Infraestructura", "infrastructureTooltip": "Estabilidad y confiabilidad de la infraestructura EOS.", "trustiness": "Lealtad", "trustinessTooltip": "Colaboración y reputación entre la comunidad EOS.", "community": "Comunidad", - "communityTooltip": "Creación de valor comunitario a través de la educación, eventos y/o otros contenidos útiles.", + "communityTooltip": "Creación de valor comunitario a través de la educación y la promoción de charlas, chats, hackatones, conferencias, seminarios, espacios para desarrolladores y otros contenidos útiles.", "development": "Desarrollo", "developmentTooltip": "Conocimientos técnicos y uso de software de código abierto, scripts, marcos, billeteras, portales de votación, métricas, etc.", "globalRate": "Evaluación General", "myRate": "Mi Evaluación", "edenRates": "Evaluación Eden", + "totalRates": "Calificación Total", "rateWithoutLogin": "Necesitas iniciar sesión para evaluar un productor de bloques", "noBlockProducer": "No encontramos este PB", "success": "¡Éxito!", "title": "Calificación de Productores de bloques EOS", - "infoMessage": "Apoye la red votando por sus BP o proxy favoritos, una vez que haya votado por 21 BP puede comenzar a calificar." + "infoMessage": "Apoye la red votando por sus BP o proxy favoritos, una vez que haya votado por 21 BP puede comenzar a calificar.", + "enabled": "Habilitado", + "disabled": "Deshabilitado" }, "footer": { @@ -205,6 +208,7 @@ "generalInformation": "Información General", "eosRates": "Calificación General", "edenRates": "Calificación Eden", + "totalRates": "Calificación Total", "raters": "Calificadores", "amount": "Calificaciones", "rankings": "Promedio", diff --git a/webapp/src/language/ko.json b/webapp/src/language/ko.json index 85622fee..cb7f567c 100644 --- a/webapp/src/language/ko.json +++ b/webapp/src/language/ko.json @@ -1,305 +1,310 @@ { - "translations": { - "community": "커뮤니티 참여율", - "development": "개발지원 참여율", - "infrastructure": "인프라구축 참여율", - "transparency": "투명성", - "trustiness": "신뢰성", + "translations": { + "community": "커뮤니티 참여율", + "development": "개발지원 참여율", + "infrastructure": "인프라구축 참여율", + "transparency": "투명성", + "trustiness": "신뢰성", - "bpsTitle": "EOS 블럭생산자 순위 목록 - EOS Rate", - "proxiesTitle": "EOS 투표대리인 목록 과 투표툴 - EOS Rate", - "availableToRate": "여러분께서 직접 블럭생산자들을 평가 할 수 있습니다", - "notAvailableToRate": "투표대리인에게 투표권한을 위임하거나, 21개 이상의 블럭생산자들에게 직접 투표가 필요합니다", - "voteWithoutLogin": "투표를 하기 위해서 EOS계정에 로그인이 필요합니다", - "btnVoteBPs": "투표", - "clearSelection": "모든선택 취소", - "loadMore": "더 보기", - "view": "추가정보", - "rate": "평가", - "updateRatingButton": "평가 내용 업데이트하기", - "remove": "투표 철회", - "addToVote": "투표대상 추가", - "selected": "선택됨", - "details": "세부사항", - "voting": "투표", + "bpsTitle": "EOS 블럭생산자 순위 목록 - EOS Rate", + "proxiesTitle": "EOS 투표대리인 목록 과 투표툴 - EOS Rate", + "availableToRate": "여러분께서 직접 블럭생산자들을 평가 할 수 있습니다", + "notAvailableToRate": "투표대리인에게 투표권한을 위임하거나, 21개 이상의 블럭생산자들에게 직접 투표가 필요합니다", + "voteWithoutLogin": "투표를 하기 위해서 EOS계정에 로그인이 필요합니다", + "btnVoteBPs": "투표", + "clearSelection": "모든선택 취소", + "loadMore": "더 보기", + "view": "추가정보", + "rate": "평가", + "updateRatingButton": "평가 내용 업데이트하기", + "remove": "투표 철회", + "addToVote": "투표대상 추가", + "selected": "선택됨", + "details": "세부사항", + "voting": "투표", - "compareToolTitle": "비교 도구", - "compareToolToggle": "비교", - "voteToolToggle": "투표", - "compareToolCollapsedSwitch": "그래프 모아보기", - "voteToolTitle": "투표 도구", - "noBPSelected": "선택된 블럭생산자가 없습니다", - "noSelectedBP": "아직 블록생산자가 선택되지 않았습니다. '투표대상에 추가'를 클릭하고 투표를 진행할 수 있습니다", - "voteToolDescription": "EOS 계정에 로그인한 후 선택한 블록생산자에게 투표하십시오", - "chosen": "선택됨", - "averageCard": "평균점수", - "rateCard": "평가횟수", + "compareToolTitle": "비교 도구", + "compareToolToggle": "비교", + "voteToolToggle": "투표", + "compareToolCollapsedSwitch": "그래프 모아보기", + "voteToolTitle": "투표 도구", + "noBPSelected": "선택된 블럭생산자가 없습니다", + "noSelectedBP": "아직 블록생산자가 선택되지 않았습니다. '투표대상에 추가'를 클릭하고 투표를 진행할 수 있습니다", + "voteToolDescription": "EOS 계정에 로그인한 후 선택한 블록생산자에게 투표하십시오", + "chosen": "선택됨", + "averageCard": "평균점수", + "rateCard": "평가횟수", - "loginUsername": "사용자 이름", - "loginPassword": "비밀번호", - "loginSignin": "로그인", - "loginValidationUsername": "사용자이름이 필요합니다", - "loginValidationPassword": "비밀번호가 필요합니다", + "loginUsername": "사용자 이름", + "loginPassword": "비밀번호", + "loginSignin": "로그인", + "loginValidationUsername": "사용자이름이 필요합니다", + "loginValidationPassword": "비밀번호가 필요합니다", - "settingsTitle": "설정", - "settingsLanguages": "English/Spanish/한국어", - "settingsNotifications": "알림", + "settingsTitle": "설정", + "settingsLanguages": "English/Spanish/한국어", + "settingsNotifications": "알림", - "navigationRecents": "최근", - "navigationRate": "평가", - "navigationSettings": "설정", + "navigationRecents": "최근", + "navigationRate": "평가", + "navigationSettings": "설정", - "searchAutocomplete": "탐색...", + "searchAutocomplete": "탐색...", - "notFound": "찾을 수 없음", - "noBpJson": "BP.json 파일이 제공되지 않았습니다", + "notFound": "찾을 수 없음", + "noBpJson": "BP.json 파일이 제공되지 않았습니다", - "drawerLinkHome": "홈", - "drawerLinkAllBPs": "블럭 생산자", - "drawerLinkNetworkMonitor": "EOS 네트워크 모니터", - "drawerLinkSettings": "설정", - "drawerLinkAccount": "계정", - "drawerLinkAllProxies": "투표 대리인", - "drawerLinkAbout": "EOS Rate 정보", - "drawerLinkRicardianContract": "리카르디안 계약서", - "drawerLinkHelp": "도움말", - "lockedRating": "평가를 잠금 해제하려면 투표대리인에게 투표권한을 위임하거나, 21개 이상의 블럭생산자들에게 직접 투표가 필요합니다", - "edenMemberMessage": "Eden 멤버. 평가 잠금해제", - "unlockedRating": "21개 이상의 블럭생산자들에게 직접 투표했거나, 투표대리인에게 투표권한을 위임하였으므로 평가가 잠금 해제되었습니다", - "success": "성공!", - "appBarSignIn": "로그인", + "home": "홈", + "myAccount": "내 계정", + "blockProducers": "블럭 생산자", + "networkMonitor": "EOS 네트워크 모니터", + "settings": "설정", + "account": "계정", + "proxies": "투표 대리인", + "about": "EOS Rate 정보", + "ricardianContract": "리카르디안 계약서", + "help": "도움말", + "lockedRating": "평가를 잠금 해제하려면 투표대리인에게 투표권한을 위임하거나, 21개 이상의 블럭생산자들에게 직접 투표가 필요합니다", + "edenMemberMessage": "Eden 멤버. 평가 잠금해제", + "unlockedRating": "21개 이상의 블럭생산자들에게 직접 투표했거나, 투표대리인에게 투표권한을 위임하였으므로 평가가 잠금 해제되었습니다", + "success": "성공!", + "appBarSignIn": "로그인", - "connecting": "연결", - "connectingWith": "와 연결", - "connectingErrorTitle": "에러", - "connectingErrorActionBtn": "에러 해결", + "connecting": "연결", + "connectingWith": "와 연결", + "connectingErrorTitle": "에러", + "connectingErrorActionBtn": "에러 해결", - "hideComparisonTool": "비교 도구 숨김", - "showComparisonTool": "비교 도구 표시", - "language": "언어" - }, + "hideComparisonTool": "비교 도구 숨김", + "showComparisonTool": "비교 도구 표시", + "language": "언어", + "version": "버전", + "signOut": "로그아웃" + }, - "sortInput": { - "vote": "최고득표 순서", - "alphabetical": "알파벳 순서", - "ratings": "평가횟수 순서", - "generalRate": "일반 최고평점 순서", - "edenRate": "Eden 최고평점 순서", - "community": "커뮤니티 참여율", - "development": "개발지원 참여율", - "infrastructure": "인프라구축 참여율", - "transparency": "투명성", - "trustiness": "신뢰성" - }, + "sortInput": { + "vote": "최고득표 순서", + "alphabetical": "알파벳 순서", + "ratings": "평가횟수 순서", + "generalRate": "일반 최고평점 순서", + "edenRate": "Eden 최고평점 순서", + "community": "커뮤니티 참여율", + "development": "개발지원 참여율", + "infrastructure": "인프라구축 참여율", + "transparency": "투명성", + "trustiness": "신뢰성" + }, - "not-found": { - "graphic": "헉! 이런!", - "description": "뭔가 잘못 된 것 같습니다!", - "recoveryCta": "홈을 클릭하세요" - }, + "not-found": { + "graphic": "헉! 이런!", + "description": "뭔가 잘못 된 것 같습니다!", + "recoveryCta": "홈을 클릭하세요" + }, - "home": { - "title": "EOS 블록생산자 평가 및 블럭생산자 투표 포털 - EOS Rate", - "cover": { - "title": "당신의 목소리를 들려주세요. 블럭생산자들을 평가하세요", - "paragraph": { - "subtitle1": "EOS Rate란? ", - "text1": "EOS Rate는 EOS 토큰 보유자가 클릭 몇 번으로 블록 생산자들을 평가할 수 있는 오픈 소스 dApp입니다. 사용자는 평가 시스템 및 투표 포털에 액세스할 수 있으므로 토큰 보유자가 정보에 입각한 결정을 더 쉽게 내릴 수 있습니다.", - "text2": "EOS Rate는 평가결과를 수집하여 글로벌 다수의 의견('대중의 지혜')을 포착하고, 투표 패턴이 유권자의 정서를 진정으로 반영하는지 측정합니다.", - "subtitle2": "EOS Rate는 어떻게 작동합니까?", - "text3": "평가를 제출하려면 토큰 보유자가 EOS 지갑으로 로그인해야 합니다. 이는 하나의 계정이 블럭생산자당 하나의 평가 제출만 나타낼 수 있음을 의미합니다. 평가는 EOS 블록체인에 안전하게 저장되어 불변성을 보장합니다.", - "text4": "EOS Rate 포털에 액세스하여 평가를 제출하고 당신의 목소리를 높이십시오." - }, - "cta": "지금 평가 시작" - }, - "subTopic": { - "videoUrl": "https://www.youtube.com/embed/saZnZqJsMhk", - "title": "진정한 민주주의", - "paragraph1": "여러분이 가장 대표성을 가졌다고 생각하는 BPs 찾아 보세요.", - "paragraph2": "EOS Rate는 커뮤니티의 투명성을 기반으로 구축 되었습니다.각각의 BPs들의 프로파일을 생성합니다. 원형(LEAF-Liquid EOS Attribute Factors)의 내부에서 EOS 토큰 홀더들이 투표로 선택된 내용들이 시작적으로 보여줌으로서 객관적이고 직관적인 선택을 할 수 있도록 도와 줍니다.", - "subtitle": "자 그럼 평가를 시작 하세요!", - "text": "사용하는 도중에 질문사항이나 건의 사항이 있다면 우리에게 연락 해 주세요", - "telegramGroup": "텔레그램 그룹" - }, - "ratingCategory": { - "title": "평가내역 카테고리", - "transparency": { - "title": "투명도", - "description": "오너쉽 기반의 공시의 투명성은 bp.json,리워드 사용공개,재무상대공개로 가능합니다." - }, - "infrastructure": { - "title": "인프라", - "description": "EOS 인프라의 안정성과 신뢰도 구축 ." - }, - "trustiness": { - "title": "신뢰도", - "description": "EOS 커뮤니티의 협업과 함께 구축된 평판." - }, - "community": { - "title": "커뮤니티", - "description": "커뮤니의 가치는 SNS상의 대화,헤커톤,컨프런스,세미나,개발자 전용 공간 제공,유용한 컨텐츠 제공으로 인한 교육과 건전한 토론은 커뮤니티의 새로운 가치를 만들고 성장 할 수 있습니다." - }, - "development": { - "title": "개발", - "description": "기술정보 - 오픈소스 기반의 사용정보,스크립트,프레임워크,월렛,투표포탈,메트릭스,등등등." - } - } - }, + "home": { + "title": "EOS 블록생산자 평가 및 블럭생산자 투표 포털 - EOS Rate", + "cover": { + "title": "당신의 목소리를 들려주세요. 블럭생산자들을 평가하세요", + "paragraph": { + "subtitle1": "EOS Rate란? ", + "text1": "EOS Rate는 EOS 토큰 보유자가 클릭 몇 번으로 블록 생산자들을 평가할 수 있는 오픈 소스 dApp입니다. 사용자는 평가 시스템 및 투표 포털에 액세스할 수 있으므로 토큰 보유자가 정보에 입각한 결정을 더 쉽게 내릴 수 있습니다.", + "text2": "EOS Rate는 평가결과를 수집하여 글로벌 다수의 의견('대중의 지혜')을 포착하고, 투표 패턴이 유권자의 정서를 진정으로 반영하는지 측정합니다.", + "subtitle2": "EOS Rate는 어떻게 작동합니까?", + "text3": "평가를 제출하려면 토큰 보유자가 EOS 지갑으로 로그인해야 합니다. 이는 하나의 계정이 블럭생산자당 하나의 평가 제출만 나타낼 수 있음을 의미합니다. 평가는 EOS 블록체인에 안전하게 저장되어 불변성을 보장합니다.", + "text4": "EOS Rate 포털에 액세스하여 평가를 제출하고 당신의 목소리를 높이십시오." + }, + "cta": "지금 평가 시작" + }, + "subTopic": { + "videoUrl": "https://www.youtube.com/embed/saZnZqJsMhk", + "title": "진정한 민주주의", + "paragraph1": "여러분이 가장 대표성을 가졌다고 생각하는 BPs 찾아 보세요.", + "paragraph2": "EOS Rate는 커뮤니티의 투명성을 기반으로 구축 되었습니다.각각의 BPs들의 프로파일을 생성합니다. 원형(LEAF-Liquid EOS Attribute Factors)의 내부에서 EOS 토큰 홀더들이 투표로 선택된 내용들이 시작적으로 보여줌으로서 객관적이고 직관적인 선택을 할 수 있도록 도와 줍니다.", + "subtitle": "자 그럼 평가를 시작 하세요!", + "text": "사용하는 도중에 질문사항이나 건의 사항이 있다면 우리에게 연락 해 주세요", + "telegramGroup": "텔레그램 그룹" + }, + "ratingCategory": { + "title": "평가내역 카테고리", + "transparency": { + "title": "투명도", + "description": "오너쉽 기반의 공시의 투명성은 bp.json,리워드 사용공개,재무상대공개로 가능합니다." + }, + "infrastructure": { + "title": "인프라", + "description": "EOS 인프라의 안정성과 신뢰도 구축 ." + }, + "trustiness": { + "title": "신뢰도", + "description": "EOS 커뮤니티의 협업과 함께 구축된 평판." + }, + "community": { + "title": "커뮤니티", + "description": "커뮤니의 가치는 SNS상의 대화,헤커톤,컨프런스,세미나,개발자 전용 공간 제공,유용한 컨텐츠 제공으로 인한 교육과 건전한 토론은 커뮤니티의 새로운 가치를 만들고 성장 할 수 있습니다." + }, + "development": { + "title": "개발", + "description": "기술정보 - 오픈소스 기반의 사용정보,스크립트,프레임워크,월렛,투표포탈,메트릭스,등등등." + } + } + }, - "account": { - "account_name": "어카운트", - "active": "액티브", - "activity": "액티비티", - "authority": "권한", - "core_liquid_balance": "리퀴드 발란스", - "inactive": "비활성", - "logout": "로그아웃", - "title": "어카운트 프로파일t", - "yourRating": "당신의 평가", - "unpublish": "평가 지우기", - "youRated": "이미 평가된", - "infrastructure": "인프라", - "transparency": "투명도", - "trustiness": "신뢰도", - "community": "커뮤니티", - "development": "개발", - "voteWithoutLogin": "로그인을 하여 실행 할 수 있습니다", - "success": "성공!" - }, + "account": { + "account_name": "어카운트", + "active": "액티브", + "activity": "액티비티", + "authority": "권한", + "core_liquid_balance": "리퀴드 발란스", + "inactive": "비활성", + "logout": "로그아웃", + "title": "어카운트 프로파일t", + "yourRating": "당신의 평가", + "unpublish": "평가 지우기", + "youRated": "이미 평가된", + "infrastructure": "인프라", + "transparency": "투명도", + "trustiness": "신뢰도", + "community": "커뮤니티", + "development": "개발", + "voteWithoutLogin": "로그인을 하여 실행 할 수 있습니다", + "success": "성공!" + }, - "bpRatePage": { - "allBPs": "모든 BPs 리스트", - "subTitle": "BPs 평가r", - "subText": "슬라이드 기능을 사용하여 BPs 평가하기.", - "rateText": "특정 카테고리 부분에 대한 정보가 부족할경우 선택을 하지 않고 비활성화 상태로 두셔도 됩니다.", - "helpText": "선호하는 월렛으로 로그인하여 BPs 평가를 공개 하세요.", - "publishRatingButton": "평가내용 공개하기", - "updateRatingButton": "평가 내용 업데이트하기", - "cancelRatingButton": "취소", - "transparency": "투명도", - "transparencyTooltip": "오너쉽의 공개로 인한 투명성.", - "infrastructure": "인프라", - "infrastructureTooltip": "EOS 인프라의 안정성과 신뢰도 .", - "trustiness": "신뢰도", - "trustinessTooltip": "EOS 커뮤니티와의 협업으로 형성된 평판.", - "community": "커뮤니티", - "communityTooltip": "커뮤니티는 교육과 이벤트 및 유용한 컨텐츠를 통해서 가치를 올릴 수 있습니다.", - "development": "개발", - "developmentTooltip": "기술정보 - 오픈소스 기반의 사용정보,스크립트,프레임워크,월렛,투표포탈,메트릭스,등등등.", - "globalRate": "기본적인 평가", - "myRate": "나의 평가내역", - "edenRates": "Eden 평가내역", - "rateWithoutLogin": "BPs 평가를 하기 위해서는 로그인이 필요 합니다", - "noBlockProducer": "존재하지 않는 BP.", - "success": "성공!", - "title": "BPs의 인프라와 커뮤니티 평판 평가하기", - "infoMessage": "여러분이 선호하는 BPs에게 직접 투표 혹은 프록시를 통해서 네트워크를 지지하세요,21BPs에게 투표된 평가를 시작 할 수 있습니다." - }, + "bpRatePage": { + "allBPs": "모든 BPs 리스트", + "subTitle": "이 블록 생산자 평가", + "helpText": "선호하는 월렛으로 로그인하여 BPs 평가를 공개 하세요.", + "publishRatingButton": "평가내용 공개하기", + "updateRatingButton": "평가 내용 업데이트하기", + "cancelRatingButton": "취소", + "transparency": "투명도", + "transparencyTooltip": "소유권 공개, 완전한 bp.json, 보상 사용 및 재무 통계 준수.", + "infrastructure": "인프라", + "infrastructureTooltip": "EOS 인프라의 안정성과 신뢰도 .", + "trustiness": "신뢰도", + "trustinessTooltip": "EOS 커뮤니티와의 협업으로 형성된 평판.", + "community": "커뮤니티", + "communityTooltip": "교육 및 홍보를 통한 커뮤니티 가치 창출, 대화, 채팅, 해커톤, 컨퍼런스, 세미나, 개발자 공간 및 기타 유용한 콘텐츠.", + "development": "개발", + "developmentTooltip": "기술정보 - 오픈소스 기반의 사용정보,스크립트,프레임워크,월렛,투표포탈,메트릭스,등등등.", + "globalRate": "기본적인 평가", + "myRate": "나의 평가내역", + "edenRates": "Eden 평가내역", + "totalRates": "총 평점", + "rateWithoutLogin": "BPs 평가를 하기 위해서는 로그인이 필요 합니다", + "noBlockProducer": "존재하지 않는 BP.", + "success": "성공!", + "title": "BPs의 인프라와 커뮤니티 평판 평가하기", + "infoMessage": "여러분이 선호하는 BPs에게 직접 투표 혹은 프록시를 통해서 네트워크를 지지하세요,21BPs에게 투표된 평가를 시작 할 수 있습니다.", + "enabled": "활성화됨", + "disabled": "장애가있는" + }, - "footer": { - "legend": "기여하고 싶으신가요? 이 서비스 dapp은 오픈소스 입니다" - }, + "footer": { + "legend": "기여하고 싶으신가요? 이 서비스 dapp은 오픈소스 입니다" + }, - "profile": { - "generalInformation": "기본적인 정보", - "eosRates": "기본적인 평가", - "edenRates": "Eden 평가", - "raters": "평가자", - "amount": "평가", - "rankings": "평균", - "social": "소셜", - "additionalResource": "추가 리소스", - "researchPortal": "EOS 블록 프로듀서 연구 포털", - "bpValidator": "블록 생산자 검증자", - "bpInterviews": "블록 프로듀서 인터뷰", - "account": "어카운트", - "location": "지역", - "status": "상태", - "website": "웹사이트", - "votes": "투표", - "rates": "평가", - "average": "평균", - "websiteInfo": "제공된 웹사이트", - "buttonRate": "선택한 BP 평가", - "buttonVote": "선택한 프록시 투표", - "updateRatingButton": "평가 내용 업데이트하기", - "allBP": "모든 BPs", - "allP": "모든 프록시", - "noBpJson": "선택한 BP의 bp.json 파일을 찾을 수 없습니다.", - "noCountryName": "공개된 지역 없음.", - "noBlockProducer": "선택한 BP 정보 없음.", - "noWebSiteInfo": "제공된 웹사이트 정보 없음.", - "proxyVotes": "프록시 투표", - "philosophy": "철학", - "slogan": "슬로건", - "background": "백그라운드", - "totalVotes": "토탈 득표수", - "voteWithoutLogin": "로그인하여 선택한 프록시를 투표 할 수 있습니다", - "labelTool": "투표하기r", - "success": "성공!", - "title": "BPs 커뮤니티 평가하기", - "proxyProfile": "EOS 프록시 어카운트 리뷰", - "interview": "BP 인터뷰:", - "additionalResources": "자원지원" - }, + "profile": { + "generalInformation": "기본적인 정보", + "eosRates": "기본적인 평가", + "edenRates": "Eden 평가", + "totalRates": "총 평점", + "raters": "평가자", + "amount": "평가", + "rankings": "평균", + "social": "소셜", + "additionalResource": "추가 리소스", + "researchPortal": "EOS 블록 프로듀서 연구 포털", + "bpValidator": "블록 생산자 검증자", + "bpInterviews": "블록 프로듀서 인터뷰", + "account": "어카운트", + "location": "지역", + "status": "상태", + "website": "웹사이트", + "votes": "투표", + "rates": "평가", + "average": "평균", + "websiteInfo": "제공된 웹사이트", + "buttonRate": "선택한 BP 평가", + "buttonVote": "선택한 프록시 투표", + "updateRatingButton": "평가 내용 업데이트하기", + "allBP": "모든 BPs", + "allP": "모든 프록시", + "noBpJson": "선택한 BP의 bp.json 파일을 찾을 수 없습니다.", + "noCountryName": "공개된 지역 없음.", + "noBlockProducer": "선택한 BP 정보 없음.", + "noWebSiteInfo": "제공된 웹사이트 정보 없음.", + "proxyVotes": "프록시 투표", + "philosophy": "철학", + "slogan": "슬로건", + "background": "백그라운드", + "totalVotes": "토탈 득표수", + "voteWithoutLogin": "로그인하여 선택한 프록시를 투표 할 수 있습니다", + "labelTool": "투표하기r", + "success": "성공!", + "title": "BPs 커뮤니티 평가하기", + "proxyProfile": "EOS 프록시 어카운트 리뷰", + "interview": "BP 인터뷰:", + "additionalResources": "자원지원" + }, - "about": { - "tabTitle": "BP의 EOS 평가진행과 EOS 투표 툴 제공", - "title": "EOS RATE: EOS 메인넷의 평가내역", - "subtitle1": "EOS 메인넷은 무엇인가?", - "body1": { - "paragraph1": "만약 여러분이 EOSio 커뮤니티에 속해 있거나 EOSio블록체인에 대해서 정보를 읽어 봤다면 EOS 메인넷에 관하여 들어 봤을 것 입니다. EOS 메인넷은 EOSio블록체인 플랫폼의 가장 먼저 런칭을 하였고 가장 중요한 퍼블릭 네트워크라는 것을 의미 합니다. 또한 이 글을 읽고 있다면 블록체인의 용어에 대해서 잘 알 고 있을 것이라고 판단이 됩니다.", - "paragraph2": "EOSIO는 댄 라리머에 의해 개발된 DPoS를 기반으로 하는 합의 메커니즘을 기본적으로 사용 합니다.EOSio에서 DPoS는 EOS토큰 홀더(보유자)들이 BPs 로 불리는 EOS 네트워크를 대표하는 집단에게 투표 하는 과정이 있습니다.EOS 메인넷은 가장 많은 투표를 획득한 21BPs에 의해서 운영이 됩니다.", - "paragraph3": "DPoS는 21개의 투표 네트워크 및 거래소에서 투표로 선출된 BPs노드가 가 직접 블록을 생성하며 리워드를 받을 수 있습니다.EOSio는 DPoS를 사용하여 확장을 함을 목표로 합니다. 그렇다보니 당연히 DPoS의 BPs들은 POW(Proof-of-Work)나 POSProof-of-Stake)보다 더빠르게 합의를 이룰 수 있습니다. 이더리움과 비교한다면 EOS 노드들은 초당 4000이상의 빠른 트랜잭션의 검증을 달성 할 수 있습니다." - }, - "subtitle2": "강력한 권한은 강력한 책임을 필요로 합니다", - "body2": { - "paragraph1": "그럼에도 불구하고 사람들은 DPoS와 EOS 메인넷을 두고 중앙집권화로 발생되는 문제점들을 가지고 있다고 주장들을 합니다. 예를들어 BPs의 의해 어카운트 동결된 내용에 대한 근본 원인을 파악하지 않고 단순하게 동결의 결과만을 보고서 눈살을 찌부리는 것과 같습니다. 또한 그들은 네트워크의 성능저하에 관련된 의견 불일 치와 같은 주장을 합니다.", - "paragraph2": "결론적으로 EOS메인넷의 토큰 홀더들은 EOS 메인넷의 투명도와 민주적인 투표과정을 통해서 선택된 21BPs들을 선택 할 수 있습니다.이 선출된 BPs들은 EOS 메인넷의 커뮤니티를 위해서 보호를 하며 최상의 기술 능력을 구현을 해야만 합니다.", - "paragraph3": "EOS 평가제공 툴을 이용하여 토큰 홀더들의 투표된 내역을 확일 가능합니다. 그렇지만 EOS 메인넷에서 이루어 지는 투표 파워는 토큰 홀더들의 보유 수량에 의해서 결정이 됩니다, 이말의 의미는 토큰 홀더의 보유 수량이 낮다면 그만큼 의견이 적게 반영 된다는 것을 의미 합니다.그러므로 EOS Rate라는 오픈소스프로젝트의 아이디어를 제공하여 EOS 메인넷에서 가장 투명하고 신뢰가 가는 투표과정을 구현 하고자 합니다." - }, - "subtitle3": "EOS Rate란 무엇인가?", - "body3": { - "paragraph1": "EOS Rate는 커뮤니티의 투명성일 기반으로 구축 되었습니다.각각의 BPs들의 프로파일을 생성합니다. 원형(LEAF-Liquid EOS Attribute Factors)의 내부에서 EOS 토큰 홀더들이 투표로 선택된 내용들이 시작적으로 보여줌으로서 객관적이고 직관적인 선택을 할 수 있도록 도와 줍니다.", - "paragraph2": "더불어 EOS 평가의 제공으로 커뮤니티의 반영된 의견, 즉 '많은 사람들의 지혜' 를 반영하는데 많은 도움이 됩니다.글로벌의 모든 내용들을 모으고 투표 패턴이 토큰홀더의 정서를 반영하는의 데이터를 투명하게 제공하고자 합니다.EOS Rate Dapp은 LEAF (Liquid EOS Attribute Factors) 라는 공개된 데이터를 제공하여 토큰홀더가 판단하기 쉬운 원형의 그래픽과 함께 BPs의 프로파일을 제공합니다.", - "paragraph3": "안전하고 투명한 평가를 제출 하기 위해서는 반드시 EOS 월렛을 연동을 필요로 합니다.평가된 기록은 기존의 기록된 평가에 추가적으로 반영되어 업데이트된 그래픽으로 확인 가능합니다.그래서 EOS 평가내용의 프로세스는 우리 모두에게 좋은 결정을 할 수 있도록 정보를 제공 합니다.", - "paragraph4": "추가적으로, 토큰 홀더는 5가지의 카테고리에 평가를 제출 할 수 있습니다:", - "paragraph5": "토큰홀더의 평가된 기록은 기존의 기록된 평가에 추가적으로 반영되어 업데이트된 그래픽으로 확인 가능합니다.그래서 EOS 평가내용의 프로세스는 우리 모두에게 좋은 결정을 할 수 있도록 정보를 제공 합니다:" - }, - "categories": { - "transparency": { - "title": "투명성", - "description": "투명성은 bp.json, BPs 리워드 사용부분, 재무상태 공개와 같은 오너쉽 공개로 가능합니다." - }, - "infrastructure": { - "title": "인프라", - "description": "EOS 인프라의 안정성과 신뢰도 구축." - }, - "trustiness": { - "title": "신뢰", - "description": "EOS 커뮤니티와의 협업과 평판을 만들 수 있습니다." - }, - "community": { - "title": "커뮤니티", - "description": "커뮤니의 가치는 SNS상의 대화,헤커톤,컨프런스,세미나,개발자 전용 공간 제공,유용한 컨텐츠 제공으로 인한 교육과 건전한 토론은 커뮤니티의 새로운 가치를 만들고 성장 할 수 있습니다" - }, - "development": { - "title": "개발지원", - "description": "기술정보 - 오픈소스 기반의 사용정보,스크립트,프레임워크,월렛,투표포탈,메트릭스,등등등" - } - } - }, + "about": { + "tabTitle": "BP의 EOS 평가진행과 EOS 투표 툴 제공", + "title": "EOS RATE: EOS 메인넷의 평가내역", + "subtitle1": "EOS 메인넷은 무엇인가?", + "body1": { + "paragraph1": "만약 여러분이 EOSio 커뮤니티에 속해 있거나 EOSio블록체인에 대해서 정보를 읽어 봤다면 EOS 메인넷에 관하여 들어 봤을 것 입니다. EOS 메인넷은 EOSio블록체인 플랫폼의 가장 먼저 런칭을 하였고 가장 중요한 퍼블릭 네트워크라는 것을 의미 합니다. 또한 이 글을 읽고 있다면 블록체인의 용어에 대해서 잘 알 고 있을 것이라고 판단이 됩니다.", + "paragraph2": "EOSIO는 댄 라리머에 의해 개발된 DPoS를 기반으로 하는 합의 메커니즘을 기본적으로 사용 합니다.EOSio에서 DPoS는 EOS토큰 홀더(보유자)들이 BPs 로 불리는 EOS 네트워크를 대표하는 집단에게 투표 하는 과정이 있습니다.EOS 메인넷은 가장 많은 투표를 획득한 21BPs에 의해서 운영이 됩니다.", + "paragraph3": "DPoS는 21개의 투표 네트워크 및 거래소에서 투표로 선출된 BPs노드가 가 직접 블록을 생성하며 리워드를 받을 수 있습니다.EOSio는 DPoS를 사용하여 확장을 함을 목표로 합니다. 그렇다보니 당연히 DPoS의 BPs들은 POW(Proof-of-Work)나 POSProof-of-Stake)보다 더빠르게 합의를 이룰 수 있습니다. 이더리움과 비교한다면 EOS 노드들은 초당 4000이상의 빠른 트랜잭션의 검증을 달성 할 수 있습니다." + }, + "subtitle2": "강력한 권한은 강력한 책임을 필요로 합니다", + "body2": { + "paragraph1": "그럼에도 불구하고 사람들은 DPoS와 EOS 메인넷을 두고 중앙집권화로 발생되는 문제점들을 가지고 있다고 주장들을 합니다. 예를들어 BPs의 의해 어카운트 동결된 내용에 대한 근본 원인을 파악하지 않고 단순하게 동결의 결과만을 보고서 눈살을 찌부리는 것과 같습니다. 또한 그들은 네트워크의 성능저하에 관련된 의견 불일 치와 같은 주장을 합니다.", + "paragraph2": "결론적으로 EOS메인넷의 토큰 홀더들은 EOS 메인넷의 투명도와 민주적인 투표과정을 통해서 선택된 21BPs들을 선택 할 수 있습니다.이 선출된 BPs들은 EOS 메인넷의 커뮤니티를 위해서 보호를 하며 최상의 기술 능력을 구현을 해야만 합니다.", + "paragraph3": "EOS 평가제공 툴을 이용하여 토큰 홀더들의 투표된 내역을 확일 가능합니다. 그렇지만 EOS 메인넷에서 이루어 지는 투표 파워는 토큰 홀더들의 보유 수량에 의해서 결정이 됩니다, 이말의 의미는 토큰 홀더의 보유 수량이 낮다면 그만큼 의견이 적게 반영 된다는 것을 의미 합니다.그러므로 EOS Rate라는 오픈소스프로젝트의 아이디어를 제공하여 EOS 메인넷에서 가장 투명하고 신뢰가 가는 투표과정을 구현 하고자 합니다." + }, + "subtitle3": "EOS Rate란 무엇인가?", + "body3": { + "paragraph1": "EOS Rate는 커뮤니티의 투명성일 기반으로 구축 되었습니다.각각의 BPs들의 프로파일을 생성합니다. 원형(LEAF-Liquid EOS Attribute Factors)의 내부에서 EOS 토큰 홀더들이 투표로 선택된 내용들이 시작적으로 보여줌으로서 객관적이고 직관적인 선택을 할 수 있도록 도와 줍니다.", + "paragraph2": "더불어 EOS 평가의 제공으로 커뮤니티의 반영된 의견, 즉 '많은 사람들의 지혜' 를 반영하는데 많은 도움이 됩니다.글로벌의 모든 내용들을 모으고 투표 패턴이 토큰홀더의 정서를 반영하는의 데이터를 투명하게 제공하고자 합니다.EOS Rate Dapp은 LEAF (Liquid EOS Attribute Factors) 라는 공개된 데이터를 제공하여 토큰홀더가 판단하기 쉬운 원형의 그래픽과 함께 BPs의 프로파일을 제공합니다.", + "paragraph3": "안전하고 투명한 평가를 제출 하기 위해서는 반드시 EOS 월렛을 연동을 필요로 합니다.평가된 기록은 기존의 기록된 평가에 추가적으로 반영되어 업데이트된 그래픽으로 확인 가능합니다.그래서 EOS 평가내용의 프로세스는 우리 모두에게 좋은 결정을 할 수 있도록 정보를 제공 합니다.", + "paragraph4": "추가적으로, 토큰 홀더는 5가지의 카테고리에 평가를 제출 할 수 있습니다:", + "paragraph5": "토큰홀더의 평가된 기록은 기존의 기록된 평가에 추가적으로 반영되어 업데이트된 그래픽으로 확인 가능합니다.그래서 EOS 평가내용의 프로세스는 우리 모두에게 좋은 결정을 할 수 있도록 정보를 제공 합니다:" + }, + "categories": { + "transparency": { + "title": "투명성", + "description": "투명성은 bp.json, BPs 리워드 사용부분, 재무상태 공개와 같은 오너쉽 공개로 가능합니다." + }, + "infrastructure": { + "title": "인프라", + "description": "EOS 인프라의 안정성과 신뢰도 구축." + }, + "trustiness": { + "title": "신뢰", + "description": "EOS 커뮤니티와의 협업과 평판을 만들 수 있습니다." + }, + "community": { + "title": "커뮤니티", + "description": "커뮤니의 가치는 SNS상의 대화,헤커톤,컨프런스,세미나,개발자 전용 공간 제공,유용한 컨텐츠 제공으로 인한 교육과 건전한 토론은 커뮤니티의 새로운 가치를 만들고 성장 할 수 있습니다" + }, + "development": { + "title": "개발지원", + "description": "기술정보 - 오픈소스 기반의 사용정보,스크립트,프레임워크,월렛,투표포탈,메트릭스,등등등" + } + } + }, - "help": { - "tabTitle": "EOS 커뮤니티 오픈소스에 도움을 주셔서 감사합니다 - EOS Rate", - "title": "EOS Rate를 이용해주셔서 감사합니다", - "paragraph": "EOS Rate는 여전히 진행중인 프로젝트 입니다,사용하는 과정에 오류가 있다면 아래의 링크로 의견을 전달해 주세요", - "githubEOSCR": "EOS Costa Rica 깃허브", - "telegramChannel": "텔레그램 채널", - "websiteEOSCR": "EOS Costa Rica 웹사이트" - }, + "help": { + "tabTitle": "EOS 커뮤니티 오픈소스에 도움을 주셔서 감사합니다 - EOS Rate", + "title": "EOS Rate를 이용해주셔서 감사합니다", + "paragraph": "EOS Rate는 여전히 진행중인 프로젝트 입니다,사용하는 과정에 오류가 있다면 아래의 링크로 의견을 전달해 주세요", + "githubEOSCR": "EOS Costa Rica 깃허브", + "telegramChannel": "텔레그램 채널", + "websiteEOSCR": "EOS Costa Rica 웹사이트" + }, - "termsOfUse": { - "tabTitle": "Ricardian Contracts for EOS Rate Smart Contract" - } + "termsOfUse": { + "tabTitle": "Ricardian Contracts for EOS Rate Smart Contract" + } } diff --git a/webapp/src/language/kr.json b/webapp/src/language/kr.json deleted file mode 100644 index 8b137891..00000000 --- a/webapp/src/language/kr.json +++ /dev/null @@ -1 +0,0 @@ - diff --git a/webapp/src/layouts/Dashboard/index.js b/webapp/src/layouts/Dashboard/index.js new file mode 100644 index 00000000..d4861f23 --- /dev/null +++ b/webapp/src/layouts/Dashboard/index.js @@ -0,0 +1,58 @@ +import React, { useState, useEffect } from 'react' +import PropTypes from 'prop-types' +import Box from '@mui/material/Box' +import { makeStyles } from '@mui/styles' + +import Sidebar from '../../components/Sidebar' +import Header from '../../components/Header' +import Footer from '../../components/Footer' +import Message from '../../components/Message' +import { InitGA, LogPageView } from '../../config/google-analitycs-module' + +import styles from './styles' + +const drawerWidth = 260 +const useStyles = makeStyles(theme => styles(theme, drawerWidth)) + +const Dashboard = ({ children, routes }) => { + const classes = useStyles() + const [mobileOpen, setMobileOpen] = useState(false) + + const handleDrawerToggle = () => { + setMobileOpen(!mobileOpen) + } + + useEffect(() => { + InitGA() + LogPageView() + }, []) + + return ( + + + + + +
+ + {children} +
+ + + + + ) +} + +Dashboard.propTypes = { + children: PropTypes.node, + routes: PropTypes.array +} + +export default Dashboard diff --git a/webapp/src/layouts/Dashboard/styles.js b/webapp/src/layouts/Dashboard/styles.js new file mode 100644 index 00000000..469499a8 --- /dev/null +++ b/webapp/src/layouts/Dashboard/styles.js @@ -0,0 +1,21 @@ +export default (theme, drawerWidth) => ({ + root: { + display: 'flex', + minHeight: '100vh' + }, + mainContent: { + flex: 1, + display: 'flex', + flexDirection: 'column', + maxWidth: '100%', + overflow: 'hidden', + height: '100vh' + }, + childContent: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + height: '100%', + overflow: 'scroll' + } +}) diff --git a/webapp/src/layouts/index.js b/webapp/src/layouts/index.js new file mode 100644 index 00000000..ad42f122 --- /dev/null +++ b/webapp/src/layouts/index.js @@ -0,0 +1 @@ +export { default as DashboardLayout } from './Dashboard' diff --git a/webapp/src/models/BlockProducer/blockProducers.js b/webapp/src/models/BlockProducer/blockProducers.js deleted file mode 100644 index cb89cbec..00000000 --- a/webapp/src/models/BlockProducer/blockProducers.js +++ /dev/null @@ -1,297 +0,0 @@ -import filterObjects from 'filter-objects' -import uniq from 'lodash.uniq' - -import apolloClient from 'services/graphql' -import { getAllBPs } from 'services/bps' -import { getRpc } from 'utils/eosjsUtils' - -import QUERY_PRODUCER from './query_get_producer_by' -import QUERY_RATING from './query_get_bp_rating_by' -import QUERY_EDEN_RATING from './query_get_eden_stats' -import MUTATION_UPDATE_RATING from './mutation_update_rate' -import { contract } from '../../config' - -const initialState = { - filters: {}, - list: [], - filtered: [], - sortBy: null, - selected: [], - compareTool: false, - producer: null, - userRate: null, - edenRate: null, - transaction: null, - showSortSelected: false -} - -const Proxies = { - state: initialState, - reducers: { - toggleCompareTool(state) { - return { - ...state, - compareTool: !state.compareTool - } - }, - setShowSortSelected(state, showSortSelected) { - return { - ...state, - showSortSelected - } - }, - setBPs(state, list) { - // Whenever we get a new list, clear filters - return { - ...state, - filters: {}, - filtered: [], - list: list.map((bp) => ({ ...bp })) - } - }, - updateBPList(state, list) { - return { - ...state, - list - } - }, - addToSelected(state, producerAccountName) { - return { - ...state, - selected: uniq([...state.selected, producerAccountName]) - } - }, - addArrayToSelected(state, producerAccountNames) { - return { - ...state, - selected: uniq([...state.selected, ...producerAccountNames]) - } - }, - removeSelected(state, producerAccountName) { - return { - ...state, - selected: state.selected.filter( - (selected) => selected !== producerAccountName - ) - } - }, - clearSelected(state) { - return { - ...state, - selected: [] - } - }, - clearFilters(state) { - return { - ...state, - filtered: [], - filters: {} - } - }, - setFiltered(state, filtered, filters) { - return { - ...state, - filtered: [...filtered], - filters: { ...filters } - } - }, - setSortBy(state, sort) { - return { - ...state, - sortBy: sort - } - }, - addProducer(state, producer) { - return { ...state, producer } - }, - addUserRate(state, userRate) { - return { ...state, userRate } - }, - addEdenRate(state, edenRate) { - return { ...state, edenRate } - }, - addTransaction(state, transaction) { - return { ...state, transaction } - } - }, - effects: (dispatch) => ({ - async getBPs() { - return getAllBPs({ - setBPs: (state) => this.setBPs(state) - }) - }, - async applyFilter(filters, state) { - this.setFiltered( - filterObjects.filter(filters, state.blockProducers.list), - filters - ) - }, - async saveLastTransaction(transaction) { - this.addTransaction(transaction) - }, - async getBlockProducerByOwner(owner, state) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { - data: { producers } - } = await apolloClient.query({ - variables: { owner }, - query: QUERY_PRODUCER - }) - - if (!producers.length) { - this.addProducer(null) - dispatch.isLoading.storeIsContentLoading(false) - - return - } - - const blockProducer = producers[0] - const bpData = - blockProducer.owner && - (state.blockProducers.list || []).find( - ({ owner }) => owner === blockProducer.owner - ) - - this.addProducer({ - ...blockProducer, - average: bpData ? bpData.average : 0, - ratings_cntr: bpData ? bpData.ratings_cntr : 0, - general_info: bpData ? bpData.general_info : {}, - system: { - ...blockProducer.system, - votesInEos: bpData ? bpData.system.votesInEos : 0, - parameters: bpData ? bpData.system.parameters : {} - }, - data: bpData ? bpData.data : [] - }) - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('getBlockProducerByOwner', error) - dispatch.isLoading.storeIsContentLoading(false) - } - }, - async getBlockProducerRatingByOwner({ bp, userAccount }, state) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { - data: { user_ratings: userRatings } - } = await apolloClient.query({ - variables: { bp, user: userAccount }, - query: QUERY_RATING - }) - - this.addUserRate(userRatings.length ? userRatings[0].ratings : null) - - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('getBlockProducerRatingByOwner', error) - dispatch.isLoading.storeIsContentLoading(false) - } - }, - async getBlockProducerEdenRating({ bp }, state) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { - data: { eden_ratings_stats: edenRatings } - } = await apolloClient.query({ - variables: { bp }, - query: QUERY_EDEN_RATING, - fetchPolicy: 'network-only' - }) - - this.addEdenRate(edenRatings.length > 0 ? edenRatings[0] : null) - - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('getBlockProducerEdenRating', error) - dispatch.isLoading.storeIsContentLoading(false) - } - }, - async mutationInsertUserRating( - { ual, user, bp, result, ...ratings }, - state - ) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { - data: { rateProducer } - } = await apolloClient.mutate({ - variables: { - ratingInput: { - producer: bp, - user, - transaction: state.blockProducers.transaction - } - }, - mutation: MUTATION_UPDATE_RATING - }) - - const rpc = getRpc(ual) - - const { rows: rateStat } = await rpc.get_table_rows({ - json: true, - code: contract, - scope: contract, - table: 'stats', - lower_bound: bp, - limit: 1, - reverse: false, - show_payer: false - }) - - const producerUpdatedList = state.blockProducers.list.map( - (producer) => { - if (rateStat.length && producer.owner === rateStat[0].bp) { - const parameters = { - community: rateStat[0].community, - development: rateStat[0].development, - infrastructure: rateStat[0].infrastructure, - transparency: rateStat[0].transparency, - trustiness: rateStat[0].trustiness - } - const graphData = Object.values(parameters) - - return { - ...producer, - average: rateStat[0].average, - ratings_cntr: rateStat[0].ratings_cntr, - system: { - ...producer.system, - parameters - }, - data: { - ...producer.data, - data: graphData - } - } - } - - return producer - } - ) - const currentBP = producerUpdatedList.find( - (producer) => producer.owner === bp - ) - - this.addProducer(currentBP) - this.addEdenRate(rateProducer.resultEden) - this.updateBPList(producerUpdatedList) - this.getBlockProducerRatingByOwner({ bp, userAccount: user }) - dispatch.user.getUserRates({ - userRate: { ...rateProducer, ...currentBP } - }) - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('mutationInsertUserRating', error) - dispatch.isLoading.storeIsContentLoading(false) - } - } - }) -} - -export default Proxies diff --git a/webapp/src/models/BlockProducer/mutation_insert_user_rating.js b/webapp/src/models/BlockProducer/mutation_insert_user_rating.js deleted file mode 100644 index ae0aab64..00000000 --- a/webapp/src/models/BlockProducer/mutation_insert_user_rating.js +++ /dev/null @@ -1,15 +0,0 @@ -import gql from 'graphql-tag' - -const MUTATION_INSERT_USER_RATING = gql` - mutation saveUserRating($objects: [user_ratings_insert_input!]!) { - insert_user_ratings(objects: $objects) { - returning { - user - bp - ratings - } - } - } -` - -export default MUTATION_INSERT_USER_RATING diff --git a/webapp/src/models/BlockProducer/mutation_update_rate.js b/webapp/src/models/BlockProducer/mutation_update_rate.js deleted file mode 100644 index a48f1d7e..00000000 --- a/webapp/src/models/BlockProducer/mutation_update_rate.js +++ /dev/null @@ -1,16 +0,0 @@ -import gql from 'graphql-tag' - -const MUTATION_UPDATE_RATING = gql` - mutation updateRating($ratingInput: RatingInput!) { - rateProducer(ratingInput: $ratingInput) { - message - resultEden - uniq_rating - user - bp - ratings - } - } -` - -export default MUTATION_UPDATE_RATING diff --git a/webapp/src/models/BlockProducer/mutation_update_user_rating.js b/webapp/src/models/BlockProducer/mutation_update_user_rating.js deleted file mode 100644 index c40d1579..00000000 --- a/webapp/src/models/BlockProducer/mutation_update_user_rating.js +++ /dev/null @@ -1,23 +0,0 @@ -import gql from 'graphql-tag' - -const MUTATION_UPDATE_USER_RATING = gql` - mutation updateUserRating( - $userRating: user_ratings_set_input - $user: String - $bp: String - ) { - update_user_ratings( - _set: $userRating - where: { _and: [{ user: { _eq: $user } }, { bp: { _eq: $bp } }] } - ) { - returning { - user - bp - ratings - uniq_rating - } - } - } -` - -export default MUTATION_UPDATE_USER_RATING diff --git a/webapp/src/models/BlockProducer/query_get_bp_rating_by.js b/webapp/src/models/BlockProducer/query_get_bp_rating_by.js deleted file mode 100644 index c80144d6..00000000 --- a/webapp/src/models/BlockProducer/query_get_bp_rating_by.js +++ /dev/null @@ -1,16 +0,0 @@ -import gql from 'graphql-tag' - -const QUERY_RATING = gql` - query getRating($user: String, $bp: String) { - user_ratings( - where: { _and: [{ user: { _eq: $user } }, { bp: { _eq: $bp } }] } - ) { - user - bp - ratings - tx_data - } - } -` - -export default QUERY_RATING diff --git a/webapp/src/models/BlockProducer/query_get_eden_stats.js b/webapp/src/models/BlockProducer/query_get_eden_stats.js deleted file mode 100644 index 68a0b1c4..00000000 --- a/webapp/src/models/BlockProducer/query_get_eden_stats.js +++ /dev/null @@ -1,18 +0,0 @@ -import gql from 'graphql-tag' - -const QUERY_EDEN_RATING = gql` - query getEdenRating($bp: String) { - eden_ratings_stats(where: { bp: { _eq: $bp } }) { - bp - average - ratings_cntr - infrastructure - transparency - trustiness - development - community - } - } -` - -export default QUERY_EDEN_RATING diff --git a/webapp/src/models/BlockProducer/query_get_producer_by.js b/webapp/src/models/BlockProducer/query_get_producer_by.js deleted file mode 100644 index cfdf0a4a..00000000 --- a/webapp/src/models/BlockProducer/query_get_producer_by.js +++ /dev/null @@ -1,13 +0,0 @@ -import gql from 'graphql-tag' - -const QUERY_PRODUCER = gql` - query getProducer($owner: String) { - producers(where: { owner: { _eq: $owner } }) { - bpjson - owner - system - } - } -` - -export default QUERY_PRODUCER diff --git a/webapp/src/models/Proxy/proxy.js b/webapp/src/models/Proxy/proxy.js deleted file mode 100644 index 063b03eb..00000000 --- a/webapp/src/models/Proxy/proxy.js +++ /dev/null @@ -1,207 +0,0 @@ -import _get from 'lodash.get' -import filterObjects from 'filter-objects' - -import calculateEosFromVotes from 'utils/convertVotesToEosVotes' -import getBPRadarData from 'utils/getBPRadarData' -import apolloClient from 'services/graphql' - -import QUERY_GET_PROXIES from './query_get_proxies' -import QUERY_GET_PROXY_BY_OWNER from './query_get_proxy_by_owner' - -const initialState = { - proxies: [], - compareTool: false, - proxy: null, - filters: {}, - filtered: [], - selected: [] -} - -const Proxies = { - state: initialState, - reducers: { - toggleCompareTool(state) { - return { - ...state, - compareTool: !state.compareTool - } - }, - addProxies(state, proxies) { - return { - ...state, - proxies, - filters: {}, - filtered: [] - } - }, - addProxy(state, proxy) { - return { ...state, proxy } - }, - addToSelected(state, owner) { - return { - ...state, - selected: [owner] - } - }, - removeSelected(state) { - return { - ...state, - selected: [] - } - }, - clearFilters(state) { - return { - ...state, - filtered: [], - filters: {} - } - }, - setFiltered(state, filtered, filters) { - return { - ...state, - filtered: [...filtered], - filters: { ...filters } - } - } - }, - effects: (dispatch) => ({ - async applyFilter(filters, state) { - this.setFiltered( - filterObjects.filter(filters, state.proxies.proxies), - filters - ) - }, - async getProxies(payload, { blockProducers: { list } }) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { - data: { proxies } - } = await apolloClient.query({ - variables: {}, - query: QUERY_GET_PROXIES - }) - - if (!proxies.length) { - this.addProxies(null) - dispatch.isLoading.storeIsContentLoading(false) - - return - } - const proxiesModeled = proxies.map((proxy) => { - const rateInfo = [] - const proxyProducers = _get(proxy, 'voter_info.producers', []) - const proxiedVoteEOS = calculateEosFromVotes( - _get(proxy, 'voter_info.last_vote_weight', 0) - ) - const totalVoteEOS = calculateEosFromVotes( - _get(proxy, 'voter_info.proxied_vote_weight', 0) - ) - const producersDataModeled = proxyProducers.map((owner) => { - const producer = list.find((bp) => bp.owner === owner) - - if (producer) { - const { - system: { parameters } - } = producer - - rateInfo.push(parameters) - - return producer - } - - return { owner } - }) - - const averageParams = rateInfo.reduce( - (acc, current, index) => { - const community = acc.community + current.community - const development = acc.development + current.development - const infrastructure = acc.infrastructure + current.infrastructure - const transparency = acc.transparency + current.transparency - const trustiness = acc.trustiness + current.trustiness - - if (index + 1 === rateInfo.length) { - return { - community: community / rateInfo.length, - development: development / rateInfo.length, - infrastructure: infrastructure / rateInfo.length, - transparency: transparency / rateInfo.length, - trustiness: trustiness / rateInfo.length - } - } - - return { - community, - development, - infrastructure, - transparency, - trustiness - } - }, - { - community: 0, - development: 0, - infrastructure: 0, - transparency: 0, - trustiness: 0 - } - ) - - return { - ...proxy, - voter_info: { - ...proxy.voter_info, - producers: producersDataModeled - }, - averageParams, - data: getBPRadarData({ - name: proxy.owner, - parameters: averageParams - }), - proxiedVoteEOS, - totalVoteEOS - } - }) - - this.addProxies(proxiesModeled) - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('getProxies', error) - dispatch.isLoading.storeIsContentLoading(false) - } - }, - async getProxyByOwner(payload, state) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { - data: { proxies } - } = await apolloClient.query({ - variables: { owner: payload }, - query: QUERY_GET_PROXY_BY_OWNER - }) - - if (!proxies.length) { - this.addProxy(null) - dispatch.isLoading.storeIsContentLoading(false) - - return - } - - const proxy = proxies[0] - const proxyModeled = state.proxies.proxies.find( - ({ owner }) => owner === proxy.owner - ) - - this.addProxy({ ...proxy, ...proxyModeled }) - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('getProxy', error) - dispatch.isLoading.storeIsContentLoading(false) - } - } - }) -} - -export default Proxies diff --git a/webapp/src/models/Proxy/query_get_proxies.js b/webapp/src/models/Proxy/query_get_proxies.js deleted file mode 100644 index 2d374bf5..00000000 --- a/webapp/src/models/Proxy/query_get_proxies.js +++ /dev/null @@ -1,22 +0,0 @@ -import gql from 'graphql-tag' - -const QUERY_GET_PROXIES = gql` - query getProxies { - proxies { - background - logo_256 - name - owner - philosophy - slogan - steemit - telegram - twitter - voter_info - website - wechat - } - } -` - -export default QUERY_GET_PROXIES diff --git a/webapp/src/models/Proxy/query_get_proxy_by_owner.js b/webapp/src/models/Proxy/query_get_proxy_by_owner.js deleted file mode 100644 index 0fdca974..00000000 --- a/webapp/src/models/Proxy/query_get_proxy_by_owner.js +++ /dev/null @@ -1,22 +0,0 @@ -import gql from 'graphql-tag' - -const QUERY_GET_PROXY_BY_OWNER = gql` - query getProxiesByOwner($owner: String!) { - proxies(where: { owner: { _eq: $owner } }) { - background - logo_256 - name - owner - philosophy - slogan - steemit - telegram - twitter - voter_info - website - wechat - } - } -` - -export default QUERY_GET_PROXY_BY_OWNER diff --git a/webapp/src/models/User/mutation_delete_user_rate.js b/webapp/src/models/User/mutation_delete_user_rate.js deleted file mode 100644 index 4e835cd7..00000000 --- a/webapp/src/models/User/mutation_delete_user_rate.js +++ /dev/null @@ -1,13 +0,0 @@ -import gql from 'graphql-tag' - -const MUTATION_DELETE_USER_RATE = gql` - mutation deleteUserRate($user: String!, $bpName: String!) { - delete_user_ratings( - where: { _and: [{ user: { _eq: $user } }, { bp: { _eq: $bpName } }] } - ) { - affected_rows - } - } -` - -export default MUTATION_DELETE_USER_RATE diff --git a/webapp/src/models/User/query_get_rates.js b/webapp/src/models/User/query_get_rates.js deleted file mode 100644 index 0e031ce7..00000000 --- a/webapp/src/models/User/query_get_rates.js +++ /dev/null @@ -1,15 +0,0 @@ -import gql from 'graphql-tag' - -const QUERY_RATING = gql` - query getRates($user: String) { - user_ratings(where: { user: { _eq: $user } }, order_by: { tx_data: asc }) { - bp - ratings - uniq_rating - user - tx_data - } - } -` - -export default QUERY_RATING diff --git a/webapp/src/models/User/user.js b/webapp/src/models/User/user.js deleted file mode 100644 index 7e3f348c..00000000 --- a/webapp/src/models/User/user.js +++ /dev/null @@ -1,167 +0,0 @@ -import _get from 'lodash.get' - -import apolloClient from 'services/graphql' -import { getRpc, getAccountName } from 'utils/eosjsUtils' - -import { contractEden } from '../../config' -import QUERY_GET_RATES from './query_get_rates' -import MUTATION_DELETE_USER_RATE from './mutation_delete_user_rate' - -const initialState = { - data: null -} - -const user = { - state: initialState, - - reducers: { - setUser(state, data) { - return { - ...state, - data - } - } - }, - - effects: (dispatch) => ({ - async getUserChainData({ ual }, { user, blockProducers, isLoading }) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const accountName = await getAccountName(ual) - - if (user.data && user.data.account_name === accountName) { - dispatch.isLoading.storeIsContentLoading(false) - return - } - - let account = null - let userRates = [] - let edenMember = false - const rpc = getRpc(ual) - - if (accountName.length) { - account = await rpc.get_account(accountName) - - const { rows: edenMembers } = await rpc.get_table_rows({ - json: true, - code: contractEden, - scope: 0, - table: 'member', - lower_bound: accountName, - limit: 1, - reverse: false, - show_payer: false - }) - - if (edenMembers[0][1].account === accountName) { - edenMember = true - } - } - - const { - data: { user_ratings: userRatings } - } = await apolloClient.query({ - variables: { user: accountName }, - query: QUERY_GET_RATES - }) - - const producers = _get(account, 'voter_info.producers', []) - const proxy = _get(account, 'voter_info.proxy', '') - userRates = userRatings - - if (userRatings.length) { - userRates = userRatings.map((bpRated) => { - const item = blockProducers.list.find( - ({ owner }) => bpRated.bp === owner - ) - - return { ...item, ...bpRated } - }) - } - - account - ? this.setUser({ - ...account, - hasProxy: Boolean(proxy.length), - producersCount: producers.length, - userRates, - edenMember - }) - : this.setUser(null) - - if (producers.length) { - const filterBPs = producers.filter((bpName) => - blockProducers.list.find(({ owner }) => bpName === owner) - ) - - dispatch.blockProducers.addArrayToSelected(filterBPs) - } - proxy.length && dispatch.proxies.addToSelected(proxy) - - if ((producers.length || proxy.length) && !blockProducers.compareTool) { - dispatch.blockProducers.toggleCompareTool() - } - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('getUserChainData', error) - dispatch.isLoading.storeIsContentLoading(false) - this.setUser(null) - } - }, - async removeBlockProducersVotedByUser() { - this.setUser(null) - dispatch.blockProducers.clearSelected() - }, - async deleteUserRate({ user, bpName }, state) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { - data: { - delete_user_ratings: { affected_rows: affectedRows } - } - } = await apolloClient.mutate({ - variables: { user, bpName }, - mutation: MUTATION_DELETE_USER_RATE - }) - - if (affectedRows) { - const { - data: { userRates } - } = state.user - const rates = userRates.filter(({ owner }) => owner !== bpName) - - this.setUser({ ...state.user.data, userRates: rates }) - } - - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('deleteUserRate', error) - dispatch.isLoading.storeIsContentLoading(false) - } - }, - async getUserRates({ userRate }, { user }) { - try { - dispatch.isLoading.storeIsContentLoading(true) - - const { message, ...bpRate } = userRate - const userRatesFiltered = user.data.userRates.filter( - ({ owner }) => owner !== bpRate.bp - ) - - this.setUser({ - ...user.data, - userRates: [...userRatesFiltered, bpRate] - }) - dispatch.isLoading.storeIsContentLoading(false) - } catch (error) { - console.error('getUserRates', error) - dispatch.isLoading.storeIsContentLoading(false) - this.setUser(null) - } - } - }) -} - -export default user diff --git a/webapp/src/models/home.js b/webapp/src/models/home.js deleted file mode 100644 index 6aa6d7d6..00000000 --- a/webapp/src/models/home.js +++ /dev/null @@ -1,35 +0,0 @@ -import { findBPById } from 'services/bps' -import getBPRadarData from 'utils/getBPRadarData' - -const initialState = { - isPlaying: false, - blockProducer: null -} - -const home = { - state: initialState, - - reducers: { - setBP(state, blockProducer) { - return { - ...state, - blockProducer - } - } - }, - - effects: { - async getBlockData() { - const blockProducer = await findBPById(0) - this.setBP({ - ...blockProducer, - data: getBPRadarData({ - name: blockProducer.org.candidate_name, - parameters: blockProducer.parameters - }) - }) - } - } -} - -export default home diff --git a/webapp/src/models/index.js b/webapp/src/models/index.js deleted file mode 100644 index 83516b31..00000000 --- a/webapp/src/models/index.js +++ /dev/null @@ -1,7 +0,0 @@ -export { default as settings } from './settings' -export { default as location } from './location' -export { default as blockProducers } from './BlockProducer/blockProducers' -export { default as proxies } from './Proxy/proxy' -export { default as home } from './home' -export { default as user } from './User/user' -export { default as isLoading } from './isLoading' diff --git a/webapp/src/models/isLoading.js b/webapp/src/models/isLoading.js deleted file mode 100644 index 1bc20bfa..00000000 --- a/webapp/src/models/isLoading.js +++ /dev/null @@ -1,14 +0,0 @@ -export default { - state: { - isContentLoading: false - }, - - reducers: { - storeIsContentLoading(state, isLoading) { - return { - ...state, - isContentLoading: isLoading - } - } - } -} diff --git a/webapp/src/models/location.js b/webapp/src/models/location.js deleted file mode 100644 index 17c295e2..00000000 --- a/webapp/src/models/location.js +++ /dev/null @@ -1,36 +0,0 @@ -const initialState = { - pathname: window.location.pathname, - data: {} -} - -const location = { - state: initialState, - - reducers: { - setLocation(state, pathname, data = {}) { - return { - ...state, - pathname, - data - } - } - } -} - -export const locationChangeListener = ({ dispatch, getState }) => { - let { - location: { pathname: currentPathname } - } = window - - window.setInterval(() => { - const { - location: { pathname } - } = window - if (currentPathname !== pathname) { - currentPathname = pathname - dispatch.location.setLocation(pathname) - } - }, 400) -} - -export default location diff --git a/webapp/src/models/settings.js b/webapp/src/models/settings.js deleted file mode 100644 index bc6153c0..00000000 --- a/webapp/src/models/settings.js +++ /dev/null @@ -1,19 +0,0 @@ -// Initial state -const initialState = { - language: 'en', - notifications: true -} - -const settings = { - state: initialState, - reducers: { - setSettings(state, { key, value }) { - return { - ...state, - [key]: value - } - } - } -} - -export default settings diff --git a/webapp/src/routes/about/index.js b/webapp/src/routes/About/index.js similarity index 75% rename from webapp/src/routes/about/index.js rename to webapp/src/routes/About/index.js index 3353c5ac..95fe3d2f 100644 --- a/webapp/src/routes/about/index.js +++ b/webapp/src/routes/About/index.js @@ -1,12 +1,10 @@ -import React from 'react' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/styles' +import React, { memo } from 'react' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' import { useTranslation } from 'react-i18next' -import Grid from '@material-ui/core/Grid' -import Box from '@material-ui/core/Box' -import classNames from 'classnames' +import Box from '@mui/material/Box' -import TitlePage from 'components/title-page' +import TitlePage from '../../components/PageTitle' import styles from './styles' @@ -19,16 +17,9 @@ const About = () => { return ( - - - + + + {t('title')} {t('subtitle1')} @@ -40,18 +31,11 @@ const About = () => { {t('body1.paragraph3')} - - + + - - + + {t('subtitle2')} {t('body2.paragraph1')} @@ -62,18 +46,11 @@ const About = () => { {t('body2.paragraph3')} - - + + - - + + {t('subtitle3')} {t('body3.paragraph1')} @@ -126,11 +103,11 @@ const About = () => { src='/EOS-Rate-Infographic.jpg' alt='EOS block producer ratings' /> - - - + + + ) } -export default About +export default memo(About) diff --git a/webapp/src/routes/about/styles.js b/webapp/src/routes/About/styles.js similarity index 71% rename from webapp/src/routes/about/styles.js rename to webapp/src/routes/About/styles.js index c14f01d5..d04373d9 100644 --- a/webapp/src/routes/about/styles.js +++ b/webapp/src/routes/About/styles.js @@ -1,7 +1,9 @@ -export default (theme) => ({ +export default theme => ({ wrapperContainers: { color: '#433F5B', padding: theme.spacing(6, 2), + maxWidth: 1024, + width: '100%', '& h6': { marginBottom: theme.spacing(1) }, @@ -10,6 +12,8 @@ export default (theme) => ({ } }, firstContainer: { + display: 'flex', + justifyContent: 'center', backgroundColor: theme.palette.surface.main, '& h5': { fontSize: theme.typography.h4.fontSize, @@ -17,12 +21,16 @@ export default (theme) => ({ } }, middleContainer: { + display: 'flex', + justifyContent: 'center', backgroundColor: theme.palette.surface.main, '& img': { width: '100%' } }, lastContainer: { + display: 'flex', + justifyContent: 'center', backgroundColor: '#f5f5f5' } }) diff --git a/webapp/src/routes/Account/index.js b/webapp/src/routes/Account/index.js new file mode 100644 index 00000000..7ad180dd --- /dev/null +++ b/webapp/src/routes/Account/index.js @@ -0,0 +1,284 @@ +import React, { useState, forwardRef } from 'react' +import { useTranslation } from 'react-i18next' +import { useMutation } from '@apollo/client' +import clsx from 'clsx' +import Button from '@mui/material/Button' +import Paper from '@mui/material/Paper' +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' +import Avatar from '@mui/material/Avatar' +import MuiAlert from '@mui/material//Alert' +import IconButton from '@mui/material/IconButton' +import CloseIcon from '@mui/icons-material/Close' +import Accordion from '@mui/material/Accordion' +import AccordionSummary from '@mui/material/AccordionSummary' +import AccordionDetails from '@mui/material/AccordionDetails' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import Snackbar from '@mui/material/Snackbar' +import Link from '@mui/material/Link' +import _get from 'lodash.get' + +import { DELETE_USER_RATE } from '../../gql' +import { mainConfig } from '../../config' +import TitlePage from '../../components/PageTitle' +import { useSharedState } from '../../context/state.context' +import formatNumber from '../../utils/format-number' + +import styles from './styles' + +const useStyles = makeStyles(styles) +const VOTE_INDICATORS = [ + 'community', + 'development', + 'infrastructure', + 'transparency', + 'trustiness' +] + +const INIT_RATING_STATE_DATA = { + processing: false, + txError: null, + txSuccess: false +} + +const Alert = forwardRef(function Alert(props, ref) { + return +}) + +const Account = () => { + const { t } = useTranslation('account') + const classes = useStyles() + const [deleteUserRate] = useMutation(DELETE_USER_RATE) + const [state, { logout, setUser }] = useSharedState() + const [ratingState, setRatingState] = useState(INIT_RATING_STATE_DATA) + const [showMessage, setShowMessage] = useState(false) + + const onHandleDeleteUserRate = async bpName => { + try { + if (!state.user) { + setShowMessage(true) + + return + } + + const transaction = { + actions: [ + { + account: mainConfig.contract, + name: 'rmrate', + authorization: [ + { + actor: state.user.accountName, + permission: 'active' + } + ], + data: { user: state.user.accountName, bp: bpName } + } + ] + } + + await state.ual.activeUser.signTransaction(transaction, { + broadcast: true + }) + + await deleteUserRate({ + variables: { + user: state.user.accountName, + bpName + } + }) + + await setUser() + + setRatingState({ + ...ratingState, + txError: null, + processing: true, + txSuccess: true + }) + } catch (error) { + setRatingState({ + ...ratingState, + processing: false, + txError: error.cause ? error.cause.message : error + }) + } + } + + const handleClose = (e, reason) => { + if (reason === 'clickaway') { + return + } + + setShowMessage(false) + setRatingState({ + ...ratingState, + processing: false, + txError: null, + txSuccess: false + }) + } + + return ( + + + + + {t('title')} + + + + + {state.user + ? `${state.user.accountName}: ${ + state.user?.userData?.core_liquid_balance || 0 + }` + : 'accountName: 0'} + + + {(state.user ? state.user?.userData?.userRates || [] : []).map( + rate => { + const imageURL = _get( + rate, + 'bpjson.org.branding.logo_256', + null + ) + const BPName = _get( + rate, + 'bpjson.org.candidate_name', + rate.bp + ) + const date = _get( + rate, + 'tx_data.transaction.transactionDate', + '' + ).substring(0, 10) + + return ( + + } + aria-controls='panel1a-content' + id='panel1a-header' + > + + + {!imageURL ? ( + 'BP' + ) : ( + + )} + + + {date.length > 1 + ? `${t('youRated')} ${BPName} - ${date}` + : `${t('youRated')} ${BPName}`} + + + + + + {t('yourRating')} + + {VOTE_INDICATORS.map(value => ( + + {t(value)}: + + {formatNumber(rate.ratings[value], 0)} + + + ))} + + {rate.tx_data && ( + + {rate.tx_data.transaction.transactionId} + + )} + + + + onHandleDeleteUserRate(rate.bp)} + > + + {t('unpublish')} + + + + + + ) + } + )} + + + + + {t('voteWithoutLogin')} + + + + + {ratingState.txError} + + + + + {t('success')} + + + + + + + ) +} + +export default Account diff --git a/webapp/src/routes/Account/styles.js b/webapp/src/routes/Account/styles.js new file mode 100644 index 00000000..c54604a2 --- /dev/null +++ b/webapp/src/routes/Account/styles.js @@ -0,0 +1,101 @@ +export default theme => ({ + container: { + padding: theme.spacing(3, 2), + color: theme.palette.common.white + }, + account: { + padding: theme.spacing(2) + }, + title: { + marginBottom: '12.5px !important', + fontWeight: 'normal', + fontStretch: 'normal', + fontStyle: 'normal', + lineHeight: '1.17', + letterSpacing: 'normal', + textAlign: 'left', + color: theme.palette.primary.dark, + [theme.breakpoints.down('sm')]: { + fontSize: '2.03rem !important', + marginBottom: 0 + } + }, + box: { + height: 'calc(100% - 55px)', + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between' + }, + bold: { + marginBottom: `${theme.spacing(1)} !important`, + fontWeight: 'bold', + fontStretch: 'normal', + fontStyle: 'normal', + lineHeight: '23px !important', + letterSpacing: '0.15px !important', + textAlign: 'left', + color: theme.palette.primary.dark, + fontSize: '18px !important' + }, + button: { + marginTop: `${theme.spacing(3)} !important` + }, + rateList: { + marginTop: theme.spacing(3), + '& hr': { + width: '100%' + } + }, + avatar: { + backgroundColor: theme.palette.surface.main + }, + link: { + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + display: 'block', + width: '100%', + color: '#1a73e8' + }, + accordionTitle: { + marginLeft: `${theme.spacing(1)} !important` + }, + row: { + display: 'flex', + justifyContent: 'space-between', + marginBottom: theme.spacing(1), + width: '80%' + }, + remove: { + display: 'flex', + justifyContent: 'flex-end', + '& svg': { + fontSize: 16, + color: '#CD4729' + }, + '& p': { + fontStyle: 'normal', + fontWeight: '500', + fontSize: '14px', + lineHeight: '16px', + display: 'flex', + alignItems: 'center', + textAlign: 'center', + letterSpacing: '1px', + textTransform: 'uppercase', + color: '#CD4729' + } + }, + yourRate: { + fontStyle: 'normal', + fontWeight: '500 !important', + lineHeight: '24px', + color: theme.palette.common.black, + marginBottom: `${theme.spacing(1)} !important` + }, + boxWrapper: { + alignItems: 'center', + display: 'flex' + }, + alert: { width: '100%' } +}) diff --git a/webapp/src/routes/BlockProducers/BlockProducerProfile.js b/webapp/src/routes/BlockProducers/BlockProducerProfile.js new file mode 100644 index 00000000..739fc1b1 --- /dev/null +++ b/webapp/src/routes/BlockProducers/BlockProducerProfile.js @@ -0,0 +1,375 @@ +import React, { useState, useEffect, forwardRef, Fragment } from 'react' +import PropTypes from 'prop-types' +import { useTranslation } from 'react-i18next' +import { Link, useParams } from 'react-router-dom' +import Avatar from '@mui/material/Avatar' +import Button from '@mui/material/Button' +import Grid from '@mui/material/Grid' +import Snackbar from '@mui/material/Snackbar' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' +import MuiAlert from '@mui/material/Alert' +import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft' +import AccountCircle from '@mui/icons-material/AccountCircle' +import CloseIcon from '@mui/icons-material/Close' +import _get from 'lodash.get' +import Box from '@mui/material/Box' +import useMediaQuery from '@mui/material/useMediaQuery' +import IconButton from '@mui/material/IconButton' +import { Link as MLink } from '@mui/material' + +import { mainConfig } from '../../config' +import getBPRadarData from '../../utils/get-bp-radar-data' +import TitlePage from '../../components/PageTitle' +import PolarChart from '../../components/PolarChart' +import Table from '../../components/Table' +import getAverageValue from '../../utils/get-average-value' +import { useSharedState } from '../../context/state.context' + +import { + SocialNetworks, + GeneralInformation, + WebsiteLegend, + AdditionalResources +} from './GeneralInformationProfile' +import formatNumber from '../../utils/format-number' +import styles from './styles' + +const useStyles = makeStyles(styles) + +const Alert = forwardRef(function Alert(props, ref) { + return +}) + +const ProfileTitle = ({ + classes, + hasInformation, + producer, + t, + bpTitle, + isContentLoading +}) => { + if (!isContentLoading && !producer) { + return ( + + {t('noBlockProducer')} + + ) + } + + return ( + <> + + {bpTitle} + + {!hasInformation && ( + + {t('noBpJson')} + + )} + + ) +} + +const BlockProducerProfile = () => { + const { t } = useTranslation('profile') + const { account } = useParams() + const classes = useStyles() + const [state, { setProducer, setLastTransaction }] = useSharedState() + const isMobile = useMediaQuery('(max-width:768px)') + const [isRated, setIsRated] = useState(false) + const [bpHasInformation, setBpHasInformation] = useState(false) + const [blockProducerLogo, setBlockProducerLogo] = useState(null) + const [webInfo, setWebInfo] = useState(null) + const [polarChartData, setPolarChartData] = useState([]) + const [blockProducerTitle, setBlockProducerTitle] = useState('No Title') + const [open, setOpen] = useState(false) + + const getRatingData = edenRate => ({ + community: parseFloat(formatNumber(edenRate?.community || 0, 1)), + development: parseFloat(formatNumber(edenRate?.development || 0, 1)), + infrastructure: parseFloat(formatNumber(edenRate?.development || 0, 1)), + transparency: parseFloat(formatNumber(edenRate?.transparency || 0, 1)), + trustiness: parseFloat(formatNumber(edenRate?.trustiness || 0, 1)) + }) + + const setProfileData = bp => { + const userDataSet = getBPRadarData({ + name: t('edenRates'), + parameters: getRatingData(bp.edenRate) + }) + + setBpHasInformation(!!Object.values(bp.bpjson).length) + setBlockProducerLogo(_get(bp, 'bpjson.org.branding.logo_256', null)) + setBlockProducerTitle( + _get(bp, 'bpjson.org.candidate_name', _get(bp, 'system.owner', 'No Data')) + ) + setWebInfo(_get(bp, 'general_info', null)) + + if (bp.totalStats) { + const totalStatsDataSet = getBPRadarData({ + name: t('totalRates'), + parameters: getRatingData(bp?.totalStats) + }) + + setPolarChartData([ + { ...bp.data, name: t('eosRates') }, + userDataSet, + totalStatsDataSet + ]) + } + } + + const handleClose = (e, reason) => { + if (reason === 'clickaway') { + return + } + setOpen(false) + setLastTransaction(null) + } + + useEffect(() => { + const getBpData = async () => { + if (state.blockProducers.data.length) { + // TODO: do a double check if this is necessary + const bp = state.blockProducers.data.find( + ({ owner }) => owner === account + ) + setProducer(bp, true) + setProfileData(bp) + + return + } + + await setProducer(account) + } + + if (state.blockProducers) getBpData() + }, [account]) + + useEffect(() => { + if (!state.blockProducer) { + return + } + + setProfileData(state.blockProducer) + }, [state.blockProducer]) + + useEffect(() => { + if (state.user && state.blockProducer) { + setIsRated( + state.user?.userData?.userRates.some( + rate => rate.owner === state.blockProducer.owner + ) + ) + } + }, [state.user, state.blockProducer]) + + useEffect(() => { + setOpen(!!state.transaction) + }, []) + + return ( + + + + + + + + + + + {blockProducerLogo ? ( + + + + ) : ( + + )} + + + + {!isMobile && ( + + + + + + + + + )} + + + + + + + + +
+ + + {isMobile && ( + <> + + + + + + + + + + )} + + + + + + + + + + } + /> + + ) +} + +ProfileTitle.propTypes = { + classes: PropTypes.object, + hasInformation: PropTypes.bool, + producer: PropTypes.object, + t: PropTypes.any, + bpTitle: PropTypes.string, + isContentLoading: PropTypes.bool +} + +export default BlockProducerProfile diff --git a/webapp/src/routes/BlockProducers/BlockProducerRate.js b/webapp/src/routes/BlockProducers/BlockProducerRate.js new file mode 100644 index 00000000..81fc00c8 --- /dev/null +++ b/webapp/src/routes/BlockProducers/BlockProducerRate.js @@ -0,0 +1,528 @@ +/* eslint-disable react/display-name */ +import React, { useState, useEffect, forwardRef } from 'react' +import { useTranslation } from 'react-i18next' +import { Link, useParams, useHistory } from 'react-router-dom' +import Avatar from '@mui/material/Avatar' +import Button from '@mui/material/Button' +import Grid from '@mui/material/Grid' +import PropTypes from 'prop-types' +import CircularProgress from '@mui/material/CircularProgress' +import Typography from '@mui/material/Typography' +import AccountCircle from '@mui/icons-material/AccountCircle' +import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft' +import _get from 'lodash.get' +import clsx from 'clsx' +import Snackbar from '@mui/material/Snackbar' +import MuiAlert from '@mui/material/Alert' +import { makeStyles } from '@mui/styles' +import Box from '@mui/material/Box' + +import Table from '../../components/Table' +import TitlePage from '../../components/PageTitle' +import PolarChart from '../../components/PolarChart' +import getBPRadarData from '../../utils/get-bp-radar-data' +import { useSharedState } from '../../context/state.context' +import formatNumber from '../../utils/format-number' +import { mainConfig } from '../../config' + +import SliderRatingSection from './SliderRatingSection' +import getAverageValue from '../../utils/get-average-value' +import styles from './styles' + +const useStyles = makeStyles(styles) + +const INIT_RATING_STATE_DATA = { + community: 1, + communityEnabled: true, + development: 1, + developmentEnabled: true, + infrastructure: 1, + infraEnabled: true, + transparency: 1, + transparencyEnabled: true, + trustiness: 1, + trustinessEnabled: true, + processing: false, + txError: null, + txSuccess: false +} + +const Alert = forwardRef(function Alert(props, ref) { + return +}) + +const RadarSection = ({ t, state, polarChartData, classes }) => { + return ( + <> + + + + +
+ + + ) +} + +RadarSection.propTypes = { + t: PropTypes.object, + state: PropTypes.object, + polarChartData: PropTypes.object, + classes: PropTypes.object +} + +const BlockProducerRate = () => { + const classes = useStyles() + const { account } = useParams() + const history = useHistory() + const { t } = useTranslation('bpRatePage') + const [ + state, + { setProducer, setLastTransaction, handleMutationInsertUserRating } + ] = useSharedState() + const [ratingState, setRatingState] = useState(INIT_RATING_STATE_DATA) + const [isRated, setIsRated] = useState(true) + const [blockProducerLogo, setBlockProducerLogo] = useState(null) + const [blockProducerTitle, setBlockProducerTitle] = useState('No Title') + const [polarChartData, setPolarChartData] = useState([]) + const [showMessage, setShowMessage] = useState(false) + const [showAlert, setShowAlert] = useState(false) + + const handleStateChange = parameter => (event, value) => { + setRatingState({ ...ratingState, [parameter]: value }) + } + + const handleClose = (event, reason) => { + if (reason === 'clickaway') { + return + } + + setShowMessage(false) + setRatingState({ + ...ratingState, + processing: false, + txError: null, + txSuccess: false + }) + } + + const handleSetLastTransactionId = (event, reason) => { + history.push({ + pathname: `/block-producers/${account}` + }) + } + + const getRatingData = (useString = false) => { + const { + community, + communityEnabled, + development, + developmentEnabled, + infrastructure, + infraEnabled, + transparency, + transparencyEnabled, + trustiness, + trustinessEnabled + } = ratingState + + if (useString) { + return { + community: formatNumber(communityEnabled ? community : 0, 0).toString(), + development: formatNumber( + developmentEnabled ? development : 0, + 0 + ).toString(), + infrastructure: formatNumber( + infraEnabled ? infrastructure : 0, + 0 + ).toString(), + transparency: formatNumber( + transparencyEnabled ? transparency : 0, + 0 + ).toString(), + trustiness: formatNumber( + trustinessEnabled ? trustiness : 0, + 0 + ).toString() + } + } + + return { + community: communityEnabled ? community : 0, + development: developmentEnabled ? development : 0, + infrastructure: infraEnabled ? infrastructure : 0, + transparency: transparencyEnabled ? transparency : 0, + trustiness: trustinessEnabled ? trustiness : 0 + } + } + + const getSavedRatingData = rate => ({ + community: parseFloat(formatNumber(rate?.community || 0, 1)), + development: parseFloat(formatNumber(rate?.development || 0, 1)), + infrastructure: parseFloat(formatNumber(rate?.infrastructure || 0, 1)), + transparency: parseFloat(formatNumber(rate?.transparency || 0, 1)), + trustiness: parseFloat(formatNumber(rate?.trustiness || 0, 1)) + }) + + const transact = async () => { + try { + if (!state.user.accountName) { + setShowMessage(true) + + return + } + + const transaction = { + actions: [ + { + authorization: [ + { + actor: state.user.accountName, + permission: 'active' + } + ], + account: mainConfig.contract, + name: 'rate', + data: { + user: state.user.accountName, + bp: account, + ...getRatingData(true) + } + } + ] + } + + setRatingState({ + ...ratingState, + txError: null, + processing: true, + txSuccess: false + }) + + const result = await state.ual.activeUser.signTransaction(transaction, { + broadcast: true + }) + + await setLastTransaction({ + transactionId: result.transaction.transaction_id, + transactionDate: result.transaction.processed.block_time + }) + + await handleMutationInsertUserRating({ + ual: state.ual, + user: state.user.accountName, + bp: account, + ...getRatingData(false), + result + }) + + setRatingState({ + ...ratingState, + processing: false, + txSuccess: true + }) + + handleSetLastTransactionId() + } catch (err) { + setRatingState({ + ...ratingState, + processing: false, + txError: err.cause ? err.cause.message : err + }) + } + } + + const toNumbers = arr => arr.map(Number) + + const setProfileData = (bp, userDataSet) => { + if (bp) { + const edenDataSet = getBPRadarData({ + name: t('edenRates'), + parameters: getSavedRatingData(bp.edenRate) + }) + + setBlockProducerTitle( + `${t('title')} ${ + _get(bp, 'bpjson.org.candidate_name') || + _get(bp, 'system.owner', t('noBlockProducer')) + } - EOS Rate` + ) + setBlockProducerLogo(_get(bp, 'bpjson.org.branding.logo_256', null)) + const generalRateData = toNumbers(bp.data.data) + + if (bp.totalStats) { + const totalStatsDataSet = getBPRadarData({ + name: t('totalRates'), + parameters: getSavedRatingData(bp?.totalStats) + }) + setPolarChartData([ + { ...bp.data, name: t('globalRate'), data: generalRateData }, + edenDataSet, + userDataSet, + totalStatsDataSet + ]) + } + } + } + + useEffect(() => { + const getBpData = async () => { + if (state.blockProducers.data.length) { + // TODO: do a double check if this is necessary + const bp = state.blockProducers.data.find( + ({ owner }) => owner === account + ) + setProducer(bp, true) + setProfileData(bp, {}) + + return + } + + await setProducer(account) + } + + getBpData() + }, [account]) + + useEffect(() => { + if (state.user && state.blockProducer) { + const bpRated = (state.user?.userData?.userRates || []).find( + rate => rate.owner === state.blockProducer.owner + ) + + if (bpRated) { + setRatingState({ + ...ratingState, + ...getSavedRatingData(bpRated.ratings) + }) + if ( + state.user.userData.edenMember || + state.user.userData.hasProxy || + state.user.userData.producersCount >= 21 + ) { + setShowAlert(false) + } else { + setShowAlert(true) + } + } else { + setRatingState(INIT_RATING_STATE_DATA) + } + setIsRated(!!bpRated) + } + }, [state.user, state.blockProducer]) + + useEffect(() => { + const userDataSet = getBPRadarData({ + name: t('myRate'), + parameters: getRatingData() + }) + setProfileData(state.blockProducer, userDataSet) + }, [ratingState]) + + return ( + + + + + + + + + + + + {blockProducerLogo ? ( + + + + ) : ( + + )} + + {_get(state.blockProducer, 'bpjson.org.candidate_name') || + _get(state.blockProducer, 'system.owner', t('noBlockProducer'))} + + + + + + + {t('subTitle')} + + + {' '} + {t('helpText')}{' '} + + + + + + + + + + + {t('rateWithoutLogin')} + + + + + {ratingState.txError} + + + {ratingState.processing && ( + + )} + + + + + + + + + + + + + + + + + + {showAlert && ( + + + {t('infoMessage')} + + + )} + + + ) +} + +export default BlockProducerRate diff --git a/webapp/src/routes/BlockProducers/BottomSheetSelectedBps.js b/webapp/src/routes/BlockProducers/BottomSheetSelectedBps.js new file mode 100644 index 00000000..fb78ac4c --- /dev/null +++ b/webapp/src/routes/BlockProducers/BottomSheetSelectedBps.js @@ -0,0 +1,32 @@ +import React from 'react' +import PropTypes from 'prop-types' +import Drawer from '@mui/material/Drawer' +import { makeStyles } from '@mui/styles' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const SelectedBpsBottomSheet = ({ open, children, classesStyle }) => { + const classes = useStyles() + + return ( + + {children} + + ) +} + +SelectedBpsBottomSheet.propTypes = { + open: PropTypes.bool, + classesStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), + children: PropTypes.node +} + +export default SelectedBpsBottomSheet diff --git a/webapp/src/routes/block-producers/general-information-profile.js b/webapp/src/routes/BlockProducers/GeneralInformationProfile.js similarity index 88% rename from webapp/src/routes/block-producers/general-information-profile.js rename to webapp/src/routes/BlockProducers/GeneralInformationProfile.js index 741663a6..b2f301f9 100644 --- a/webapp/src/routes/block-producers/general-information-profile.js +++ b/webapp/src/routes/BlockProducers/GeneralInformationProfile.js @@ -1,13 +1,14 @@ import React from 'react' import PropTypes from 'prop-types' -import classNames from 'classnames' +import clsx from 'clsx' import { useTranslation } from 'react-i18next' import countries from 'i18n-iso-countries' -import Grid from '@material-ui/core/Grid' +import Grid from '@mui/material/Grid' import _get from 'lodash.get' -import Typography from '@material-ui/core/Typography' -import Box from '@material-ui/core/Box' -import formatNumber from 'utils/formatNumber' +import Typography from '@mui/material/Typography' +import Box from '@mui/material/Box' + +import formatNumber from '../../utils/format-number' countries.registerLocale(require('i18n-iso-countries/langs/en.json')) countries.registerLocale(require('i18n-iso-countries/langs/es.json')) @@ -29,7 +30,7 @@ const _getCountryName = (country = null, locationNumber, defaultMessage) => { return defaultMessage } - +// refactor this TODO const SocialNetworks = ({ classes, producer }) => { const { t } = useTranslation('profile') const github = _get(producer, 'bpjson.org.social.github') @@ -51,7 +52,7 @@ const SocialNetworks = ({ classes, producer }) => { { { { { { @@ -188,12 +189,12 @@ const AdditionalResources = ({ classes, producer }) => { @@ -209,12 +210,12 @@ const AdditionalResources = ({ classes, producer }) => { @@ -277,7 +278,7 @@ const GeneralInformation = ({ classes, producer = {} }) => { {_get(producer, 'system.owner', '- -')} @@ -288,7 +289,7 @@ const GeneralInformation = ({ classes, producer = {} }) => { {countryName} @@ -299,7 +300,7 @@ const GeneralInformation = ({ classes, producer = {} }) => { {webpageURL ? ( { {formatNumber(parseFloat(totalVotes), 0)} diff --git a/webapp/src/routes/block-producers/slider-rating-section.js b/webapp/src/routes/BlockProducers/SliderRatingSection.js similarity index 58% rename from webapp/src/routes/block-producers/slider-rating-section.js rename to webapp/src/routes/BlockProducers/SliderRatingSection.js index f4084420..de6c1033 100644 --- a/webapp/src/routes/block-producers/slider-rating-section.js +++ b/webapp/src/routes/BlockProducers/SliderRatingSection.js @@ -1,11 +1,13 @@ import React from 'react' import PropTypes from 'prop-types' -import classNames from 'classnames' -import { Grid, Switch, Tooltip, Typography } from '@material-ui/core' -import { makeStyles } from '@material-ui/core/styles' -import HelpOutline from '@material-ui/icons/HelpOutline' +import clsx from 'clsx' +import Grid from '@mui/material/Grid' +import Switch from '@mui/material/Switch' +import Typography from '@mui/material/Typography' +import Box from '@mui/material/Box' +import { makeStyles } from '@mui/styles' -import RateSlider from 'components/rate-slider' +import RateSlider from '../../components/RateSlider' import styles from './styles' @@ -36,20 +38,17 @@ const SliderRatingSection = ({ - {t('community')}{' '} - - - + {`${t('community')}`} + {t('communityTooltip')} -
+ -
+ + {`${ratingState.communityEnabled ? t('enabled') : t('disabled')}`} + +
- {t('development')}{' '} - - - + {t('development')} + {t('developmentTooltip')} -
+ -
+ + {`${ratingState.developmentEnabled ? t('enabled') : t('disabled')}`} + +
- {t('infrastructure')}{' '} - - - + {t('infrastructure')} + {t('infrastructureTooltip')} -
+ -
+ + {ratingState.infraEnabled ? t('enabled') : t('disabled')} + +
- {t('transparency')}{' '} - - - + {t('transparency')} + {t('transparencyTooltip')} -
+ -
+ + {ratingState.transparencyEnabled ? t('enabled') : t('disabled')} + +
- {t('trustiness')}{' '} - - - + {t('trustiness')} + {t('trustinessTooltip')} -
+ -
+ + {ratingState.trustinessEnabled ? t('enabled') : t('disabled')} + +
) diff --git a/webapp/src/routes/BlockProducers/index.js b/webapp/src/routes/BlockProducers/index.js new file mode 100644 index 00000000..c783a3ea --- /dev/null +++ b/webapp/src/routes/BlockProducers/index.js @@ -0,0 +1,276 @@ +import React, { useEffect, useState, useRef } from 'react' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import Grid from '@mui/material/Grid' +import Box from '@mui/material/Box' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import Collapse from '@mui/material/Collapse' +import ThumbUpAltIcon from '@mui/icons-material/ThumbUpAlt' +import clsx from 'clsx' +import _get from 'lodash.get' + +import TitlePage from '../../components/PageTitle' +import CompareTool from '../../components/CompareTool' +import Card from '../../components/Card' +import FilterBanner from '../../components/FilterBanner' +import getAverageValue from '../../utils/get-average-value' +import { useSharedState } from '../../context/state.context' + +import styles from './styles' +import SelectedBpsBottomSheet from './BottomSheetSelectedBps' + +const useStyles = makeStyles(styles) + +const AllBps = () => { + const { t } = useTranslation('translations') + const [state, { setProducers, setCompareBPTool, setSelectedProducers }] = + useSharedState() + const classes = useStyles() + const myRef = useRef(null) + const [currentlyVisible, setCurrentlyVisible] = useState(30) + const [hasMoreRows, setMoreRows] = useState(false) + + const [ratingState, setRatingState] = useState({ + txError: null, + txSuccess: false, + showChipMessage: false + }) + + const loadMore = async () => { + if (!hasMoreRows) return + + await setProducers(currentlyVisible + 12) + setCurrentlyVisible(currentlyVisible + 12) + } + + const goToTop = () => { + document.getElementById('childContent').scrollTo(0, 0) + } + + const handleOnFliterChange = async filter => { + await setProducers(currentlyVisible, filter) + } + + const handleToggleSelected = (item, isAddItem = false) => { + if (isAddItem) { + setSelectedProducers([...state.selectedProducers, item]) + console.log({ selectedProducers: state?.selectedProducers }) + } else { + const removeSelected = state.selectedProducers.filter( + bpName => bpName !== item + ) + + setSelectedProducers(removeSelected) + } + } + + const handleOpenDesktopVotingTool = () => { + goToTop() + !state.compareBPToolVisible && setCompareBPTool(true) + } + + const handleOnClear = () => { + setSelectedProducers([]) + state.compareBPToolVisible && setCompareBPTool(false) + } + + const handleOnClose = () => { + state.compareBPToolVisible && setCompareBPTool(false) + } + + const handleSetRatingState = () => { + setRatingState({ + ...ratingState, + txError: null, + txSuccess: false, + showChipMessage: false + }) + } + + const sendVoteBps = async BPs => { + if (!state.user) return + + const transaction = { + actions: [ + { + account: 'eosio', + name: 'voteproducer', + authorization: [ + { + actor: state.user.accountName, + permission: 'active' + } + ], + data: { + voter: state.user.accountName, + proxy: '', + producers: BPs.sort() + } + } + ] + } + + try { + await state.ual.activeUser.signTransaction(transaction, { + broadcast: true + }) + + setRatingState({ + ...ratingState, + txSuccess: true, + showChipMessage: true + }) + + setTimeout(() => { + setRatingState({ + ...ratingState, + txError: null, + txSuccess: false, + showChipMessage: false + }) + }, 2000) + } catch (error) { + console.warn(error) + + setRatingState({ + ...ratingState, + txError: error && error.cause ? error.cause.message : error, + showChipMessage: true + }) + } + } + + useEffect(() => { + if (!state.user) return + + setSelectedProducers([ + ...state.selectedProducers, + ...state?.user?.userData?.voter_info?.producers + ]) + }, [state.user]) + + useEffect(() => { + const getData = async () => { + !state.blockProducers.data.length && + (await setProducers(currentlyVisible)) + } + + getData() + }, []) + + useEffect(() => { + if (!state.blockProducers.data.length) { + return + } + + setMoreRows(state.blockProducers.rows > state.blockProducers.data.length) + }, [state.blockProducers]) + + return ( + + + + sendVoteBps(state.selectedProducers || [])} + userInfo={state.user} + message={ratingState} + setMessage={handleSetRatingState} + handleOnClose={handleOnClose} + handleOnClear={handleOnClear} + /> + + + + + {(state.blockProducers.data || []).map(blockProducer => ( + + () => { + handleToggleSelected(producerAccountName, isAdding) + }} + data={blockProducer} + imageURL={_get(blockProducer, 'bpjson.org.branding.logo_256')} + owner={_get(blockProducer, 'owner')} + title={_get(blockProducer, 'bpjson.org.candidate_name')} + pathLink='block-producers' + buttonLabel={t('addToVote')} + average={getAverageValue( + _get(blockProducer, 'totalStats.average', 0) + )} + rate={_get(blockProducer, 'totalStats.ratings_cntr', 0)} + isNewRate={ + state.user && + state.user.userData.userRates.some( + ({ owner }) => owner === blockProducer.owner + ) + } + /> + + ))} + + + {state.selectedProducers.length > 0 && ( + + + + + + )} + + sendVoteBps(state.selectedProducers || [])} + userInfo={state.user} + message={ratingState} + setMessage={handleSetRatingState} + handleOnClose={handleOnClose} + handleOnClear={handleOnClear} + /> + + + + + + ) +} + +export default AllBps diff --git a/webapp/src/routes/block-producers/styles.js b/webapp/src/routes/BlockProducers/styles.js similarity index 65% rename from webapp/src/routes/block-producers/styles.js rename to webapp/src/routes/BlockProducers/styles.js index cfa5b4c8..8bbcfdff 100644 --- a/webapp/src/routes/block-producers/styles.js +++ b/webapp/src/routes/BlockProducers/styles.js @@ -1,9 +1,8 @@ -export default (theme) => ({ +export default theme => ({ // index style - root: { + rootBP: { position: 'relative', - maxWidth: '100%', - margin: 'auto' + maxWidth: '100%' }, compareToggleButton: { position: 'fixed', @@ -17,29 +16,42 @@ export default (theme) => ({ background: theme.palette.surface.main, color: theme.palette.primary.main }, - wrapper: { - padding: theme.spacing(1), + wrapperGrid: { maxWidth: '100%', - margin: 'auto' + margin: '0 auto' + }, + gridRow: { + display: 'flex', + flexFlow: 'row wrap', + justifyContent: 'center' + }, + gridItem: { + flexBasis: '100%', + '-ms-flex': 'auto', + width: '100%', + position: 'relative', + padding: 10, + boxSizing: 'border-box', + [theme.breakpoints.up('sm')]: { + flexBasis: '50%' + }, + [theme.breakpoints.up('mdd')]: { + flexBasis: '33.33%' + } }, compareTool: { - paddingTop: '0 !important', - transform: 'scaleY(1)', - transformOrigin: 'top', - opacity: 1, height: '100%', - transition: [ - 'opacity 0.25s ease', - 'height 0.25s ease', - 'transform 0.25s ease', - 'min-height 0.25s ease' - ] + paddingTop: 0 }, bpCard: { backgroundColor: theme.palette.primary.light }, + loadMoreBtnBox: { + display: 'flex', + justifyContent: 'center', + padding: theme.spacing(2, 0) + }, loadMoreButton: { - color: '#443f56', display: 'block', margin: `${theme.spacing(2)}px auto`, '&:hover': { @@ -47,19 +59,33 @@ export default (theme) => ({ color: 'white' } }, - hidden: { - opacity: 0, - transform: 'scaleY(0)', - minHeight: 0, - height: 0 + hiddenMobile: { + display: 'none', + [theme.breakpoints.up('sm')]: { + display: 'flex' + } + }, + hiddenDesktop: { + display: 'flex', + overflow: 'hidden', + maxHeight: '100vh', + [theme.breakpoints.up('sm')]: { + display: 'none' + } }, // slider rating sliderWrapper: { display: 'flex', - alignItems: 'center' + alignItems: 'center', + marginBottom: 10, + width: '80%', + [theme.breakpoints.down('md')]: { + width: '100%' + } }, sliderBoxContent: { marginTop: 30, + padding: '0 10px 0 10px', [theme.breakpoints.down('sm')]: { marginTop: 10 } @@ -72,7 +98,8 @@ export default (theme) => ({ verticalAlign: 'middle' }, switchBox: { - marginLeft: 10 + marginLeft: 10, + color: '#443f56 !important' }, // filter box nestedPadding: { @@ -89,8 +116,12 @@ export default (theme) => ({ container: { padding: theme.spacing(1) }, + pageTitle: { + display: 'flex', + alignItems: 'center' + }, bpName: { - marginLeft: theme.spacing(1) + marginLeft: `${theme.spacing(1)} !important` }, accountCircle: { color: theme.palette.surface.main @@ -196,7 +227,6 @@ export default (theme) => ({ marginTop: 10, display: 'flex', flexDirection: 'column', - [theme.breakpoints.up('sm')]: { flexDirection: 'row', width: '100%' @@ -218,7 +248,7 @@ export default (theme) => ({ zIndex: 999, maxWidth: '100%', '& > button': { - backgroundColor: 'black', + backgroundColor: theme.palette.common.black, color: 'white', borderRadius: '24px 0 0 0' } @@ -232,7 +262,7 @@ export default (theme) => ({ }, paperAnchor: { right: '0', - overflowY: 'initial' + overflowY: 'hidden' }, reliefGrid: { margin: '10px 16px 30px 16px', @@ -273,5 +303,58 @@ export default (theme) => ({ '& .MuiAlert-icon': { alignItems: 'center' } + }, + linkRate: { + marginLeft: `${theme.spacing(2)} !important`, + padding: `${theme.spacing(1, 2)} !important` + }, + showMobile: { + [theme.breakpoints.up('md')]: { + display: 'none' + } + }, + showDesktop: { + [theme.breakpoints.down('md')]: { + display: 'none' + } + }, + infoGridStyle: { + borderRight: 'solid 1px rgba(0, 0, 0, 0.38)', + paddingTop: 18, + paddingRight: 50, + [theme.breakpoints.down('md')]: { + borderRight: 0, + paddingRight: 0 + } + }, + chartWrapperSliderView: { + '& .highcharts-container ': { + height: '400px !important', + width: '100% !important', + '& > svg': { + height: '400px !important', + width: '100% !important' + } + } + }, + tableBox: { + marginBottom: '70px !important', + justifyContent: 'center !important', + margin: 'auto !important' + }, + centerContent: { + display: 'flex', + justifyContent: 'center' + }, + profileChartWrapper: { + marginTop: 20, + '& .highcharts-container ': { + height: '400px !important', + width: '100% !important', + '& > svg': { + height: '400px !important', + width: '100% !important' + } + } } }) diff --git a/webapp/src/routes/Help/index.js b/webapp/src/routes/Help/index.js new file mode 100644 index 00000000..b8544f80 --- /dev/null +++ b/webapp/src/routes/Help/index.js @@ -0,0 +1,68 @@ +import React from 'react' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import Grid from '@mui/material/Grid' +import Box from '@mui/material/Box' +import Link from '@mui/material/Link' +import HttpIcon from '@mui/icons-material/Http' +import TelegramIcon from '@mui/icons-material/Telegram' +import GitHubIcon from '@mui/icons-material/GitHub' + +import TitlePage from '../../components/PageTitle' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const Help = () => { + const classes = useStyles() + const { t } = useTranslation('help') + + return ( + + + + + {t('title')} + + {t('paragraph')} + + + + + + {t('githubEOSCR')} + + + + + + {t('telegramChannel')} + + + + + + {t('websiteEOSCR')} + + + + + + ) +} + +export default Help diff --git a/webapp/src/routes/help/styles.js b/webapp/src/routes/Help/styles.js similarity index 78% rename from webapp/src/routes/help/styles.js rename to webapp/src/routes/Help/styles.js index 7cd96895..a46fbde5 100644 --- a/webapp/src/routes/help/styles.js +++ b/webapp/src/routes/Help/styles.js @@ -1,15 +1,18 @@ -export default (theme) => ({ +export default theme => ({ wrapperContainers: { color: '#433F5B', + display: 'flex', + justifyContent: 'center', + width: '100%', padding: theme.spacing(6, 2), '& h6': { marginBottom: theme.spacing(1) - }, - [theme.breakpoints.up('sm')]: { - padding: theme.spacing(6, 4) } }, firstContainer: { + maxWidth: 1024, + width: '100%', + '& h5': { fontSize: theme.typography.h4.fontSize, marginBottom: 12.5 diff --git a/webapp/src/routes/Home/Cover.js b/webapp/src/routes/Home/Cover.js new file mode 100644 index 00000000..e0c5f7e2 --- /dev/null +++ b/webapp/src/routes/Home/Cover.js @@ -0,0 +1,92 @@ +import React, { forwardRef, memo } from 'react' +import { useTranslation } from 'react-i18next' +import Typography from '@mui/material/Typography' +import Button from '@mui/material/Button' +import Box from '@mui/material/Box' +import { makeStyles } from '@mui/styles' +import { Link } from 'react-router-dom' + +import PolarChart from '../../components/PolarChart' + +import styles from './styles' + +const refBPLink = (props, ref) => +const bpLink = forwardRef(refBPLink) +const useStyles = makeStyles(styles) + +const HomeCover = () => { + const { t } = useTranslation('home') + const classes = useStyles() + + return ( + + + {t('cover.title')} + + + + + + + + + + + + + {t('cover.paragraph.subtitle1')} + + + {t('cover.paragraph.text1')} + + + {t('cover.paragraph.text2')} + + + {t('cover.paragraph.subtitle2')} + + + {t('cover.paragraph.text3')} + + + {t('cover.paragraph.text4')} + + + + + + + + + + + ) +} + +export default memo(HomeCover) diff --git a/webapp/src/routes/home/rateCategory.js b/webapp/src/routes/Home/RateCategory.js similarity index 62% rename from webapp/src/routes/home/rateCategory.js rename to webapp/src/routes/Home/RateCategory.js index e28fd62a..6ef9f064 100644 --- a/webapp/src/routes/home/rateCategory.js +++ b/webapp/src/routes/Home/RateCategory.js @@ -1,14 +1,14 @@ -import React from 'react' +import React, { memo } from 'react' import { useTranslation } from 'react-i18next' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/core/styles' -import Grid from '@material-ui/core/Grid' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' +import Box from '@mui/material/Box' -import CommunityIcon from 'components/icon/communityIcon' -import TransparencyIcon from 'components/icon/transparencyIcon' -import TrustinessIcon from 'components/icon/trustinessIcon' -import InfrastructureIcon from 'components/icon/infrastructureIcon' -import DevelopmentIcon from 'components/icon/developmentIcon' +import CommunityIcon from '../../components/icon/communityIcon' +import TransparencyIcon from '../../components/icon/transparencyIcon' +import TrustinessIcon from '../../components/icon/trustinessIcon' +import InfrastructureIcon from '../../components/icon/infrastructureIcon' +import DevelopmentIcon from '../../components/icon/developmentIcon' import styles from './styles' @@ -19,19 +19,17 @@ const RatingCategory = () => { const classes = useStyles() return ( - - - - {t('ratingCategory.title')} - - - -
+ + + {t('ratingCategory.title')} + + + {t('ratingCategory.transparency.title')} -
+ { > {t('ratingCategory.transparency.description')} -
- -
+ + + {t('ratingCategory.infrastructure.title')} -
+ { > {t('ratingCategory.infrastructure.description')} -
- -
+ + + {t('ratingCategory.trustiness.title')} -
+ { > {t('ratingCategory.trustiness.description')} -
- -
+ + + {t('ratingCategory.community.title')} -
+ { > {t('ratingCategory.community.description')} -
- -
+ + + {t('ratingCategory.development.title')} -
+ { > {t('ratingCategory.development.description')} -
-
+ + ) } -export default RatingCategory +export default memo(RatingCategory) diff --git a/webapp/src/routes/home/subTopic.js b/webapp/src/routes/Home/SubTopic.js similarity index 68% rename from webapp/src/routes/home/subTopic.js rename to webapp/src/routes/Home/SubTopic.js index ee3b61d1..fd224d5b 100644 --- a/webapp/src/routes/home/subTopic.js +++ b/webapp/src/routes/Home/SubTopic.js @@ -1,10 +1,10 @@ -import React from 'react' +import React, { memo } from 'react' import { useTranslation } from 'react-i18next' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/core/styles' -import Grid from '@material-ui/core/Grid' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' +import Box from '@mui/material/Box' -import Video from 'components/video' +import Video from '../../components/Video' import styles from './styles' @@ -15,9 +15,9 @@ const SubTopic = () => { const classes = useStyles() return ( - - - + + + {t('subTopic.title')} @@ -38,7 +38,7 @@ const SubTopic = () => { > {t('subTopic.paragraph2')} - + {t('subTopic.subtitle')} @@ -58,12 +58,12 @@ const SubTopic = () => { {t('subTopic.telegramGroup')}.
-
- + + -
+ + ) } -export default SubTopic +export default memo(SubTopic) diff --git a/webapp/src/routes/Home/index.js b/webapp/src/routes/Home/index.js new file mode 100644 index 00000000..da840794 --- /dev/null +++ b/webapp/src/routes/Home/index.js @@ -0,0 +1,48 @@ +import React from 'react' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import Box from '@mui/material/Box' +import clsx from 'clsx' + +import TitlePage from '../../components/PageTitle' + +import styles from './styles' +import Cover from './Cover' +import SubTopic from './SubTopic' +import RateCategory from './RateCategory' + +const useStyles = makeStyles(styles) + +const Home = () => { + const { t } = useTranslation('home') + const classes = useStyles() + + return ( + + + + + + + + + + + + + ) +} + +export default Home diff --git a/webapp/src/routes/Home/styles.js b/webapp/src/routes/Home/styles.js new file mode 100644 index 00000000..a554add6 --- /dev/null +++ b/webapp/src/routes/Home/styles.js @@ -0,0 +1,186 @@ +export default theme => ({ + spacingContainers: { + padding: theme.spacing(8, 2), + [theme.breakpoints.down('sm')]: { + padding: theme.spacing(6, 2) + } + }, + mainCoverContainer: { + backgroundColor: theme.palette.surface.main, + display: 'flex', + justifyContent: 'center' + }, + mainSubTopicContainer: { + backgroundColor: theme.palette.surface.main, + display: 'flex', + justifyContent: 'center' + }, + rateCategoryContainer: { + backgroundColor: '#f5f5f5', + display: 'flex', + justifyContent: 'center' + }, + coverContainer: { + padding: 0, + color: '#433F5B', + maxWidth: '1024px', + backgroundColor: theme.palette.surface.main + }, + mainTitle: { + marginBottom: '12.5px !important', + fontWeight: 'normal', + fontStretch: 'normal', + fontStyle: 'normal', + lineHeight: '1.17', + letterSpacing: 'normal', + textAlign: 'left', + color: theme.palette.primary.dark, + [theme.breakpoints.down('sm')]: { + fontSize: '2.03rem !important', + marginBottom: 0 + } + }, + btnWrapper: { + display: 'flex', + justifyContent: 'center' + }, + btnMobile: { + width: '100%', + [theme.breakpoints.up('sm')]: { + width: 336 + } + }, + ctaContainer: { + textAlign: 'center', + display: 'none', + [theme.breakpoints.up('md')]: { + display: 'flex', + justifyContent: 'center' + } + }, + chartContainer: { + width: '100%', + display: 'none', + alignItems: 'center', + [theme.breakpoints.up('md')]: { + display: 'flex', + width: '45%', + '& .highcharts-container ': { + height: '500px !important', + width: '100% !important', + '& > svg': { + height: '500px !important', + width: '100% !important' + } + } + } + }, + chartContainerMobile: { + width: '100%', + '& .highcharts-container ': { + height: '400px !important', + width: '100% !important', + '& > svg': { + height: '400px !important', + width: '100% !important' + } + } + }, + subtitle: { + marginBottom: `${theme.spacing(1)} !important`, + fontWeight: '500', + fontStretch: 'normal', + fontStyle: 'normal', + lineHeight: '23px !important', + letterSpacing: '0.15px !important', + textAlign: 'left', + color: theme.palette.primary.dark, + fontSize: 20 + }, + leftCoverBox: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + '& .MuiTypography-body2': { + lineHeight: '28px', + letterSpacing: '0.44px', + fontSize: 16, + color: theme.palette.common.black + }, + [theme.breakpoints.up('md')]: { + width: '55%' + } + }, + ratingContainer: { + maxWidth: '1024px' + }, + ratingTitle: { + fontWeight: '500', + fontStretch: 'normal', + fontStyle: 'normal', + lineHeight: '23px !important', + letterSpacing: '0.15px !important', + textAlign: 'left', + color: theme.palette.primary.dark, + fontSize: 20, + display: 'flex', + marginBottom: 12.5 + }, + paragraph: { + marginLeft: `${theme.spacing(4.5)} !important`, + lineHeight: '28px !important', + letterSpacing: '0.44px !important', + color: theme.palette.common.black + }, + subTitleContainer: { + display: 'flex', + alignItems: 'center', + paddingTop: 6 + }, + iconStyle: { + marginRight: theme.spacing(2), + marginTop: theme.spacing(1), + color: '#433F5B' + }, + subTopicContainer: { + maxWidth: '1024px', + display: 'flex', + flexDirection: 'column', + [theme.breakpoints.up('md')]: { + flexDirection: 'row', + justifyContent: 'space-between' + } + }, + ratingParagraph: { + color: theme.palette.grey[600] + }, + gridContent: { + padding: '2%', + width: '100%', + [theme.breakpoints.up('md')]: { + width: '50%' + } + }, + videoBox: { + width: '100%', + [theme.breakpoints.up('md')]: { + width: '50%' + } + }, + link: { + color: theme.palette.grey[600], + fontWeight: '500', + textDecoration: 'none' + }, + mobileView: { + display: 'flex', + flexDirection: 'column', + margin: '-10px 0 25px 0', + [theme.breakpoints.up('md')]: { + display: 'none' + } + }, + desktopView: { + display: 'flex' + } +}) diff --git a/webapp/src/routes/proxies/general-information-profile.js b/webapp/src/routes/Proxies/GeneralInformationProfile.js similarity index 79% rename from webapp/src/routes/proxies/general-information-profile.js rename to webapp/src/routes/Proxies/GeneralInformationProfile.js index c83ddc9d..c1058cba 100644 --- a/webapp/src/routes/proxies/general-information-profile.js +++ b/webapp/src/routes/Proxies/GeneralInformationProfile.js @@ -1,12 +1,13 @@ import React from 'react' import PropTypes from 'prop-types' -import classNames from 'classnames' +import clsx from 'clsx' import { useTranslation } from 'react-i18next' -import Grid from '@material-ui/core/Grid' +import Grid from '@mui/material/Grid' +import Box from '@mui/material/Box' import _get from 'lodash.get' -import Typography from '@material-ui/core/Typography' +import Typography from '@mui/material/Typography' -import formatNumber from 'utils/formatNumber' +import formatNumber from '../../utils/format-number' const SocialNetworks = ({ classes, proxy }) => { const { t } = useTranslation('profile') @@ -22,13 +23,13 @@ const SocialNetworks = ({ classes, proxy }) => { {t('social')} {twitter && ( - + Twitter: { {twitter} - + )} {steemit && ( - + Steemit: { {steemit} - + )} {telegram && ( - + Telegram: { {telegram} - + )}
) @@ -99,24 +100,24 @@ const GeneralInformation = ({ classes, proxy = {} }) => { {t('generalInformation')} - + {t('account')}: {_get(proxy, 'owner', '- -')} - - + + {t('website')}: {webpageURL ? ( { '- -' )} - + {background && ( - + {t('background')}: {background} - + )} {philosophy && ( - + {t('philosophy')}: {philosophy} - + )} {t('rankings')} - + {t('proxyVotes')}: {formatNumber(parseFloat(proxyVotes), 0)} - - + + {t('totalVotes')}: {formatNumber(parseFloat(totalVotes), 0)} - + ) diff --git a/webapp/src/routes/Proxies/ProxyProfile.js b/webapp/src/routes/Proxies/ProxyProfile.js new file mode 100644 index 00000000..9c56872b --- /dev/null +++ b/webapp/src/routes/Proxies/ProxyProfile.js @@ -0,0 +1,282 @@ +import React, { useEffect, forwardRef, useState } from 'react' +import clsx from 'clsx' +import { useTranslation } from 'react-i18next' +import { Link, useParams } from 'react-router-dom' +import CircularProgress from '@mui/material/CircularProgress' +import Avatar from '@mui/material/Avatar' +import Button from '@mui/material/Button' +import Grid from '@mui/material/Grid' +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { makeStyles } from '@mui/styles' +import Snackbar from '@mui/material/Snackbar' +import MuiAlert from '@mui/material/Alert' +import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft' +import _get from 'lodash.get' + +import TitlePage from '../../components/PageTitle' +import PolarChart from '../../components/PolarChart' +import { useSharedState } from '../../context/state.context' + +import { SocialNetworks, GeneralInformation } from './GeneralInformationProfile' +import styles from './styles' + +const useStyles = makeStyles(styles) + +const Alert = forwardRef(function Alert(props, ref) { + return +}) + +const ProxyProfile = () => { + const { t } = useTranslation('profile') + const classes = useStyles() + const { account } = useParams() + const [state, { setProxy }] = useSharedState() + const [proxyLogo, setProxyLogo] = useState(null) + const [proxySlogan, setProxySlogan] = useState(null) + const [polarChartData, setPolarChartData] = useState([]) + const [proxyTitle, setProxyTitle] = useState('No Title') + const [showMessage, setShowMessage] = useState(false) + const [ratingState, setRatingState] = useState({ + processing: false, + txError: null, + txSuccess: false + }) + + const sendVoteProxy = async proxy => { + if (!state?.user?.accountName) { + setShowMessage(true) + + return + } + + const transaction = { + actions: [ + { + account: 'eosio', + name: 'voteproducer', + authorization: [ + { + actor: state.user.accountName, + permission: 'active' + } + ], + data: { + voter: state.user.accountName, + proxy, + producers: [] + } + } + ] + } + + try { + setRatingState({ + ...ratingState, + txError: null, + processing: true, + txSuccess: false + }) + + await state.ual.activeUser.signTransaction(transaction, { + broadcast: true + }) + + setRatingState({ + ...ratingState, + processing: false, + txSuccess: true + }) + + setTimeout(() => { + setRatingState({ + ...ratingState, + txError: null, + txSuccess: false + }) + }, 2000) + setShowMessage(false) + } catch (error) { + console.warn(error) + setRatingState({ + ...ratingState, + processing: false, + txError: error.message ? error.message : error + }) + } + } + + const handleClose = (event, reason) => { + if (reason === 'clickaway') { + return + } + + setShowMessage(false) + setRatingState({ + ...ratingState, + processing: false, + txError: null, + txSuccess: false + }) + } + + useEffect(() => { + if (state.proxy) { + setProxyLogo(_get(state.proxy, 'logo_256', null)) + setProxyTitle( + _get(state.proxy, 'name', _get(state.proxy, 'owner', 'No Data')) + ) + setProxySlogan(_get(state.proxy, 'slogan', null)) + setPolarChartData([state.proxy.data]) + } + }, [state.proxy]) + + useEffect(() => { + const getProxyData = async () => { + if (state.proxies.data.length) { + // TODO: do a double check if this is necessary + const proxySelected = state.proxies.data.find( + ({ owner }) => owner === account + ) + + setProxy(proxySelected, true) + + return + } + + await setProxy(account) + } + + getProxyData() + }, [account]) + + return ( + + + + + + + + + + + + {proxyLogo ? : ''} + + + {proxyTitle} + + + {proxySlogan && ( + +
{proxySlogan}
+
+ )} +
+ + + + + + + + + + + + + + {t('voteWithoutLogin')} + + + + + {ratingState.txError} + + + + + {t('success')} + + + {ratingState.processing && ( + + + + {t('voting')} ... + + + )} + + + + + + + + + +
+
+ ) +} + +export default ProxyProfile diff --git a/webapp/src/routes/Proxies/index.js b/webapp/src/routes/Proxies/index.js new file mode 100644 index 00000000..fb05445e --- /dev/null +++ b/webapp/src/routes/Proxies/index.js @@ -0,0 +1,226 @@ +import React, { useEffect, useState } from 'react' +import PropTypes from 'prop-types' +import Button from '@mui/material/Button' +import Box from '@mui/material/Box' +import Collapse from '@mui/material/Collapse' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import _get from 'lodash.get' + +import { useSharedState } from '../../context/state.context' +import TitlePage from '../../components/PageTitle' +import FilterBanner from '../../components/FilterBanner' +import Card from '../../components/Card' +import CompareTool from '../../components/CompareTool' +import SelectedBpsBottomSheet from './../BlockProducers/BottomSheetSelectedBps' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const AllProxies = ({ ual = {} }) => { + const { t } = useTranslation('translations') + const classes = useStyles() + const [state, { setProxies, setCompareProxyTool, setSelectedProxies }] = + useSharedState() + const [currentlyVisible, setCurrentlyVisible] = useState(30) + const [hasMoreRows, setMoreRows] = useState(false) + const [ratingState, setRatingState] = useState({ + processing: false, + txError: null, + txSuccess: false + }) + + const loadMore = async () => { + if (!hasMoreRows) return + + await setProxies(currentlyVisible + 12) + setCurrentlyVisible(currentlyVisible + 12) + } + + const handleToggleCompareTool = () => { + setCompareProxyTool(!state.compareProxyToolVisible) + } + + const handleToggleSelected = () => { + setSelectedProxies([]) + } + + const handleOpenDesktopVotingTool = (isAdding, producerAccountName) => { + console.log({ isAdding, producerAccountName }) + + setSelectedProxies([producerAccountName]) + setCompareProxyTool(true) + } + + const handleSetRatingState = () => { + setRatingState({ + ...ratingState, + txError: null, + txSuccess: false, + showChipMessage: false + }) + } + + const sendVoteProxy = async () => { + if (!state.user.accountName) return + + const transaction = { + actions: [ + { + account: 'eosio', + name: 'voteproducer', + authorization: [ + { + actor: state.user.accountName, + permission: 'active' + } + ], + data: { + voter: state.user.accountName, + proxy: state.proxy, + producers: [] + } + } + ] + } + + try { + setRatingState({ + ...ratingState, + txError: null, + processing: true, + txSuccess: false + }) + + await ual.activeUser.signTransaction(transaction, { + broadcast: true + }) + + setRatingState({ + ...ratingState, + processing: false, + txSuccess: true + }) + + setTimeout(() => { + setRatingState({ + ...ratingState, + txError: null, + txSuccess: false + }) + }, 2000) + } catch (error) { + console.warn(error) + setRatingState({ + ...ratingState, + processing: false, + txError: error.message ? error.message : error + }) + } + } + + useEffect(() => { + const getProxiesData = async () => { + !state.proxies.data.length && (await setProxies(currentlyVisible)) + } + + getProxiesData() + }, []) + + useEffect(() => { + if (!state.proxies.data.length) { + return + } + + setMoreRows(state.proxies.rows > state.proxies.data.length) + }, [state.proxies]) + + return ( + + + + { + handleToggleCompareTool() + handleToggleSelected() + }} + /> + + + + + {(state.proxies.data || []).map(proxy => ( + + + + ))} + + + + { + handleToggleCompareTool() + handleToggleSelected() + }} + /> + + + + + + ) +} + +AllProxies.propTypes = { + ual: PropTypes.object +} + +export default AllProxies diff --git a/webapp/src/routes/proxies/styles.js b/webapp/src/routes/Proxies/styles.js similarity index 52% rename from webapp/src/routes/proxies/styles.js rename to webapp/src/routes/Proxies/styles.js index f6c475cb..c80c8290 100644 --- a/webapp/src/routes/proxies/styles.js +++ b/webapp/src/routes/Proxies/styles.js @@ -1,4 +1,4 @@ -export default (theme) => ({ +export default theme => ({ // index root: { position: 'relative' @@ -15,16 +15,35 @@ export default (theme) => ({ background: theme.palette.surface.main, color: theme.palette.primary.main }, - wrapper: { - padding: theme.spacing(1), + wrapperGrid: { maxWidth: '100%', - margin: 'auto' + margin: '0 auto' + }, + gridRow: { + display: 'flex', + flexFlow: 'row wrap', + justifyContent: 'center' + }, + gridItem: { + flexBasis: '100%', + '-ms-flex': 'auto', + width: '100%', + position: 'relative', + padding: 10, + boxSizing: 'border-box', + [theme.breakpoints.up('sm')]: { + flexBasis: '50%' + }, + [theme.breakpoints.up('mdd')]: { + flexBasis: '33.33%' + } }, compareTool: { - minHeight: 340, + paddingTop: '0 !important', transform: 'scaleY(1)', transformOrigin: 'top', opacity: 1, + height: '100%', transition: [ 'opacity 0.25s ease', 'height 0.25s ease', @@ -62,7 +81,14 @@ export default (theme) => ({ padding: 10 }, bpName: { - marginLeft: 6 + marginLeft: `${theme.spacing(1)} !important`, + fontWeight: 'normal', + fontStretch: 'normal', + fontStyle: 'normal', + lineHeight: '1.17', + letterSpacing: 'normal', + textAlign: 'left', + color: theme.palette.common.black }, accountCircle: { color: theme.palette.secondary.main @@ -71,26 +97,44 @@ export default (theme) => ({ padding: '3%' }, title: { - color: theme.palette.primary.main, - fontSize: '1.5rem', - marginBottom: 5, - marginTop: 5 + color: theme.palette.common.black, + fontSize: '1.5rem !important' + }, + bpSlogan: { + marginLeft: `${theme.spacing(2)} !important`, + [theme.breakpoints.up('md')]: { + marginLeft: `${theme.spacing(3)} !important` + } }, subTitle: { - fontSize: 14 + fontSize: '18px !important', + fontWeight: '500 !important' + }, + rowBox: { + display: 'flex', + marginLeft: `${theme.spacing(2)} !important`, + [theme.breakpoints.up('md')]: { + marginLeft: `${theme.spacing(3)} !important` + } }, longSubTitle: { - margin: '7px 0', - fontSize: 14 + fontSize: '18px !important', + fontWeight: '500 !important', + marginLeft: `${theme.spacing(2)} !important`, + [theme.breakpoints.up('md')]: { + marginLeft: `${theme.spacing(3)} !important` + } }, longValue: { - marginLeft: 4, - marginTop: 7, - fontWeight: 500 + margin: `${theme.spacing(0, 0, 1, 2)} !important`, + fontWeight: '400 !important', + [theme.breakpoints.up('md')]: { + marginLeft: `${theme.spacing(0, 0, 1, 3)} !important` + } }, value: { - marginLeft: 4, - fontWeight: 500 + marginLeft: '4px !important', + fontWeight: '400 !important' }, category: { marginTop: 10 @@ -99,12 +143,12 @@ export default (theme) => ({ color: theme.palette.surface.main, backgroundColor: theme.palette.secondary.main, width: '100%', + height: 36, '&:hover': { backgroundColor: theme.palette.secondary.light }, - - [theme.breakpoints.up('sm')]: { - marginRight: 10 + [theme.breakpoints.up('md')]: { + width: '50%' } }, wrapperBox: { @@ -123,14 +167,12 @@ export default (theme) => ({ }, showOnlySm: { display: 'flex', - [theme.breakpoints.up('sm')]: { display: 'none' } }, showOnlyLg: { display: 'flex', - [theme.breakpoints.down('sm')]: { display: 'none' } @@ -164,12 +206,48 @@ export default (theme) => ({ '&:after': { content: 'close-quote' } }, reliefGrid: { - margin: '0 30px 30px 30px', - padding: '20px', + padding: '20px 0', border: '1px solid #f8f8f', borderRadius: '6px', boxShadow: 'inset 2px 2px 2px #fff, inset -1px 0 2px rgba(0,0,0,.1), 1px 1px 3px rgba(0,0,0,.1)', backgroundColor: '#fff' + }, + hiddenDesktop: { + display: 'flex !important', + justifyContent: 'center', + [theme.breakpoints.up('md')]: { + display: 'none !important' + } + }, + hiddenMobile: { + display: 'none !important', + [theme.breakpoints.up('md')]: { + display: 'flex !important', + justifyContent: 'center' + } + }, + loadMoreBtnBox: { + display: 'flex', + justifyContent: 'center', + padding: theme.spacing(2, 0) + }, + avatarTitle: { + display: 'flex', + alignItems: 'center' + }, + polarGraphWrapper: { + width: '100%', + '& .highcharts-container ': { + height: '400px !important', + width: '100% !important', + '& > svg': { + height: '400px !important', + width: '100% !important' + } + } + }, + paddingHorinzontal: { + padding: theme.spacing(0, 1) } }) diff --git a/webapp/src/routes/Route404/index.js b/webapp/src/routes/Route404/index.js new file mode 100644 index 00000000..211d4532 --- /dev/null +++ b/webapp/src/routes/Route404/index.js @@ -0,0 +1,40 @@ +import React from 'react' +import { Button, Typography } from '@material-ui/core' +import { makeStyles } from '@mui/styles' +import { Link } from 'react-router-dom' +import Helmet from 'react-helmet' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const Route404 = () => { + const classes = useStyles() + + return ( +
+ + + 404 + + + Page not found. + + + The page you are looking for might have been removed. + + + +
+ ) +} + +export default Route404 diff --git a/webapp/src/routes/Route404/styles.js b/webapp/src/routes/Route404/styles.js new file mode 100644 index 00000000..754598c1 --- /dev/null +++ b/webapp/src/routes/Route404/styles.js @@ -0,0 +1,10 @@ +export default theme => ({ + wrapper: { + padding: theme.spacing(6), + textAlign: 'center', + background: 'transparent', + [theme.breakpoints.up('md')]: { + padding: theme.spacing(10) + } + } +}) diff --git a/webapp/src/routes/termsOfUse/index.js b/webapp/src/routes/TermsOfUse/index.js similarity index 50% rename from webapp/src/routes/termsOfUse/index.js rename to webapp/src/routes/TermsOfUse/index.js index 860bc434..91669341 100644 --- a/webapp/src/routes/termsOfUse/index.js +++ b/webapp/src/routes/TermsOfUse/index.js @@ -1,10 +1,11 @@ import React from 'react' -import Box from '@material-ui/core/Box' -import { makeStyles } from '@material-ui/styles' +import Box from '@mui/material/Box' +import { makeStyles } from '@mui/styles' import { useTranslation } from 'react-i18next' import { RicardianContract } from '@eoscostarica/eoscr-components' -import { contract } from '../../config' -import TitlePage from 'components/title-page' + +import { mainConfig } from '../../config' +import TitlePage from '../../components/PageTitle' import styles from './styles' const useStyles = makeStyles(styles) @@ -15,11 +16,13 @@ const TermsOfUse = () => { return ( - - + + + + ) } diff --git a/webapp/src/routes/TermsOfUse/styles.js b/webapp/src/routes/TermsOfUse/styles.js new file mode 100644 index 00000000..89141f77 --- /dev/null +++ b/webapp/src/routes/TermsOfUse/styles.js @@ -0,0 +1,15 @@ +export default theme => ({ + root: { + padding: theme.spacing(3), + display: 'flex', + justifyContent: 'center', + width: '100%', + '& a': { + lineBreak: 'anywhere' + } + }, + wrapper: { + maxWidth: 1024, + width: '100%' + } +}) diff --git a/webapp/src/routes/account/index.js b/webapp/src/routes/account/index.js deleted file mode 100644 index 733dd478..00000000 --- a/webapp/src/routes/account/index.js +++ /dev/null @@ -1,307 +0,0 @@ -import React, { useEffect, useState } from 'react' -import PropTypes from 'prop-types' -import { useTranslation } from 'react-i18next' -import classNames from 'classnames' -import Button from '@material-ui/core/Button' -import Paper from '@material-ui/core/Paper' -import Grid from '@material-ui/core/Grid' -import Box from '@material-ui/core/Box' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/styles' -import { useDispatch, useSelector } from 'react-redux' -import Avatar from '@material-ui/core/Avatar' -import MuiAlert from '@material-ui/lab/Alert' -import IconButton from '@material-ui/core/IconButton' -import CloseIcon from '@material-ui/icons/Close' -import Accordion from '@material-ui/core/Accordion' -import AccordionSummary from '@material-ui/core/AccordionSummary' -import AccordionDetails from '@material-ui/core/AccordionDetails' -import ExpandMoreIcon from '@material-ui/icons/ExpandMore' -import Snackbar from '@material-ui/core/Snackbar' -import { useMediaQuery } from '@material-ui/core' -import Link from '@material-ui/core/Link' -import _get from 'lodash.get' - -import TitlePage from 'components/title-page' -import { contract, blockExplorer } from '../../config' -import styles from './styles' -import formatNumber from '../../utils/formatNumber' - -const useStyles = makeStyles(styles) - -const INIT_RATING_STATE_DATA = { - processing: false, - txError: null, - txSuccess: false -} - -const Account = ({ ual }) => { - const { t } = useTranslation('account') - const dispatch = useDispatch() - const classes = useStyles() - const [ratingState, setRatingState] = useState(INIT_RATING_STATE_DATA) - const [showMessage, setShowMessage] = useState(false) - const isDesktop = useMediaQuery('(min-width:769px)') - const { data: user } = useSelector((state) => state.user) - - const onHandleDeleteUserRate = async (bpName) => { - try { - if (!user) { - setShowMessage(true) - - return - } - - const transaction = { - actions: [ - { - account: contract, - name: 'rmrate', - authorization: [ - { - actor: user.account_name, - permission: 'active' - } - ], - data: { user: user.account_name, bp: bpName } - } - ] - } - - await ual.activeUser.signTransaction(transaction, { - broadcast: true - }) - - await dispatch.user.deleteUserRate({ - user: user.account_name, - bpName - }) - - await dispatch.user.getUserChainData({ ual }) - - setRatingState({ - ...ratingState, - txError: null, - processing: true, - txSuccess: true - }) - } catch (error) { - setRatingState({ - ...ratingState, - processing: false, - txError: error.cause ? error.cause.message : error - }) - } - } - - const handleClose = (event, reason) => { - if (reason === 'clickaway') { - return - } - - setShowMessage(false) - setRatingState({ - ...ratingState, - processing: false, - txError: null, - txSuccess: false - }) - } - - function Alert(props) { - return - } - - useEffect(() => { - const getAccountInfo = async () => { - if (ual.activeUser) { - await dispatch.user.getUserChainData({ ual }) - } - } - - getAccountInfo() - }, [ual.activeUser, ual]) - - return ( - - - - - - {t('title')} - - - - {user - ? `${user.account_name}: ${user.core_liquid_balance}` - : 'accountName: 0'} - - - {(user ? user.userRates : []).map((rate) => { - const imageURL = _get( - rate, - 'bpjson.org.branding.logo_256', - null - ) - const BPName = _get(rate, 'bpjson.org.candidate_name', rate.bp) - const date = _get( - rate, - 'tx_data.transaction.transactionDate', - '' - ).substring(0, 10) - - return ( - - } - aria-controls='panel1a-content' - id='panel1a-header' - > - - - {!imageURL ? ( - 'BP' - ) : ( - - )} - - - {date.length > 1 - ? `${t('youRated')} ${BPName} - ${date}` - : `${t('youRated')} ${BPName}`} - - - - - - - - {t('yourRating')} - - - - - {`${t('community')}: ${formatNumber( - rate.ratings.community, - 0 - )}`} - - - - - {`${t('development')}: ${formatNumber( - rate.ratings.development, - 0 - )}`} - - - - - {`${t('infrastructure')}: ${formatNumber( - rate.ratings.infrastructure, - 0 - )}`} - - - - - {`${t('transparency')}: ${formatNumber( - rate.ratings.transparency, - 0 - )}`} - - - - - {`${t('trustiness')}: ${formatNumber( - rate.ratings.trustiness, - 0 - )}`} - {' '} - - - {rate.tx_data && ( - - {rate.tx_data.transaction.transactionId} - - )} - - - - onHandleDeleteUserRate(rate.bp)} - style={{ fontSize: '1.2em', color: '#cd4729' }} - > - - {t('unpublish')} - - - - - - - ) - })} - - - - {t('voteWithoutLogin')} - - - - - {ratingState.txError} - - - - - {t('success')} - - - - - - - - ) -} - -Account.propTypes = { - ual: PropTypes.object -} - -export default Account diff --git a/webapp/src/routes/account/styles.js b/webapp/src/routes/account/styles.js deleted file mode 100644 index 53554e27..00000000 --- a/webapp/src/routes/account/styles.js +++ /dev/null @@ -1,39 +0,0 @@ -export default (theme) => ({ - container: { - padding: theme.spacing(3), - color: '#ffffff' - }, - account: { - padding: theme.spacing(3, 4) - }, - title: { - textAlign: 'center' - }, - box: { - padding: theme.spacing(3, 0) - }, - bold: { - fontWeight: 'bold', - wordBreak: 'break-all' - }, - button: { - marginBottom: theme.spacing(1), - marginTop: theme.spacing(1) - }, - rateList: { - '& hr': { - width: '100%' - } - }, - avatar: { - backgroundColor: theme.palette.surface.main - }, - link: { - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - display: 'block', - width: '100%', - color: '#1a73e8' - } -}) diff --git a/webapp/src/routes/block-producers/block-producer-profile.js b/webapp/src/routes/block-producers/block-producer-profile.js deleted file mode 100644 index e7cb4e14..00000000 --- a/webapp/src/routes/block-producers/block-producer-profile.js +++ /dev/null @@ -1,364 +0,0 @@ -import React, { useState, useEffect, forwardRef, Fragment } from 'react' -import PropTypes from 'prop-types' -import { useDispatch, useSelector } from 'react-redux' -import { useTranslation } from 'react-i18next' -import { Link, useLocation } from '@reach/router' -import Avatar from '@material-ui/core/Avatar' -import Button from '@material-ui/core/Button' -import Grid from '@material-ui/core/Grid' -import Snackbar from '@material-ui/core/Snackbar' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/core/styles' -import MuiAlert from '@material-ui/lab/Alert' -import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft' -import AccountCircle from '@material-ui/icons/AccountCircle' -import CloseIcon from '@material-ui/icons/Close' -import _get from 'lodash.get' -import { - Box, - useMediaQuery, - IconButton, - Link as MLink -} from '@material-ui/core' - -import { blockExplorer } from '../../config' -import getBPRadarData from 'utils/getBPRadarData' -import TitlePage from 'components/title-page' -import Radar from 'components/radar' -import Table from 'components/table' -import { - SocialNetworks, - GeneralInformation, - WebsiteLegend, - AdditionalResources -} from './general-information-profile' -import getAverageValue from 'utils/getAverageValue' -import styles from './styles' - -const useStyles = makeStyles(styles) - -const ProfileTitle = ({ - classes, - hasInformation, - producer, - t, - bpTitle, - isContentLoading -}) => { - if (!isContentLoading && !producer) { - return ( - - {t('noBlockProducer')} - - ) - } - - return ( - <> - - {bpTitle} - - {!hasInformation && ( - - {t('noBpJson')} - - )} - - ) -} - -const BlockProducerProfile = ({ account, ual, ...props }) => { - const { t } = useTranslation('profile') - const classes = useStyles() - const dispatch = useDispatch() - const isDesktop = useMediaQuery('(min-width:767px)') - const isMobile = useMediaQuery('(max-width:768px)') - const accountName = _get(ual, 'activeUser.accountName', null) - const location = useLocation() - const [sizes, setSizes] = useState() - const [isNewRate, setIsNewRate] = useState(true) - const [open, setOpen] = useState(false) - const { - list: blockProducers, - producer, - edenRate, - userRate - } = useSelector((state) => state.blockProducers) - const { isContentLoading } = useSelector((state) => state.isLoading) - const bpHasInformation = Boolean( - producer && Object.values(producer.bpjson).length - ) - const bPLogo = - bpHasInformation && _get(producer, 'bpjson.org.branding.logo_256', null) - - const BlockProducerTitle = _get( - producer, - 'bpjson.org.candidate_name', - _get(producer, 'system.owner', 'No Data') - ) - - const webInfo = _get(producer, 'general_info', null) - - const getRatingData = () => { - if (edenRate) { - return { - community: edenRate.community, - development: edenRate.development, - infrastructure: edenRate.development, - transparency: edenRate.transparency, - trustiness: edenRate.trustiness - } - } - return { - community: 0, - development: 0, - infrastructure: 0, - transparency: 0, - trustiness: 0 - } - } - - const userDataSet = getBPRadarData({ - name: t('edenRates'), - parameters: getRatingData() - }) - - const handleClose = (event, reason) => { - if (reason === 'clickaway') { - return - } - setOpen(false) - } - - function Alert(props) { - return - } - - useEffect(() => { - setSizes(isDesktop ? 400 : '100%') - }, [isDesktop]) - - useEffect(() => { - const getData = async () => { - !blockProducers.length && (await dispatch.blockProducers.getBPs()) - dispatch.blockProducers.getBlockProducerByOwner(account) - dispatch.blockProducers.getBlockProducerEdenRating({ - bp: account - }) - dispatch.blockProducers.getBlockProducerRatingByOwner({ - bp: account, - userAccount: accountName - }) - } - - getData() - }, [account, blockProducers.length]) - - useEffect(() => { - dispatch.blockProducers.setShowSortSelected(false) - }, []) - - useEffect(() => { - if (userRate) setIsNewRate(false) - else setIsNewRate(true) - }, [userRate]) - - useEffect(() => { - if (location.state.transactionId) setOpen(true) - else setOpen(false) - }, []) - - return ( - - - - - - - - - - - {bPLogo ? ( - - - - ) : ( - - )} - - - - {!isMobile && ( - - - - - - - - - )} - - - - - - - - -
- - - {isMobile && ( - - - - - )} - {isMobile && ( - - - - - )} - - - - - - - - - - } - /> - - ) -} - -BlockProducerProfile.propTypes = { - account: PropTypes.string, - ual: PropTypes.object -} - -ProfileTitle.propTypes = { - classes: PropTypes.object, - hasInformation: PropTypes.bool, - producer: PropTypes.object, - t: PropTypes.any, - bpTitle: PropTypes.string, - isContentLoading: PropTypes.bool -} - -export default BlockProducerProfile diff --git a/webapp/src/routes/block-producers/block-producer-rate.js b/webapp/src/routes/block-producers/block-producer-rate.js deleted file mode 100644 index bfaf2018..00000000 --- a/webapp/src/routes/block-producers/block-producer-rate.js +++ /dev/null @@ -1,541 +0,0 @@ -/* eslint-disable react/display-name */ -import React, { useState, useEffect, forwardRef, useRef } from 'react' -import PropTypes from 'prop-types' -import { useTranslation } from 'react-i18next' -import { useDispatch, useSelector } from 'react-redux' -import { Link } from '@reach/router' -import { - useMediaQuery, - Avatar, - Button, - Grid, - CircularProgress, - Typography -} from '@material-ui/core' -import AccountCircle from '@material-ui/icons/AccountCircle' -import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft' -import _get from 'lodash.get' -import classNames from 'classnames' -import Snackbar from '@material-ui/core/Snackbar' -import MuiAlert from '@material-ui/lab/Alert' -import { makeStyles } from '@material-ui/core/styles' -import formatNumber from 'utils/formatNumber' -import Box from '@material-ui/core/Box' - -import TitlePage from 'components/title-page' -import Radar from 'components/radar' -import { contract } from '../../config' -import getBPRadarData from 'utils/getBPRadarData' - -import SliderRatingSection from './slider-rating-section' -import styles from './styles' - -const useStyles = makeStyles(styles) - -const INIT_RATING_STATE_DATA = { - community: 1, - communityEnabled: true, - development: 1, - developmentEnabled: true, - infra: 1, - infraEnabled: true, - transparency: 1, - transparencyEnabled: true, - trustiness: 1, - trustinessEnabled: true, - processing: false, - txError: null, - txSuccess: false -} - -const BlockProducerRate = ({ account, ual }) => { - const [ratingState, setRatingState] = useState(INIT_RATING_STATE_DATA) - const [isNewRate, setIsNewRate] = useState(true) - const [showMessage, setShowMessage] = useState(false) - const [showAlert, setShowAlert] = useState(false) - const linkBack = useRef(null) - const { t } = useTranslation('bpRatePage') - const dispatch = useDispatch() - const { producer, userRate, edenRate } = useSelector( - (state) => state.blockProducers - ) - const { data: user } = useSelector((state) => state.user) - const classes = useStyles() - const accountName = _get(ual, 'activeUser.accountName', null) - const bpData = _get(producer, 'data', {}) - const [lastTransactionId, setLastTransactionId] = useState(undefined) - const isDesktop = useMediaQuery('(min-width:769px)') - const isMobile = useMediaQuery('(max-width:767px)') - const [sizes, setSizes] = useState() - - const handleStateChange = (parameter) => (event, value) => { - setRatingState({ ...ratingState, [parameter]: value }) - } - - const bPLogo = _get(producer, 'bpjson.org.branding.logo_256', null) - - useEffect(() => { - setSizes(isDesktop ? 425 : '100%') - }, [isDesktop]) - - function Alert(props) { - return - } - - const handleClose = (event, reason) => { - if (reason === 'clickaway') { - return - } - - setShowMessage(false) - setRatingState({ - ...ratingState, - processing: false, - txError: null, - txSuccess: false - }) - } - - const handleSetLastTransactionId = (event, reason) => { - linkComponent() - setLastTransactionId(undefined) - } - - const linkComponent = () => { - linkBack.current.click() - } - - useEffect(() => { - const getData = async () => { - if (account) { - dispatch.blockProducers.getBlockProducerByOwner(account) - } - - if (accountName) { - await dispatch.user.getUserChainData({ ual }) - - dispatch.blockProducers.getBlockProducerRatingByOwner({ - bp: account, - userAccount: accountName - }) - setShowMessage(false) - } - } - - getData() - }, [accountName, account, ual, setShowMessage]) - - useEffect(() => { - if (userRate) { - setRatingState({ - ...ratingState, - community: accountName ? userRate.community : 1, - development: accountName ? userRate.development : 1, - infra: accountName ? userRate.infrastructure : 1, - transparency: accountName ? userRate.transparency : 1, - trustiness: accountName ? userRate.trustiness : 1 - }) - setIsNewRate(false) - } else { - setRatingState(INIT_RATING_STATE_DATA) - setIsNewRate(true) - } - }, [userRate, accountName, setRatingState]) - - useEffect(() => { - dispatch.blockProducers.setShowSortSelected(false) - }, []) - - useEffect(() => { - if (user && user.edenMember) { - setShowAlert(false) - } else if (user && (user.hasProxy || user.producersCount >= 21)) { - setShowAlert(false) - } else { - user && setShowAlert(true) - } - }, [user, setShowAlert]) - - const getRatingData = (useString = false) => { - const { - community, - communityEnabled, - development, - developmentEnabled, - infra, - infraEnabled, - transparency, - transparencyEnabled, - trustiness, - trustinessEnabled - } = ratingState - - if (useString) { - return { - community: formatNumber(communityEnabled ? community : 0, 0).toString(), - development: formatNumber( - developmentEnabled ? development : 0, - 0 - ).toString(), - infrastructure: formatNumber(infraEnabled ? infra : 0, 0).toString(), - transparency: formatNumber( - transparencyEnabled ? transparency : 0, - 0 - ).toString(), - trustiness: formatNumber( - trustinessEnabled ? trustiness : 0, - 0 - ).toString() - } - } - - return { - community: communityEnabled ? community : 0, - development: developmentEnabled ? development : 0, - infrastructure: infraEnabled ? infra : 0, - transparency: transparencyEnabled ? transparency : 0, - trustiness: trustinessEnabled ? trustiness : 0 - } - } - - const userDataSet = getBPRadarData({ - name: t('myRate'), - parameters: getRatingData() - }) - - const getEdenRatingData = () => { - if (edenRate) { - return { - community: edenRate.community, - development: edenRate.development, - infrastructure: edenRate.development, - transparency: edenRate.transparency, - trustiness: edenRate.trustiness - } - } - return { - community: 0, - development: 0, - infrastructure: 0, - transparency: 0, - trustiness: 0 - } - } - - const edenDataSet = getBPRadarData({ - name: t('edenRates'), - parameters: getEdenRatingData() - }) - - const transact = async () => { - try { - if (!accountName) { - setShowMessage(true) - - return - } - - const transaction = { - actions: [ - { - authorization: [ - { - actor: accountName, - permission: 'active' - } - ], - account: contract, - name: 'rate', - data: { user: accountName, bp: account, ...getRatingData(true) } - } - ] - } - - setRatingState({ - ...ratingState, - txError: null, - processing: true, - txSuccess: false - }) - - const result = await ual.activeUser.signTransaction(transaction, { - broadcast: true - }) - - await dispatch.blockProducers.saveLastTransaction({ - transaction: { - transactionId: result.transaction.transaction_id, - transactionDate: result.transaction.processed.block_time - } - }) - setLastTransactionId(result.transactionId) - - await dispatch.blockProducers.mutationInsertUserRating({ - ual, - user: accountName, - bp: account, - ...getRatingData(false), - result - }) - - setRatingState({ - ...ratingState, - processing: false, - txSuccess: true - }) - - handleSetLastTransactionId() - } catch (err) { - setRatingState({ - ...ratingState, - processing: false, - txError: err.cause ? err.cause.message : err - }) - } - } - - return ( - - - - - - - - - - - - {bPLogo ? ( - - - - ) : ( - - )} - - {_get(producer, 'bpjson.org.candidate_name') || - _get(producer, 'system.owner', t('noBlockProducer'))} - - - - - - - {t('subTitle')} - - {t('subText')} - {t('helpText')} - {t('rateText')} - {isMobile && ( - - - - )} - - - - - - {t('rateWithoutLogin')} - - - - - {ratingState.txError} - - - - - - - - - - - {!isMobile && ( - - - - )} - - - - - {t('rateWithoutLogin')} - - - - - {ratingState.txError} - - - {ratingState.processing && ( - - )} - - - - - - - - {showAlert && ( - - - {t('infoMessage')} - - - )} - - - ) -} - -BlockProducerRate.propTypes = { - account: PropTypes.string, - ual: PropTypes.object -} - -export default BlockProducerRate diff --git a/webapp/src/routes/block-producers/bottom-sheet-selected-bps.js b/webapp/src/routes/block-producers/bottom-sheet-selected-bps.js deleted file mode 100644 index 10ca0fd5..00000000 --- a/webapp/src/routes/block-producers/bottom-sheet-selected-bps.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import Drawer from '@material-ui/core/Drawer' -import Grid from '@material-ui/core/Grid' -import IconButton from '@material-ui/core/IconButton' -import { makeStyles } from '@material-ui/core/styles' -import CloseIcon from '@material-ui/icons/Close' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const SelectedBpsBottomSheet = ({ open, setOpen, children }) => { - const classesStyle = useStyles() - - return ( - - - - - setOpen(false)}> - - - - - {children} - - ) -} - -SelectedBpsBottomSheet.propTypes = { - open: PropTypes.bool, - setOpen: PropTypes.func, - children: PropTypes.node -} - -export default SelectedBpsBottomSheet diff --git a/webapp/src/routes/block-producers/compare-tool-toggle.js b/webapp/src/routes/block-producers/compare-tool-toggle.js deleted file mode 100644 index 1974ed5c..00000000 --- a/webapp/src/routes/block-producers/compare-tool-toggle.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react' -import { makeStyles } from '@material-ui/core/styles' -import { useDispatch, useSelector } from 'react-redux' -import { useTranslation } from 'react-i18next' -import List from '@material-ui/core/List' -import ListItem from '@material-ui/core/ListItem' -import ListItemText from '@material-ui/core/ListItemText' -import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction' -import VisibilityIcon from '@material-ui/icons/Visibility' -import VisibilityOffIcon from '@material-ui/icons/VisibilityOff' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const CompareToolToggle = () => { - const { t } = useTranslation('translations') - const classes = useStyles() - const { compareTool, selected } = useSelector((state) => state.blockProducers) - const dispatch = useDispatch() - - const handleToggleCompareTool = () => { - dispatch.blockProducers.toggleCompareTool() - } - - return ( - - handleToggleCompareTool()} - > - - - {compareTool ? : } - - - - ) -} - -export default CompareToolToggle diff --git a/webapp/src/routes/block-producers/filter-box.js b/webapp/src/routes/block-producers/filter-box.js deleted file mode 100644 index 3506cc8f..00000000 --- a/webapp/src/routes/block-producers/filter-box.js +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useState, useEffect } from 'react' -import { makeStyles } from '@material-ui/core/styles' -import List from '@material-ui/core/List' -import Typography from '@material-ui/core/Typography' -import ListSubheader from '@material-ui/core/ListSubheader' -import ListItem from '@material-ui/core/ListItem' - -import ParameterRangeSelector from 'components/parameter-range-selector' -import bpParameters from 'config/comparison-parameters' - -const useStyles = makeStyles((theme) => ({ - nested: { - paddingLeft: theme.spacing(2), - color: 'white' - }, - listItem: { - display: 'block' - } -})) - -const FilterBox = () => { - const [parameters, setParameters] = useState() - const classes = useStyles() - - useEffect(() => { - setParameters( - ...bpParameters.reduce( - (result, parameter) => ({ - ...result, - [parameter]: [0, 20] - }), - {} - ) - ) - }, []) - - const handleValueChange = (parameter) => (value) => - setParameters({ - [parameter]: value - }) - - return ( - Filter Parameters} - > - {bpParameters.map((parameter) => ( - - {parameter} - - handleValueChange(parameter)} - /> - - ))} - - ) -} - -export default FilterBox diff --git a/webapp/src/routes/block-producers/index.js b/webapp/src/routes/block-producers/index.js deleted file mode 100644 index ada12bfc..00000000 --- a/webapp/src/routes/block-producers/index.js +++ /dev/null @@ -1,300 +0,0 @@ -import React, { useEffect, useState, useRef } from 'react' -import PropTypes from 'prop-types' -import { useDispatch, useSelector } from 'react-redux' -import Grid from '@material-ui/core/Grid' -import Button from '@material-ui/core/Button' -import Typography from '@material-ui/core/Typography' -import ThumbUpAltIcon from '@material-ui/icons/ThumbUpAlt' -import { makeStyles } from '@material-ui/core/styles' -import { useTranslation } from 'react-i18next' -import classNames from 'classnames' -import _get from 'lodash.get' - -import TitlePage from 'components/title-page' -import CompareTool from 'components/compare-tool' -import getAverageValue from 'utils/getAverageValue' -import { useMediaQuery } from '@material-ui/core' -import applySortBy from 'utils/sortedBy' -import Card from 'components/card' - -import styles from './styles' -import SelectedBpsBottomSheet from './bottom-sheet-selected-bps' - -const useStyles = makeStyles(styles) - -const AllBps = ({ ual }) => { - const { t } = useTranslation('translations') - const dispatch = useDispatch() - const classes = useStyles() - const myRef = useRef(null) - const [currentlyVisible, setCurrentlyVisible] = useState(30) - const [openVoteDrawer, setOpenVoteDrawer] = useState(false) - const { data: user } = useSelector((state) => state.user) - const isDesktop = useMediaQuery('(min-width:600px)', { - defaultMatches: false - }) - const isTablet = useMediaQuery('(max-width:1024px)', { - defaultMatches: false - }) - const [openDesktopVotingTool, setOpenDesktopVotingTool] = useState(isDesktop) - const { - list: blockProducers, - selected: selectedBPs, - compareTool: compareToolVisible, - sortBy - } = useSelector((state) => state.blockProducers) - - const [ratingState, setRatingState] = useState({ - txError: null, - txSuccess: false, - showChipMessage: false - }) - const sortedBPs = applySortBy(sortBy, blockProducers) - const shownList = sortedBPs && sortedBPs.slice(0, currentlyVisible) - const hasMore = blockProducers && currentlyVisible < blockProducers.length - const accountName = _get(ual, 'activeUser.accountName', null) - - const loadMore = () => setCurrentlyVisible(currentlyVisible + 12) - const goToTop = () => document.getElementById('mainContent').scrollTo(0, 0) - - const handleToggleCompareTool = () => { - dispatch.blockProducers.toggleCompareTool() - } - - const handleToggleSelected = (item, isAddItem = false) => { - if (isAddItem) { - dispatch.blockProducers.addToSelected(item) - } else { - dispatch.blockProducers.removeSelected(item) - } - } - - const handleOpenDesktopVotingTool = (value) => { - goToTop() - setOpenDesktopVotingTool(value) - } - - const handleOnClear = () => { - handleToggleCompareTool() - dispatch.blockProducers.clearSelected() - setOpenDesktopVotingTool(false) - } - - const handleOnClose = () => { - setOpenDesktopVotingTool(false) - } - - const handleSetRatingState = () => { - setRatingState({ - ...ratingState, - txError: null, - txSuccess: false, - showChipMessage: false - }) - } - - const handleSetIsNewRate = (owner) => { - if (user) { - for (const userRate of user.userRates) { - if (userRate.owner === owner) { - return true - } - } - return false - } - } - - const sendVoteBps = async (BPs) => { - if (!accountName) return - - const transaction = { - actions: [ - { - account: 'eosio', - name: 'voteproducer', - authorization: [ - { - actor: accountName, - permission: 'active' - } - ], - data: { - voter: accountName, - proxy: '', - producers: BPs.sort() - } - } - ] - } - - try { - dispatch.isLoading.storeIsContentLoading(true) - - await ual.activeUser.signTransaction(transaction, { - broadcast: true - }) - - setRatingState({ - ...ratingState, - txSuccess: true, - showChipMessage: true - }) - - dispatch.isLoading.storeIsContentLoading(false) - - setTimeout(() => { - setRatingState({ - ...ratingState, - txError: null, - txSuccess: false, - showChipMessage: false - }) - }, 2000) - } catch (error) { - console.warn(error) - - setRatingState({ - ...ratingState, - txError: error && error.cause ? error.cause.message : error, - showChipMessage: true - }) - dispatch.isLoading.storeIsContentLoading(false) - } - } - - const cmprTool = () => ( - sendVoteBps(selectedBPs || [])} - userInfo={user} - message={ratingState} - setMessage={handleSetRatingState} - handleOnClose={handleOnClose} - handleOnClear={handleOnClear} - /> - ) - - useEffect(() => { - const getData = async () => { - !blockProducers.length && (await dispatch.blockProducers.getBPs()) - } - - getData() - }, [blockProducers.length]) - - useEffect(() => { - const getUserData = async () => { - if (ual.activeUser && !user) { - await dispatch.user.getUserChainData({ ual }) - } - } - - dispatch.blockProducers.setShowSortSelected(true) - getUserData() - }, [user, ual.activeUser, ual]) - - return ( -
- - {isDesktop && openDesktopVotingTool && cmprTool()} - - {(shownList || []).map((blockProducer) => ( - - () => { - if (isAdding) { - if (!(selectedBPs || []).length && !compareToolVisible) { - handleToggleCompareTool() - } - - handleToggleSelected(producerAccountName, isAdding) - } else { - if ((selectedBPs || []).length === 1 && compareToolVisible) { - handleToggleCompareTool() - } - - handleToggleSelected(producerAccountName, isAdding) - } - }} - data={blockProducer} - imageURL={_get(blockProducer, 'bpjson.org.branding.logo_256')} - owner={_get(blockProducer, 'owner')} - title={_get(blockProducer, 'bpjson.org.candidate_name')} - pathLink='block-producers' - buttonLabel={t('addToVote')} - average={getAverageValue(_get(blockProducer, 'average', 0))} - rate={_get(blockProducer, 'ratings_cntr', 0)} - isNewRate={handleSetIsNewRate(blockProducer.owner)} - /> - - ))} - - {selectedBPs && selectedBPs.length > 0 && ( - - - - - - )} - - {cmprTool()} - - -
- ) -} - -AllBps.propTypes = { - ual: PropTypes.object -} - -export default AllBps - -export const blockProducersDrawer = [ - { value: 'alphabetical' }, - { value: 'generalRate' }, - { value: 'edenRate' }, - { value: 'infrastructure' }, - { value: 'community' }, - { value: 'trustiness' }, - { value: 'development' }, - { value: 'transparency' }, - { value: 'vote' }, - { value: 'ratings' } -] diff --git a/webapp/src/routes/help/index.js b/webapp/src/routes/help/index.js deleted file mode 100644 index 3516becf..00000000 --- a/webapp/src/routes/help/index.js +++ /dev/null @@ -1,78 +0,0 @@ -import React from 'react' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/styles' -import { useTranslation } from 'react-i18next' -import Grid from '@material-ui/core/Grid' -import Box from '@material-ui/core/Box' -import classNames from 'classnames' -import Link from '@material-ui/core/Link' -import HttpIcon from '@material-ui/icons/Http' -import TelegramIcon from '@material-ui/icons/Telegram' -import GitHubIcon from '@material-ui/icons/GitHub' - -import TitlePage from 'components/title-page' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const Help = () => { - const classes = useStyles() - const { t } = useTranslation('help') - - return ( - - - - - - {t('title')} - - {t('paragraph')} - - - - - - {t('githubEOSCR')} - - - - - - {t('telegramChannel')} - - - - - - {t('websiteEOSCR')} - - - - - - - ) -} - -export default Help diff --git a/webapp/src/routes/home/cover.js b/webapp/src/routes/home/cover.js deleted file mode 100644 index 22a8f27f..00000000 --- a/webapp/src/routes/home/cover.js +++ /dev/null @@ -1,131 +0,0 @@ -import React, { forwardRef, useState, useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import Typography from '@material-ui/core/Typography' -import Button from '@material-ui/core/Button' -import { useMediaQuery } from '@material-ui/core' -import Grid from '@material-ui/core/Grid' -import { makeStyles } from '@material-ui/core/styles' -import { Link } from '@reach/router' -import PropTypes from 'prop-types' - -import Radar from 'components/radar' - -import styles from './styles' - -// eslint-disable-next-line react/display-name -const bpLink = forwardRef((props, ref) => ) -const useStyles = makeStyles(styles) - -const HomeCover = ({ blockProducer }) => { - const { t } = useTranslation('home') - const classes = useStyles() - const isDesktop = useMediaQuery('(min-width:769px)') - const isTablet = useMediaQuery('(min-width:540px)') - const isBigTablet = useMediaQuery('(max-width:1023px)') - const [sizes, setSizes] = useState() - - useEffect(() => { - setSizes(isDesktop ? 400 : '95%') - }, [isDesktop]) - - return ( - - - - {t('cover.title')} - - - {!isDesktop && ( - - - - - - - - - )} - - - {t('cover.paragraph.subtitle1')} - - - {t('cover.paragraph.text1')} - - - {t('cover.paragraph.text2')} - - - {t('cover.paragraph.subtitle2')} - - - {t('cover.paragraph.text3')} - - - {t('cover.paragraph.text4')} - - {isDesktop && ( -
- -
- )} -
- {isDesktop && ( - -
- -
-
- )} -
- ) -} - -HomeCover.propTypes = { - blockProducer: PropTypes.object.isRequired -} - -export default HomeCover diff --git a/webapp/src/routes/home/index.js b/webapp/src/routes/home/index.js deleted file mode 100644 index f787218a..00000000 --- a/webapp/src/routes/home/index.js +++ /dev/null @@ -1,82 +0,0 @@ -import React, { useEffect } from 'react' -import { makeStyles } from '@material-ui/core/styles' -import { useTranslation } from 'react-i18next' -import { useDispatch, useSelector } from 'react-redux' -import Grid from '@material-ui/core/Grid' -import classNames from 'classnames' - -import TitlePage from 'components/title-page' - -import styles from './styles' -import Cover from './cover' -import SubTopic from './subTopic' -import RateCategory from './rateCategory' - -const useStyles = makeStyles(styles) - -const Home = () => { - const { t } = useTranslation('home') - const classes = useStyles() - const dispatch = useDispatch() - const { blockProducer } = useSelector((state) => state.home) - - useEffect(() => { - dispatch.home.getBlockData() - }, []) - - useEffect(() => { - dispatch.blockProducers.setShowSortSelected(false) - }) - - return ( - <> - - - - {blockProducer && ( - - - - )} - - - - {blockProducer && ( - - - - )} - - - - - - - - - - ) -} - -export default Home diff --git a/webapp/src/routes/home/styles.js b/webapp/src/routes/home/styles.js deleted file mode 100644 index e1325eb5..00000000 --- a/webapp/src/routes/home/styles.js +++ /dev/null @@ -1,91 +0,0 @@ -export default (theme) => ({ - spacingContainers: { - padding: theme.spacing(8, 2), - [theme.breakpoints.down('sm')]: { - padding: theme.spacing(6, 2) - } - }, - mainCoverContainer: { - backgroundColor: theme.palette.surface.main - }, - mainSubTopicContainer: { - backgroundColor: theme.palette.surface.main - }, - rateCategoryContainer: { - backgroundColor: '#f5f5f5' - }, - coverContainer: { - padding: 0, - color: '#433F5B', - maxWidth: '1024px', - backgroundColor: theme.palette.surface.main - }, - coverTitle: { - marginBottom: 12.5, - [theme.breakpoints.down('sm')]: { - fontSize: '2.03rem', - marginBottom: 0 - } - }, - ctaContainer: { - textAlign: 'center' - }, - chartContainer: { - maxWidth: '400px', - width: '100%', - display: 'flex', - alignItems: 'center' - }, - subtitle: { - marginBottom: theme.spacing(1) - }, - leftCoverBox: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between' - }, - ratingContainer: { - maxWidth: '1024px' - }, - ratingTitle: { - fontSize: theme.typography.h4.fontSize, - display: 'flex', - marginBottom: 12.5 - }, - paragraph: { - marginLeft: theme.spacing(4.5) - }, - subTitleContainer: { - display: 'flex', - alignItems: 'center', - paddingTop: 6 - }, - iconStyle: { - marginRight: theme.spacing(2), - marginTop: theme.spacing(1), - color: '#433F5B' - }, - subTopicContainer: { - maxWidth: '1024px' - }, - title: { - fontSize: theme.typography.h4.fontSize, - color: theme.palette.grey[600], - marginBottom: 12.5 - }, - ratingParagraph: { - color: theme.palette.grey[600] - }, - topicSubtitle: { - marginBottom: theme.spacing(1), - color: theme.palette.grey[600] - }, - gridContent: { - padding: '2%' - }, - link: { - color: theme.palette.grey[600], - fontWeight: '500', - textDecoration: 'none' - } -}) diff --git a/webapp/src/routes/index.js b/webapp/src/routes/index.js index c33dc5b8..2061d0a5 100644 --- a/webapp/src/routes/index.js +++ b/webapp/src/routes/index.js @@ -1,82 +1,119 @@ -import Home from './home' -import Account from './account' -import BlockProducerProfile from './block-producers/block-producer-profile' -import BlockProducerRate from './block-producers/block-producer-rate' -import AllBps, { blockProducersDrawer } from './block-producers' -import AllProxies, { proxiesDrawer } from './proxies' -import ProxyProfile from './proxies/proxy-profile' -import Help from './help' -import TermsOfUse from './termsOfUse' -import About from './about' -import { networkMonitor } from '../config' +// eslint-disable-next-line no-unused-vars +import React, { lazy } from 'react' +import { + Activity as ActivityIcon, + Grid as GridIcon, + Home as HomeIcon, + Server as ServerIcon, + FileText as FileTextIcon, + User as UserIcon, + Info as InfoIcon, + HelpCircle as HelpIcon, + GitMerge as GitMergeIcon +} from 'react-feather' -export default [ +import { mainConfig } from '../config' + +const Home = lazy(() => import('./Home')) +const BlockProducers = lazy(() => import('./BlockProducers')) +const BlockProducerProfile = lazy(() => + import('./BlockProducers/BlockProducerProfile') +) +const BlockProducerRate = lazy(() => + import('./BlockProducers/BlockProducerRate') +) +const Proxies = lazy(() => import('./Proxies')) +const ProxyProfile = lazy(() => import('./Proxies/ProxyProfile')) +const About = lazy(() => import('./About')) +const Help = lazy(() => import('./Help')) +const Page404 = lazy(() => import('./Route404')) +const TermsOfUse = lazy(() => import('./TermsOfUse')) +const Account = lazy(() => import('./Account')) + +const routes = [ { + name: 'home', + icon: , + component: Home, path: '/', - Component: Home, - drawerLabel: 'drawerLinkHome', - target: '_self' + exact: true }, { - path: '/block-producers', - Component: AllBps, - drawerLabel: 'drawerLinkAllBPs', - drawerComponents: blockProducersDrawer, - target: '_self' + name: 'myAccount', + icon: , + path: '/account', + component: Account, + exact: true }, { - path: 'block-producers/:account', - Component: BlockProducerProfile, - target: '_self' + name: 'blockProducers', + icon: , + component: BlockProducers, + path: '/block-producers', + exact: true }, { - path: 'block-producers/:account/rate', - Component: BlockProducerRate, - target: '_self' + path: '/block-producers/:account', + component: BlockProducerProfile, + exact: true }, { - path: '/proxies', - Component: AllProxies, - drawerLabel: 'drawerLinkAllProxies', - drawerComponents: proxiesDrawer, - target: '_self' + path: '/block-producers/:account/rate', + component: BlockProducerRate, + exact: true }, { - path: 'proxies/:account', - Component: ProxyProfile, - target: '_self' + path: '/proxies', + icon: , + component: Proxies, + name: 'proxies', + exact: true }, { - path: '/account', - Component: Account, - target: '_self' + path: '/proxies/:account', + component: ProxyProfile, + exact: true }, { - path: networkMonitor, - drawerLabel: 'drawerLinkNetworkMonitor', + path: mainConfig.networkMonitor, + icon: , + name: 'networkMonitor', target: '_blank' }, { + name: 'about', + icon: , + component: About, path: '/about', - Component: About, - drawerLabel: 'drawerLinkAbout', - target: '_self' + exact: true }, { path: '/ricardian-contract', - Component: TermsOfUse, - drawerLabel: 'drawerLinkRicardianContract', - target: '_self' + component: TermsOfUse, + icon: , + name: 'ricardianContract', + exact: true }, { + name: 'help', + icon: , + component: Help, path: '/help', - Component: Help, - drawerLabel: 'drawerLinkHelp', - target: '_self' + exact: true }, { - path: 'https://github.com/eoscostarica/eos-rate/releases', - drawerLabel: 'version', + name: 'version', + badge: mainConfig.appVersion, + path: 'https://github.com/eoscostarica/full-stack-boilerplate/tags', + icon: , target: '_blank' + }, + { + component: Page404 } ] + +export default () => ({ + sidebar: routes.filter(route => !!route.name), + browser: routes.filter(route => !!route.component) +}) diff --git a/webapp/src/routes/not-found/index.js b/webapp/src/routes/not-found/index.js deleted file mode 100644 index 96135dbe..00000000 --- a/webapp/src/routes/not-found/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import React, { forwardRef } from 'react' -import { useTranslation } from 'react-i18next' -import { makeStyles } from '@material-ui/core/styles' -import Typography from '@material-ui/core/Typography' -import Button from '@material-ui/core/Button' -import { Link } from '@reach/router' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const NotFound = () => { - const { t } = useTranslation('not-found') - const classes = useStyles() - - return ( -
-
-
- 404 - {t('graphic')} -
- - {t('description')} - - -
-
- ) -} - -export default NotFound diff --git a/webapp/src/routes/not-found/styles.js b/webapp/src/routes/not-found/styles.js deleted file mode 100644 index 48b37ef0..00000000 --- a/webapp/src/routes/not-found/styles.js +++ /dev/null @@ -1,43 +0,0 @@ -export default (theme) => ({ - root: { - width: '100%', - height: 'calc(100vh - 128px)', - display: 'flex', - alignItems: 'center', - flexDirection: 'column', - justifyContent: 'space-around' - }, - container: { - margin: theme.spacing(2), - height: '100%', - width: '50%', - background: theme.palette.primary.sectionBackground, - display: 'flex', - alignItems: 'center', - flexDirection: 'column', - '& > *': { - marginTop: theme.spacing(4) - } - }, - graphic: { - borderRadius: '50%', - background: theme.palette.primary.dark, - color: 'white', - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - width: '200px', - height: '200px', - '& > span': { - fontWeight: '600', - lineHeight: 1 - }, - '& > span:first-child': { - fontSize: '4rem' - }, - '& > span:nth-child(2)': { - fontSize: '1.8rem' - } - } -}) diff --git a/webapp/src/routes/proxies/compare-tool-toggle.js b/webapp/src/routes/proxies/compare-tool-toggle.js deleted file mode 100644 index a6477efb..00000000 --- a/webapp/src/routes/proxies/compare-tool-toggle.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react' -import { makeStyles } from '@material-ui/core/styles' -import { useDispatch, useSelector } from 'react-redux' -import { useTranslation } from 'react-i18next' -import List from '@material-ui/core/List' -import ListItem from '@material-ui/core/ListItem' -import ListItemText from '@material-ui/core/ListItemText' -import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction' -import VisibilityIcon from '@material-ui/icons/Visibility' -import VisibilityOffIcon from '@material-ui/icons/VisibilityOff' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const CompareToolToggle = () => { - const { t } = useTranslation('translations') - const classes = useStyles() - const dispatch = useDispatch() - const { compareTool, selected } = useSelector((state) => state.blockProducers) - - const handleToggleCompareTool = () => { - dispatch.blockProducers.toggleCompareTool() - } - - return ( - - handleToggleCompareTool()} - > - - - {compareTool ? : } - - - - ) -} - -export default CompareToolToggle diff --git a/webapp/src/routes/proxies/filter-box.js b/webapp/src/routes/proxies/filter-box.js deleted file mode 100644 index 8a987362..00000000 --- a/webapp/src/routes/proxies/filter-box.js +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useState, useEffect } from 'react' -import { makeStyles } from '@material-ui/core/styles' -import List from '@material-ui/core/List' -import Typography from '@material-ui/core/Typography' -import ListSubheader from '@material-ui/core/ListSubheader' -import ListItem from '@material-ui/core/ListItem' - -import ParameterRangeSelector from 'components/parameter-range-selector' -import bpParameters from 'config/comparison-parameters' - -const useStyles = makeStyles((theme) => ({ - nested: { - paddingLeft: theme.spacing(2), - color: 'white' - }, - listItem: { - display: 'block' - } -})) - -const FilterBox = () => { - const [parameters, setParameters] = useState() - const classes = useStyles() - - useEffect(() => { - setParameters( - ...bpParameters.reduce( - (result, parameter) => ({ - ...result, - [parameter]: [0, 20] - }), - {} - ) - ) - }, []) - - const handleValueChange = (parameter) => (value) => - setState({ - [parameter]: value - }) - - return ( - Filter Parameters} - > - {bpParameters.map((parameter) => ( - - {parameter} - - handleValueChange(parameter)} - /> - - ))} - - ) -} - -export default FilterBox diff --git a/webapp/src/routes/proxies/index.js b/webapp/src/routes/proxies/index.js deleted file mode 100644 index b8c51ae0..00000000 --- a/webapp/src/routes/proxies/index.js +++ /dev/null @@ -1,245 +0,0 @@ -import React, { useEffect, useState } from 'react' -import PropTypes from 'prop-types' -import { useDispatch, useSelector } from 'react-redux' -import Grid from '@material-ui/core/Grid' -import Button from '@material-ui/core/Button' -import { useMediaQuery } from '@material-ui/core' -import { makeStyles } from '@material-ui/core/styles' -import { useTranslation } from 'react-i18next' -import classNames from 'classnames' -import _get from 'lodash.get' - -import TitlePage from 'components/title-page' -import Card from 'components/card' -import CompareTool from 'components/compare-tool' - -import styles from './styles' -import SelectedBpsBottomSheet from './../block-producers/bottom-sheet-selected-bps' - -const useStyles = makeStyles(styles) - -const AllProxies = ({ ual }) => { - const { t } = useTranslation('translations') - const classes = useStyles() - const dispatch = useDispatch() - const { data: user } = useSelector((state) => state.user) - const { - compareTool: compareToolVisible, - selected: selectedProxies, - filtered, - proxies - } = useSelector((state) => state.proxies) - const [currentlyVisible, setCurrentlyVisible] = useState(30) - const proxiesList = filtered && filtered.length ? filtered : proxies - const shownList = proxiesList && proxiesList.slice(0, currentlyVisible) - const hasMore = proxiesList && currentlyVisible < proxiesList.length - const isDesktop = useMediaQuery('(min-width:600px)') - const isTablet = useMediaQuery('(max-width:1024px)', { - defaultMatches: false - }) - const accountName = _get(ual, 'activeUser.accountName', null) - const [openVoteDrawer, setOpenVoteDrawer] = useState(false) - const [openDesktopVotingTool, setOpenDesktopVotingTool] = useState(isDesktop) - const [ratingState, setRatingState] = useState({ - processing: false, - txError: null, - txSuccess: false - }) - - const loadMore = () => setCurrentlyVisible(currentlyVisible + 12) - const goToTop = () => document.getElementById('mainContent').scrollTo(0, 0) - - const handleToggleCompareTool = () => { - dispatch.proxies.toggleCompareTool() - } - - const handleToggleSelected = (item, isAddItem = false) => { - if (isAddItem) { - dispatch.proxies.addToSelected(item) - } else { - dispatch.proxies.removeSelected(item) - } - } - - const handleOnClose = () => { - setOpenDesktopVotingTool(false) - } - - const handleOpenDesktopVotingTool = ( - isAdding, - producerAccountName, - value - ) => { - if (isAdding) { - if (!(selectedProxies || []).length && !compareToolVisible) - handleToggleCompareTool() - handleToggleSelected(producerAccountName, isAdding) - isDesktop ? setOpenDesktopVotingTool(value) : setOpenVoteDrawer(value) - goToTop() - } else if (!isAdding) { - if ((selectedProxies || []).length === 1 && compareToolVisible) - handleToggleCompareTool() - handleToggleSelected() - } - } - - const handleSetRatingState = () => { - setRatingState({ - ...ratingState, - txError: null, - txSuccess: false, - showChipMessage: false - }) - } - - const sendVoteProxy = async () => { - if (!accountName) return - - const transaction = { - actions: [ - { - account: 'eosio', - name: 'voteproducer', - authorization: [ - { - actor: accountName, - permission: 'active' - } - ], - data: { - voter: accountName, - proxy: selectedProxies[0], - producers: [] - } - } - ] - } - - try { - setRatingState({ - ...ratingState, - txError: null, - processing: true, - txSuccess: false - }) - - await ual.activeUser.signTransaction(transaction, { - broadcast: true - }) - - setRatingState({ - ...ratingState, - processing: false, - txSuccess: true - }) - - setTimeout(() => { - setRatingState({ - ...ratingState, - txError: null, - txSuccess: false - }) - }, 2000) - } catch (error) { - console.warn(error) - setRatingState({ - ...ratingState, - processing: false, - txError: error.message ? error.message : error - }) - } - } - - const cmprTool = () => ( - { - handleToggleCompareTool() - handleToggleSelected() - }} - handleOnClose={handleOnClose} - /> - ) - - useEffect(() => { - const getData = async () => { - await dispatch.blockProducers.getBPs() - await dispatch.proxies.getProxies() - } - - getData() - }, []) - - useEffect(() => { - const getUserData = async () => { - if (ual.activeUser && !user) { - await dispatch.user.getUserChainData({ ual }) - } - } - - dispatch.blockProducers.setShowSortSelected(false) - getUserData() - }, [user, ual.activeUser, ual]) - - return ( -
- - {isDesktop && openDesktopVotingTool && cmprTool()} - - {(shownList || []).map((proxy) => ( - - - - ))} - - - {cmprTool()} - - -
- ) -} - -AllProxies.propTypes = { - ual: PropTypes.object -} - -export default AllProxies - -export const proxiesDrawer = [] diff --git a/webapp/src/routes/proxies/proxy-profile.js b/webapp/src/routes/proxies/proxy-profile.js deleted file mode 100644 index d08de354..00000000 --- a/webapp/src/routes/proxies/proxy-profile.js +++ /dev/null @@ -1,310 +0,0 @@ -import React, { useEffect, forwardRef, useState } from 'react' -import PropTypes from 'prop-types' -import { useDispatch, useSelector } from 'react-redux' -import classNames from 'classnames' -import { useTranslation } from 'react-i18next' -import { Link } from '@reach/router' -import CircularProgress from '@material-ui/core/CircularProgress' -import Avatar from '@material-ui/core/Avatar' -import Button from '@material-ui/core/Button' -import Grid from '@material-ui/core/Grid' -import { Box, useMediaQuery } from '@material-ui/core' -import Typography from '@material-ui/core/Typography' -import { makeStyles } from '@material-ui/core/styles' -import Snackbar from '@material-ui/core/Snackbar' -import MuiAlert from '@material-ui/lab/Alert' -import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft' -import AccountCircle from '@material-ui/icons/AccountCircle' -import _get from 'lodash.get' - -import TitlePage from 'components/title-page' -import CompareTool from 'components/compare-tool' -import Radar from 'components/radar' -import { - SocialNetworks, - GeneralInformation -} from './general-information-profile' - -import styles from './styles' - -const useStyles = makeStyles(styles) - -const ProxyProfile = ({ account, ual, ...props }) => { - const { t } = useTranslation('profile') - const classes = useStyles() - const dispatch = useDispatch() - const { proxy } = useSelector((state) => state.proxies) - const [showMessage, setShowMessage] = useState(false) - const isDesktop = useMediaQuery('(min-width:767px)') - const isMobile = useMediaQuery('(max-width:768px)') - const [openDesktopVotingTool, setOpenDesktopVotingTool] = useState(isDesktop) - const [sizes, setSizes] = useState() - const [ratingState, setRatingState] = useState({ - processing: false, - txError: null, - txSuccess: false - }) - const logo = _get(proxy, 'logo_256', null) - const ProxyTitle = _get(proxy, 'name', _get(proxy, 'owner', 'No Data')) - const accountName = _get(ual, 'activeUser.accountName', null) - const slogan = _get(proxy, 'slogan', null) - const producers = _get(proxy, 'voter_info.producers', []) - - const sendVoteProxy = async (proxy) => { - if (!accountName) { - setShowMessage(true) - - return - } - - const transaction = { - actions: [ - { - account: 'eosio', - name: 'voteproducer', - authorization: [ - { - actor: accountName, - permission: 'active' - } - ], - data: { - voter: accountName, - proxy, - producers: [] - } - } - ] - } - - try { - setRatingState({ - ...ratingState, - txError: null, - processing: true, - txSuccess: false - }) - - await ual.activeUser.signTransaction(transaction, { - broadcast: true - }) - - setRatingState({ - ...ratingState, - processing: false, - txSuccess: true - }) - - setTimeout(() => { - setRatingState({ - ...ratingState, - txError: null, - txSuccess: false - }) - }, 2000) - setShowMessage(false) - } catch (error) { - console.warn(error) - setRatingState({ - ...ratingState, - processing: false, - txError: error.message ? error.message : error - }) - } - } - - function Alert(props) { - return - } - - const handleClose = (event, reason) => { - if (reason === 'clickaway') { - return - } - - setShowMessage(false) - setRatingState({ - ...ratingState, - processing: false, - txError: null, - txSuccess: false - }) - } - - const handleOnClose = () => { - setOpenDesktopVotingTool(false) - } - - useEffect(() => { - const getData = async () => { - await dispatch.proxies.getProxies() - await dispatch.proxies.getProxyByOwner(account) - } - - if (accountName) setShowMessage(false) - - getData() - }, [account, accountName, setShowMessage]) - - useEffect(() => { - setSizes(isDesktop ? 400 : '95%') - }, [isDesktop]) - - return ( - - - - - - - - - - - {logo ? ( - - - - ) : ( - - )} - - {ProxyTitle} - - - {slogan && ( - -
{slogan}
-
- )} -
- {isMobile && ( - - - - - - - - - )} - - - - - - {t('voteWithoutLogin')} - - - - - {ratingState.txError} - - - - - {t('success')} - - - {ratingState.processing && ( -
- - - {t('voting')} ... - -
- )} -
- -
- {!isMobile && ( - - - - - - - - - )} - - {proxy && openDesktopVotingTool && Boolean(producers.length) && ( - console.log('remove')} - className={classes.compareTool} - list={[proxy]} - selected={[account]} - isProxy - useOnlySliderView - optionalLabel={`${ProxyTitle} ${t('labelTool')}:`} - handleOnClose={handleOnClose} - /> - )} - -
-
- ) -} - -ProxyProfile.propTypes = { - account: PropTypes.string, - ual: PropTypes.object -} - -export default ProxyProfile diff --git a/webapp/src/routes/settings/index.js b/webapp/src/routes/settings/index.js deleted file mode 100644 index 8f8502b9..00000000 --- a/webapp/src/routes/settings/index.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useState, useEffect } from 'react' -import PropTypes from 'prop-types' -import { makeStyles } from '@material-ui/core/styles' -import { useDispatch, useSelector } from 'react-redux' -import List from '@material-ui/core/List' -import ListItem from '@material-ui/core/ListItem' -import ListItemIcon from '@material-ui/core/ListItemIcon' -import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction' -import ListItemText from '@material-ui/core/ListItemText' -import { useTranslation } from 'react-i18next' -import Typography from '@material-ui/core/Typography' -import Switch from '@material-ui/core/Switch' -import Language from '@material-ui/icons/Language' -import NotificationsIcon from '@material-ui/icons/Notifications' - -const useStyles = makeStyles((theme) => ({ - root: { - padding: theme.spacing(3) - } -})) - -const Settings = ({ i18n }) => { - const { t } = useTranslation('translations') - const classes = useStyles() - const { language, notifications } = useSelector((state) => state.settings) - const dispatch = useDispatch() - - const handleToggle = (value, currentValue) => () => { - if (value === 'language') { - if (currentValue === 'en' || 'ko' ) - const lang = 'es' - else if (currentValue === 'es' || 'ko') - const lang = 'en' - - i18n.changeLanguage(lang) - localStorage.setItem('LANGUAGE', lang) - dispatch.settings.setSettings({ key: value, value: lang }) - } else if (value === 'notifications') - dispatch.settings.setSettings({ key: value, value: !currentValue }) - } - - return ( -
- - {t('settingsTitle')} - - - - - - - - - handleToggle('language', language)} - checked={language === 'en'} - /> - - - - - - - - - handleToggle('notifications', notifications)} - checked={notifications} - /> - - - -
- ) -} - -Settings.propTypes = { - i18n: PropTypes.object.isRequired -} - -export default Settings diff --git a/webapp/src/routes/settings/styles.js b/webapp/src/routes/settings/styles.js deleted file mode 100644 index a8f7391c..00000000 --- a/webapp/src/routes/settings/styles.js +++ /dev/null @@ -1,5 +0,0 @@ -export default (theme) => ({ - root: { - padding: theme.spacing(3) - } -}) diff --git a/webapp/src/routes/termsOfUse/styles.js b/webapp/src/routes/termsOfUse/styles.js deleted file mode 100644 index 157eaebc..00000000 --- a/webapp/src/routes/termsOfUse/styles.js +++ /dev/null @@ -1,8 +0,0 @@ -export default (theme) => ({ - root: { - padding: theme.spacing(3), - '& a': { - lineBreak: 'anywhere' - } - } -}) diff --git a/webapp/src/serviceWorker.js b/webapp/src/serviceWorker.js index b6dce8c0..c1057e91 100644 --- a/webapp/src/serviceWorker.js +++ b/webapp/src/serviceWorker.js @@ -1,12 +1,15 @@ -// In production, we register a service worker to serve assets from local cache. +/* eslint-disable */ +// This optional code is used to register a service worker. +// register() is not called by default. // This lets the app load faster on subsequent visits in production, and gives // it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on the "N+1" visit to a page, since previously -// cached resources are updated in the background. +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. -// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. -// This link also includes instructions on opting out of this behavior. +// To learn more about the benefits of this model and instructions on how to +// opt-in, read http://bit.ly/CRA-PWA const isLocalhost = Boolean( window.location.hostname === 'localhost' || @@ -21,11 +24,11 @@ const isLocalhost = Boolean( export function register(config) { if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location) + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href) if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + // serve assets see https://github.com/facebook/create-react-app/issues/2374 return } @@ -41,11 +44,11 @@ export function register(config) { navigator.serviceWorker.ready.then(() => { console.log( 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://goo.gl/SC7cgQ' + 'worker. To learn more, visit http://bit.ly/CRA-PWA' ) }) } else { - // Is not local host. Just register service worker + // Is not localhost. Just register service worker registerValidSW(swUrl, config) } }) @@ -58,17 +61,22 @@ function registerValidSW(swUrl, config) { .then((registration) => { registration.onupdatefound = () => { const installingWorker = registration.installing + if (installingWorker == null) { + return + } installingWorker.onstatechange = () => { if (installingWorker.state === 'installed') { if (navigator.serviceWorker.controller) { - // At this point, the old content will have been purged and - // the fresh content will have been added to the cache. - // It's the perfect time to display a "New content is - // available; please refresh." message in your web app. - console.log('New content is available; please refresh.') + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' + ) // Execute callback - if (config.onUpdate) { + if (config && config.onUpdate) { config.onUpdate(registration) } } else { @@ -78,7 +86,7 @@ function registerValidSW(swUrl, config) { console.log('Content is cached for offline use.') // Execute callback - if (config.onSuccess) { + if (config && config.onSuccess) { config.onSuccess(registration) } } @@ -96,9 +104,10 @@ function checkValidServiceWorker(swUrl, config) { fetch(swUrl) .then((response) => { // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type') if ( response.status === 404 || - response.headers.get('content-type').indexOf('javascript') === -1 + (contentType != null && contentType.indexOf('javascript') === -1) ) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then((registration) => { diff --git a/webapp/src/services/api.js b/webapp/src/services/api.js deleted file mode 100644 index e9c1eae0..00000000 --- a/webapp/src/services/api.js +++ /dev/null @@ -1,44 +0,0 @@ -import qs from 'qs' -import store from '../store' - -const http = (method) => (endpoint, body, options = {}) => { - const token = store.getState().session - ? store.getState().session.accessToken - : null - - const params = { - method, - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - } - } - - if (token) { - params.headers.Authorization = `Bearer ${token}` - } - - if (body) { - if (method === 'GET') { - endpoint = `${endpoint}?${qs.stringify(body)}` - } else { - params.body = JSON.stringify(body) - } - } - - return fetch(`${process.env.REACT_APP_EOS_API_URL}/${endpoint}`, params) - .then((response) => - response.json().then((payload) => ({ payload, response })) - ) - .then(({ response, payload }) => - response.ok ? payload : Promise.reject(payload) - ) -} - -export default { - get: http('GET'), - post: http('POST'), - put: http('PUT'), - patch: http('PATCH'), - delete: http('DELETE') -} diff --git a/webapp/src/services/bps.js b/webapp/src/services/bps.js deleted file mode 100644 index 2371b499..00000000 --- a/webapp/src/services/bps.js +++ /dev/null @@ -1,99 +0,0 @@ -import gql from 'graphql-tag' -import _get from 'lodash.get' - -import mockedBPs from 'mock/bps' -import client from 'services/graphql' -import getBPRadarData from 'utils/getBPRadarData' -import calculateEosFromVotes from 'utils/convertVotesToEosVotes' - -export const getAllBPs = ({ nameFilter = null, setBPs = () => {} } = {}) => { - const containsActive = { - system: { - _contains: { - is_active: 1 - } - } - } - const nameFilerObject = { - _or: { candidate_name: { _ilike: `%${nameFilter}%` } } - } - const whereFilter = nameFilter - ? { ...containsActive, ...nameFilerObject } - : { ...containsActive } - - return client - .subscribe({ - query: gql` - subscription blockProducers($where: producers_list_bool_exp!) { - producers_list( - where: $where - order_by: [{ bpjson: desc }, { total_votes: desc }] - ) { - owner - system - bpjson - average - community - development - infrastructure - trustiness - transparency - ratings_cntr - general_info - eden_average - eden_ratings_cntr - } - } - `, - variables: { - where: whereFilter - } - }) - .subscribe({ - next({ data: { producers_list: producers } }) { - const BPs = producers.map((producer) => { - const { - community, - trustiness, - development, - transparency, - infrastructure, - ...bp - } = producer - const parameters = { - community: community || 0, - development: development || 0, - infrastructure: infrastructure || 0, - transparency: transparency || 0, - trustiness: trustiness || 0 - } - const votesInEos = calculateEosFromVotes( - _get(bp, 'system.total_votes', 0) - ) - return { - ...bp, - system: { - ...bp.system, - votesInEos, - parameters - }, - data: getBPRadarData({ - name: _get(bp, 'bpjson.org.candidate_name', bp.owner), - parameters - }) - } - }) - - return setBPs(BPs) - }, - error(err) { - console.error('err', err) - } - }) -} - -export const findBPs = async (filter = {}) => mockedBPs - -export const findBPById = async (id) => mockedBPs[id] - -window.getAllBPs = getAllBPs diff --git a/webapp/src/services/eosjs-api.js b/webapp/src/services/eosjs-api.js deleted file mode 100644 index 6c653d24..00000000 --- a/webapp/src/services/eosjs-api.js +++ /dev/null @@ -1,14 +0,0 @@ -import { Api, JsonRpc } from 'eosjs' -import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig' -import { TextEncoder, TextDecoder } from 'text-encoding' -import fetch from 'node-fetch' - -const signatureProvider = new JsSignatureProvider([]) - -const rpc = new JsonRpc( - process.env.REACT_APP_EOS_API_URL || 'https://jungle.eosio.cr', - { fetch } -) -const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() }) - -export default { api, rpc } diff --git a/webapp/src/services/graphql.js b/webapp/src/services/graphql.js deleted file mode 100644 index 8984deda..00000000 --- a/webapp/src/services/graphql.js +++ /dev/null @@ -1,42 +0,0 @@ -import ApolloClient from 'apollo-client' -import { WebSocketLink } from 'apollo-link-ws' -import { HttpLink } from 'apollo-link-http' -import { split } from 'apollo-link' -import { getMainDefinition } from 'apollo-utilities' -import { InMemoryCache } from 'apollo-cache-inmemory' - -// Create an http link: -const httpLink = new HttpLink({ - uri: process.env.REACT_APP_GRAPHQL_HTTP_URL, - credentials: 'same-origin' -}) - -// Create a WebSocket link: -const wsLink = new WebSocketLink({ - uri: process.env.REACT_APP_GRAPHQL_WS_URL, - options: { - reconnect: true - } -}) - -// using the ability to split links, you can send data to each link -// depending on what kind of operation is being sent -const link = split( - // split based on operation type - ({ query }) => { - const { kind, operation } = getMainDefinition(query) - return kind === 'OperationDefinition' && operation === 'subscription' - }, - wsLink, - httpLink -) - -// Instantiate client -const apolloClient = new ApolloClient({ - link, - cache: new InMemoryCache({ - addTypename: false - }) -}) - -export default apolloClient diff --git a/webapp/src/store.js b/webapp/src/store.js deleted file mode 100644 index 967c8dd6..00000000 --- a/webapp/src/store.js +++ /dev/null @@ -1,21 +0,0 @@ -import { init } from '@rematch/core' -import createPersistPlugin from '@rematch/persist' -import storage from 'redux-persist/lib/storage' - -import { locationChangeListener } from 'models/location' -import * as models from 'models' - -const persistPlugin = createPersistPlugin({ - key: 'root', - storage, - whitelist: ['blockProducers', 'settings'] -}) - -const store = init({ - models, - plugins: [persistPlugin] -}) - -locationChangeListener(store) - -export default store diff --git a/webapp/src/theme/breakpoints.js b/webapp/src/theme/breakpoints.js new file mode 100644 index 00000000..97cf097b --- /dev/null +++ b/webapp/src/theme/breakpoints.js @@ -0,0 +1,13 @@ +const breakpoints = { + values: { + xs: 0, + sm: 600, + md: 1024, + mdd: 1110, + mdg: 1115, + lg: 1440, + xl: 1920 + } +} + +export default breakpoints diff --git a/webapp/src/theme/index.js b/webapp/src/theme/index.js new file mode 100644 index 00000000..85d3ddc0 --- /dev/null +++ b/webapp/src/theme/index.js @@ -0,0 +1,28 @@ +import { createTheme } from '@mui/material/styles' + +import palette from './palette' +import breakpoints from './breakpoints' +import typography from './typography' + +export default useDarkMode => + createTheme({ + breakpoints, + typography, + palette: { type: useDarkMode ? 'dark' : 'light', ...palette }, + overrides: { + root: { + fontSize: '2em' + }, + MuiSelect: { + root: { + paddingTop: 8 + } + }, + MuiInput: { + root: { + height: 50, + fontSize: 20 + } + } + } + }) diff --git a/webapp/src/theme/palette.js b/webapp/src/theme/palette.js new file mode 100644 index 00000000..3b962664 --- /dev/null +++ b/webapp/src/theme/palette.js @@ -0,0 +1,22 @@ +export default { + background: { + default: '#eeeeee' + }, + primary: { + light: '#787291', + main: '#443f56', + dark: 'rgba(0, 0, 0, 0.87)', + sectionBackground: '#ffffff', + submenu: '#597a81' + }, + secondary: { + light: '#8ba2a6', + main: '#597a81', + dark: '#222f32' + }, + surface: { + light: '#ffffff', + main: '#ffffff', + dark: '#f8f8f8' + } +} diff --git a/webapp/src/theme/props.js b/webapp/src/theme/props.js new file mode 100644 index 00000000..449c53bc --- /dev/null +++ b/webapp/src/theme/props.js @@ -0,0 +1,10 @@ +const props = { + MuiButtonBase: { + disableRipple: true + }, + MuiCardHeader: { + titleTypographyProps: { variant: 'h6' } + } +} + +export default props diff --git a/webapp/src/theme/typography.js b/webapp/src/theme/typography.js new file mode 100644 index 00000000..78a23298 --- /dev/null +++ b/webapp/src/theme/typography.js @@ -0,0 +1,13 @@ +const typography = { + fontFamily: ['Roboto', 'sans-serif'].join(','), + body1: { + fontWeight: 400, + letterSpacing: 0.44 + }, + overline: { + letterSpacing: 1.5, + fontSize: 10 + } +} + +export default typography diff --git a/webapp/src/utils/convertVotesToEosVotes.js b/webapp/src/utils/convert-votes-to-eos-votes.js similarity index 73% rename from webapp/src/utils/convertVotesToEosVotes.js rename to webapp/src/utils/convert-votes-to-eos-votes.js index c9a5a454..50ce8b9e 100644 --- a/webapp/src/utils/convertVotesToEosVotes.js +++ b/webapp/src/utils/convert-votes-to-eos-votes.js @@ -4,9 +4,9 @@ const TIMESTAMP_EPOCH = 946684800 -const castToNumber = (value) => (!isNaN(Number(value)) ? value / 1 : 0) +const castToNumber = value => (!isNaN(Number(value)) ? value / 1 : 0) -export default (votes) => { +export default votes => { const date = Date.now() / 1000 - TIMESTAMP_EPOCH const weight = date / (86400 * 7) / 52 // 86400 = seconds per day 24*3600 return castToNumber(votes) / 2 ** weight / 10000 diff --git a/webapp/src/utils/eosapi.js b/webapp/src/utils/eosapi.js new file mode 100644 index 00000000..0700054e --- /dev/null +++ b/webapp/src/utils/eosapi.js @@ -0,0 +1,9 @@ +import EosApi from 'eosjs-api' + +import { ualConfig } from '../config' + +export const eosApi = EosApi({ + httpEndpoint: ualConfig.endpoint, + verbose: false, + fetchConfiguration: {} +}) diff --git a/webapp/src/utils/eosjsUtils.js b/webapp/src/utils/eosjs-utils.js similarity index 80% rename from webapp/src/utils/eosjsUtils.js rename to webapp/src/utils/eosjs-utils.js index 846b8332..daf2aa27 100644 --- a/webapp/src/utils/eosjsUtils.js +++ b/webapp/src/utils/eosjs-utils.js @@ -1,6 +1,6 @@ import { JsonRpc } from 'eosjs' -const getRpc = (ual) => { +const getRpc = ual => { const endpoint = ual.chains[0].rpcEndpoints[0] const rpcEndpoint = ual.activeUser.buildRpcEndpoint(endpoint) @@ -8,7 +8,7 @@ const getRpc = (ual) => { return new JsonRpc(rpcEndpoint) } -const getAccountName = async (ual) => { +const getAccountName = async ual => { return await ual.activeUser.getAccountName(ual) } diff --git a/webapp/src/utils/formatNumber.js b/webapp/src/utils/format-number.js similarity index 100% rename from webapp/src/utils/formatNumber.js rename to webapp/src/utils/format-number.js diff --git a/webapp/src/utils/format-with-thousand-separator.js b/webapp/src/utils/format-with-thousand-separator.js new file mode 100644 index 00000000..be5d3e82 --- /dev/null +++ b/webapp/src/utils/format-with-thousand-separator.js @@ -0,0 +1,13 @@ +export const formatWithThousandSeparator = (value, precision) => { + if (!value || isNaN(value)) { + return value + } + + let newValue = parseFloat(value) + + if (precision >= 0) { + newValue = newValue.toFixed(precision) + } + + return newValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') +} diff --git a/webapp/src/utils/getAverageValue.js b/webapp/src/utils/get-average-value.js similarity index 67% rename from webapp/src/utils/getAverageValue.js rename to webapp/src/utils/get-average-value.js index 58520868..fc2fe45f 100644 --- a/webapp/src/utils/getAverageValue.js +++ b/webapp/src/utils/get-average-value.js @@ -1,12 +1,12 @@ -const validateNumber = (average) => { - const value = average.toFixed(2) +const validateNumber = average => { + const value = average.toFixed(1) if (value % 1 === 0) return parseInt(value) return value } -export default (value) => { +export default value => { let average = value if (typeof average === 'string') { diff --git a/webapp/src/utils/get-bp-radar-data.js b/webapp/src/utils/get-bp-radar-data.js new file mode 100644 index 00000000..4c550dcc --- /dev/null +++ b/webapp/src/utils/get-bp-radar-data.js @@ -0,0 +1,12 @@ +import getRgbColorsFromHex from './get-rgb-colors-from-hex' + +export default ({ name, parameters }) => { + const { r, g, b } = getRgbColorsFromHex(name) + + return { + name, + type: 'area', + color: `rgba(${r}, ${g}, ${b}, .6)`, + data: Object.values(parameters) + } +} diff --git a/webapp/src/utils/getRadarLabelName.js b/webapp/src/utils/get-radar-label-name.js similarity index 80% rename from webapp/src/utils/getRadarLabelName.js rename to webapp/src/utils/get-radar-label-name.js index 0a3b73ec..f591fb45 100644 --- a/webapp/src/utils/getRadarLabelName.js +++ b/webapp/src/utils/get-radar-label-name.js @@ -1,4 +1,4 @@ -const getComparisonParameter = (t) => { +const getComparisonParameter = t => { return [ t('community'), t('development'), diff --git a/webapp/src/utils/get-rgb-colors-from-hex.js b/webapp/src/utils/get-rgb-colors-from-hex.js new file mode 100644 index 00000000..bf4609cb --- /dev/null +++ b/webapp/src/utils/get-rgb-colors-from-hex.js @@ -0,0 +1,15 @@ +const stc = require('string-to-color') + +const getColorHashByString = (inputString = 'defaultString') => { + const color = stc(inputString) + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color) + const r = parseInt(result[1], 16) + const g = parseInt(result[2], 16) + const b = parseInt(result[3], 16) + const rgb = `rgb(${r}, ${g}, ${b})` + const hex = `${color}`.toUpperCase() + + return { r, g, b, rgb, hex } +} + +export default getColorHashByString diff --git a/webapp/src/utils/getBPRadarData.js b/webapp/src/utils/getBPRadarData.js deleted file mode 100644 index 393cb8f3..00000000 --- a/webapp/src/utils/getBPRadarData.js +++ /dev/null @@ -1,18 +0,0 @@ -import getRgbColorsFromHex from 'utils/getRgbColorsFromHex' - -export default ({ name, parameters }) => { - const { r, g, b } = getRgbColorsFromHex(name) - - return { - label: name, - lineTension: 0.3, - borderJoinStyle: 'round', - backgroundColor: `rgba(${r}, ${g}, ${b}, .6)`, - borderColor: `rgba(${r}, ${g}, ${b}, .6)`, - pointBackgroundColor: `rgba(${r}, ${g}, ${b}, .6)`, - pointBorderColor: '#fff', - pointHoverBackgroundColor: '#fff', - pointHoverBorderColor: `rgba(${r}, ${g}, ${b}, 1)`, - data: Object.values(parameters) - } -} diff --git a/webapp/src/utils/getColorFromName.js b/webapp/src/utils/getColorFromName.js deleted file mode 100644 index 19e0391d..00000000 --- a/webapp/src/utils/getColorFromName.js +++ /dev/null @@ -1,18 +0,0 @@ -const hashCode = str => { - let hash = 0 - for (let i = 0; i < str.length; i++) { - hash = str.charCodeAt(i) + ((hash << 5) - hash) - } - return hash -} - -const intToRGB = i => { - const c = (i & 0x00ffffff).toString(16).toUpperCase() - - return '00000'.substring(0, 6 - c.length) + c -} - -export default name => - intToRGB(hashCode(name)) - .match(/(..?)/g) - .map(value => parseInt(value, 16)) diff --git a/webapp/src/utils/getRgbColorsFromHex.js b/webapp/src/utils/getRgbColorsFromHex.js deleted file mode 100644 index c7070334..00000000 --- a/webapp/src/utils/getRgbColorsFromHex.js +++ /dev/null @@ -1,38 +0,0 @@ -const getColorHashByString = (inputString = 'defaultString') => { - let inputStringSum = 0 - - for (const i in inputString) { - inputStringSum += inputString.charCodeAt(i) - } - - const r = ~~( - ('0.' + - Math.sin(inputStringSum + 1) - .toString() - .substr(6)) * - 256 - ) - const g = ~~( - ('0.' + - Math.sin(inputStringSum + 2) - .toString() - .substr(6)) * - 256 - ) - const b = ~~( - ('0.' + - Math.sin(inputStringSum + 3) - .toString() - .substr(6)) * - 256 - ) - - const rgb = `rgb(${r}, ${g}, ${b})` - const hex = `#${r.toString(16)}${g.toString(16)}${b.toString( - 16 - )}`.toUpperCase() - - return { r, g, b, rgb, hex } -} - -export default getColorHashByString diff --git a/webapp/src/utils/index.js b/webapp/src/utils/index.js new file mode 100644 index 00000000..58f0f1e3 --- /dev/null +++ b/webapp/src/utils/index.js @@ -0,0 +1,3 @@ +export * from './eosapi' +export * from './format-with-thousand-separator' +export * from './on-img-error' diff --git a/webapp/src/utils/modeled-bp-data.js b/webapp/src/utils/modeled-bp-data.js new file mode 100644 index 00000000..bbb60358 --- /dev/null +++ b/webapp/src/utils/modeled-bp-data.js @@ -0,0 +1,44 @@ +import _get from 'lodash.get' + +import getBPRadarData from './get-bp-radar-data' +import calculateEosFromVotes from './convert-votes-to-eos-votes' + +const formatDecimal = number => { + if (!number) return 0 + + if (number % 1 !== 0) { + return parseFloat(number.toFixed(1)) + } + + return number +} + +export default ({ + community, + trustiness, + development, + transparency, + infrastructure, + ...bp +}) => { + const parameters = { + community: formatDecimal(community), + trustiness: formatDecimal(trustiness), + development: formatDecimal(development), + transparency: formatDecimal(transparency), + infrastructure: formatDecimal(infrastructure) + } + const votesInEos = calculateEosFromVotes(_get(bp, 'system.total_votes', 0)) + return { + ...bp, + system: { + ...bp.system, + votesInEos, + parameters + }, + data: getBPRadarData({ + name: _get(bp, 'bpjson.org.candidate_name', bp.owner), + parameters + }) + } +} diff --git a/webapp/src/utils/modeled-proxy-data.js b/webapp/src/utils/modeled-proxy-data.js new file mode 100644 index 00000000..b23e6e7e --- /dev/null +++ b/webapp/src/utils/modeled-proxy-data.js @@ -0,0 +1,77 @@ +import _get from 'lodash.get' + +import calculateEosFromVotes from './convert-votes-to-eos-votes' +import getBPRadarData from './get-bp-radar-data' +import getBpDataModeled from './modeled-bp-data' + +export default proxy => { + const rateInfo = [] + const proxyProducers = _get(proxy, 'voter_info.producers', []) + const proxiedVoteEOS = calculateEosFromVotes( + _get(proxy, 'voter_info.last_vote_weight', 0) + ) + const totalVoteEOS = calculateEosFromVotes( + _get(proxy, 'voter_info.proxied_vote_weight', 0) + ) + const producersDataModeled = proxyProducers.map(bp => { + const producer = getBpDataModeled(bp) + + const { + system: { parameters } + } = producer + + rateInfo.push(parameters) + + return producer + }) + + const averageParams = rateInfo.reduce( + (acc, current, index) => { + const community = acc.community + current.community + const development = acc.development + current.development + const infrastructure = acc.infrastructure + current.infrastructure + const transparency = acc.transparency + current.transparency + const trustiness = acc.trustiness + current.trustiness + + if (index + 1 === rateInfo.length) { + return { + community: community / rateInfo.length, + development: development / rateInfo.length, + infrastructure: infrastructure / rateInfo.length, + transparency: transparency / rateInfo.length, + trustiness: trustiness / rateInfo.length + } + } + + return { + community, + development, + infrastructure, + transparency, + trustiness + } + }, + { + community: 0, + development: 0, + infrastructure: 0, + transparency: 0, + trustiness: 0 + } + ) + + return { + ...proxy, + voter_info: { + ...proxy.voter_info, + producers: producersDataModeled + }, + averageParams, + data: getBPRadarData({ + name: proxy.owner, + parameters: averageParams + }), + proxiedVoteEOS, + totalVoteEOS + } +} diff --git a/webapp/src/utils/on-img-error.js b/webapp/src/utils/on-img-error.js new file mode 100644 index 00000000..4425ed4f --- /dev/null +++ b/webapp/src/utils/on-img-error.js @@ -0,0 +1,7 @@ +export const onImgError = defaultLogo => ev => { + if (ev.target.src === defaultLogo) { + return + } + + ev.target.src = defaultLogo +} diff --git a/webapp/src/utils/sortedBy.js b/webapp/src/utils/sortedBy.js deleted file mode 100644 index dab2b0b5..00000000 --- a/webapp/src/utils/sortedBy.js +++ /dev/null @@ -1,86 +0,0 @@ -import _get from 'lodash.get' - -const _sortValues = (firstValues, secondValues, path) => { - const firstValue = _get(firstValues, path, 0) || 0 - const secondValue = _get(secondValues, path, 0) || 0 - - return secondValue - firstValue -} - -export default (sortBy, blockProducers) => { - switch (sortBy) { - case 'alphabetical': { - const _getValidName = (bp) => { - const name = _get(bp, 'bpjson.org.candidate_name', null) - - if (name && name.length) return name.toUpperCase() - - return _get(bp, 'owner').toUpperCase() - } - - return (blockProducers || []).sort((a, b) => { - const firstBP = _getValidName(a) - const secondBP = _getValidName(b) - - return firstBP < secondBP ? -1 : firstBP > secondBP ? 1 : 0 - }) - } - - case 'generalRate': { - return (blockProducers || []).sort((a, b) => _sortValues(a, b, 'average')) - } - - case 'edenRate': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'eden_average') - ) - } - - case 'infrastructure': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'system.parameters.infrastructure') - ) - } - - case 'community': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'system.parameters.community') - ) - } - - case 'trustiness': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'system.parameters.trustiness') - ) - } - - case 'development': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'system.parameters.development') - ) - } - - case 'transparency': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'system.parameters.transparency') - ) - } - - case 'vote': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'system.total_votes') - ) - } - - case 'ratings': { - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'ratings_cntr') - ) - } - - default: - return (blockProducers || []).sort((a, b) => - _sortValues(a, b, 'system.total_votes') - ) - } -} diff --git a/webapp/src/utils/ualAuthenticators.js b/webapp/src/utils/ualAuthenticators.js deleted file mode 100644 index 5102b5a8..00000000 --- a/webapp/src/utils/ualAuthenticators.js +++ /dev/null @@ -1,44 +0,0 @@ -import { Scatter } from 'ual-scatter' -import { Ledger } from 'ual-ledger' -import { Lynx } from 'ual-lynx' -import { TokenPocket } from 'ual-token-pocket' -import { MeetOne } from 'ual-meetone' -import { Anchor } from 'ual-anchor' - -import { - appName, - eosChainId, - eosApiProtocol, - eosApiHost, - eosApiPort -} from '../config' - -export const network = { - chainId: - eosChainId || - '2a02a0053e5a8cf73a56ba0fda11e4d92e0238a4a2aa74fccf46d5a910746840', - rpcEndpoints: [ - { - blockchain: 'eos', - protocol: eosApiProtocol || 'https', - host: eosApiHost || 'jungle.eosio.cr', - port: parseInt(eosApiPort || '443') - } - ] -} - -const lynx = new Lynx([network]) -const ledger = new Ledger([network]) -const tokenPocket = new TokenPocket([network]) -const meetOne = new MeetOne([network.chainId]) -const scatter = new Scatter([network], { appName }) -const anchor = new Anchor([network], { appName }) - -export const authenticators = [ - lynx, - ledger, - scatter, - tokenPocket, - meetOne, - anchor -] diff --git a/webapp/prettier.config.js b/webapp/test.prettier.config.js similarity index 80% rename from webapp/prettier.config.js rename to webapp/test.prettier.config.js index a63208a7..69967801 100644 --- a/webapp/prettier.config.js +++ b/webapp/test.prettier.config.js @@ -7,5 +7,6 @@ module.exports = { trailingComma: 'none', bracketSpacing: true, jsxBracketSameLine: false, - jsxSingleQuote: true + jsxSingleQuote: true, + endOfLine: 'auto' } diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 535c7a0d..42dfcae3 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -2,6 +2,24 @@ # yarn lockfile v1 +"@apollo/client@^3.3.21": + version "3.4.16" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.4.16.tgz#67090d5655aa843fa64d26f1913315e384a5fa0f" + integrity sha512-iF4zEYwvebkri0BZQyv8zfavPfVEafsK0wkOofa6eC2yZu50J18uTutKtC174rjHZ2eyxZ8tV7NvAPKRT+OtZw== + dependencies: + "@graphql-typed-document-node/core" "^3.0.0" + "@wry/context" "^0.6.0" + "@wry/equality" "^0.5.0" + "@wry/trie" "^0.3.0" + graphql-tag "^2.12.3" + hoist-non-react-statics "^3.3.2" + optimism "^0.16.1" + prop-types "^15.7.2" + symbol-observable "^4.0.0" + ts-invariant "^0.9.0" + tslib "^2.3.0" + zen-observable-ts "~1.1.0" + "@apollo/react-common@^3.1.4": version "3.1.4" resolved "https://registry.yarnpkg.com/@apollo/react-common/-/react-common-3.1.4.tgz#ec13c985be23ea8e799c9ea18e696eccc97be345" @@ -65,10 +83,10 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.5.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" - integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.15.8", "@babel/code-frame@^7.5.5": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.15.8.tgz#45990c47adadb00c03677baa89221f7cc23d2503" + integrity sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg== dependencies: "@babel/highlight" "^7.14.5" @@ -120,19 +138,19 @@ source-map "^0.5.0" "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5", "@babel/core@^7.8.4": - version "7.15.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" - integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.8.tgz#195b9f2bffe995d2c6c159e72fe525b4114e8c10" + integrity sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og== dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" + "@babel/code-frame" "^7.15.8" + "@babel/generator" "^7.15.8" "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.8" "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.5" + "@babel/parser" "^7.15.8" "@babel/template" "^7.15.4" "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/types" "^7.15.6" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -140,12 +158,21 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.12.1", "@babel/generator@^7.15.4", "@babel/generator@^7.6.0": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" - integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw== +"@babel/eslint-parser@^7.13.10": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.15.8.tgz#8988660b59d739500b67d0585fd4daca218d9f11" + integrity sha512-fYP7QFngCvgxjUuw8O057SVH5jCXsbFFOoE77CFDcvzwBVgTOkMD/L4mIC5Ud1xf8chK/no2fRbSSn1wvNmKuQ== dependencies: - "@babel/types" "^7.15.4" + eslint-scope "^5.1.1" + eslint-visitor-keys "^2.1.0" + semver "^6.3.0" + +"@babel/generator@^7.12.1", "@babel/generator@^7.15.4", "@babel/generator@^7.15.8", "@babel/generator@^7.6.0": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.8.tgz#fa56be6b596952ceb231048cf84ee499a19c0cd1" + integrity sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g== + dependencies: + "@babel/types" "^7.15.6" jsesc "^2.5.1" source-map "^0.5.0" @@ -252,19 +279,19 @@ dependencies: "@babel/types" "^7.15.4" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz#962cc629a7f7f9a082dd62d0307fa75fe8788d7c" - integrity sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw== +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4", "@babel/helper-module-transforms@^7.15.8": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz#d8c0e75a87a52e374a8f25f855174786a09498b2" + integrity sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg== dependencies: "@babel/helper-module-imports" "^7.15.4" "@babel/helper-replace-supers" "^7.15.4" "@babel/helper-simple-access" "^7.15.4" "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/helper-validator-identifier" "^7.14.9" + "@babel/helper-validator-identifier" "^7.15.7" "@babel/template" "^7.15.4" "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/types" "^7.15.6" "@babel/helper-optimise-call-expression@^7.15.4": version "7.15.4" @@ -318,10 +345,10 @@ dependencies: "@babel/types" "^7.15.4" -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== "@babel/helper-validator-option@^7.12.1", "@babel/helper-validator-option@^7.14.5": version "7.14.5" @@ -356,10 +383,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.3", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.6.0", "@babel/parser@^7.7.0": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.6.tgz#043b9aa3c303c0722e5377fef9197f4cf1796549" - integrity sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.3", "@babel/parser@^7.15.4", "@babel/parser@^7.15.8", "@babel/parser@^7.6.0", "@babel/parser@^7.7.0": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" + integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": version "7.15.4" @@ -370,10 +397,10 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" "@babel/plugin-proposal-optional-chaining" "^7.14.5" -"@babel/plugin-proposal-async-generator-functions@^7.12.1", "@babel/plugin-proposal-async-generator-functions@^7.15.4", "@babel/plugin-proposal-async-generator-functions@^7.2.0": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz#f82aabe96c135d2ceaa917feb9f5fca31635277e" - integrity sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw== +"@babel/plugin-proposal-async-generator-functions@^7.12.1", "@babel/plugin-proposal-async-generator-functions@^7.15.8", "@babel/plugin-proposal-async-generator-functions@^7.2.0": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz#a3100f785fab4357987c4223ab1b02b599048403" + integrity sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-remap-async-to-generator" "^7.15.4" @@ -505,7 +532,7 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-proposal-optional-chaining@^7.12.1", "@babel/plugin-proposal-optional-chaining@^7.14.5": +"@babel/plugin-proposal-optional-chaining@^7.12.1", "@babel/plugin-proposal-optional-chaining@^7.13.8", "@babel/plugin-proposal-optional-chaining@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603" integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ== @@ -610,7 +637,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.14.5": +"@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw== @@ -963,13 +990,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-spread@^7.12.1", "@babel/plugin-transform-spread@^7.14.6", "@babel/plugin-transform-spread@^7.2.0": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" - integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== +"@babel/plugin-transform-spread@^7.12.1", "@babel/plugin-transform-spread@^7.15.8", "@babel/plugin-transform-spread@^7.2.0": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz#79d5aa27f68d700449b2da07691dfa32d2f6d468" + integrity sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" "@babel/plugin-transform-sticky-regex@^7.12.1", "@babel/plugin-transform-sticky-regex@^7.14.5", "@babel/plugin-transform-sticky-regex@^7.2.0": version "7.14.5" @@ -993,9 +1020,9 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-typescript@^7.12.1": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.4.tgz#db7a062dcf8be5fc096bc0eeb40a13fbfa1fa251" - integrity sha512-sM1/FEjwYjXvMwu1PJStH11kJ154zd/lpY56NQJ5qH2D0mabMv1CAy/kdvS9RP4Xgfj9fBBA3JiSLdDHgXdzOA== + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.8.tgz#ff0e6a47de9b2d58652123ab5a879b2ff20665d8" + integrity sha512-ZXIkJpbaf6/EsmjeTbiJN/yMxWPFWvlr7sEG1P95Xb4S4IBcrf2n7s/fItIhsAmOf8oSh3VJPDppO6ExfAfKRQ== dependencies: "@babel/helper-create-class-features-plugin" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" @@ -1143,17 +1170,17 @@ js-levenshtein "^1.1.3" semver "^5.3.0" -"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.8.4": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" - integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.13.10", "@babel/preset-env@^7.8.4": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.8.tgz#f527ce5bcb121cd199f6b502bf23e420b3ff8dba" + integrity sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA== dependencies: "@babel/compat-data" "^7.15.0" "@babel/helper-compilation-targets" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.15.4" - "@babel/plugin-proposal-async-generator-functions" "^7.15.4" + "@babel/plugin-proposal-async-generator-functions" "^7.15.8" "@babel/plugin-proposal-class-properties" "^7.14.5" "@babel/plugin-proposal-class-static-block" "^7.15.4" "@babel/plugin-proposal-dynamic-import" "^7.14.5" @@ -1208,7 +1235,7 @@ "@babel/plugin-transform-regenerator" "^7.14.5" "@babel/plugin-transform-reserved-words" "^7.14.5" "@babel/plugin-transform-shorthand-properties" "^7.14.5" - "@babel/plugin-transform-spread" "^7.14.6" + "@babel/plugin-transform-spread" "^7.15.8" "@babel/plugin-transform-sticky-regex" "^7.14.5" "@babel/plugin-transform-template-literals" "^7.14.5" "@babel/plugin-transform-typeof-symbol" "^7.14.5" @@ -1217,7 +1244,7 @@ "@babel/preset-modules" "^0.1.4" "@babel/types" "^7.15.6" babel-plugin-polyfill-corejs2 "^0.2.2" - babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.5" babel-plugin-polyfill-regenerator "^0.2.2" core-js-compat "^3.16.0" semver "^6.3.0" @@ -1257,7 +1284,7 @@ "@babel/plugin-transform-react-jsx-source" "^7.12.1" "@babel/plugin-transform-react-pure-annotations" "^7.12.1" -"@babel/preset-react@^7.12.5": +"@babel/preset-react@^7.12.13", "@babel/preset-react@^7.12.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.14.5.tgz#0fbb769513f899c2c56f3a882fa79673c2d4ab3c" integrity sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ== @@ -1299,7 +1326,7 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== @@ -1361,6 +1388,68 @@ resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== +"@date-io/core@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.11.0.tgz#28580cda1c8228ab2c7ed6aee673ef0495f913e6" + integrity sha512-DvPBnNoeuLaoSJZaxgpu54qzRhRKjSYVyQjhznTFrllKuDpm0sDFjHo6lvNLCM/cfMx2gb2PM2zY2kc9C8nmuw== + +"@date-io/date-fns@^2.10.6", "@date-io/date-fns@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.11.0.tgz#142fbf954eda7ad66514af7a2802d78c4ea40053" + integrity sha512-mPQ71plBeFrArvBSHtjWMHXA89IUbZ6kuo2dsjlRC/1uNOybo91spIb+wTu03NxKTl8ut07s0jJ9svF71afpRg== + dependencies: + "@date-io/core" "^2.11.0" + +"@date-io/dayjs@^2.10.6": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/dayjs/-/dayjs-2.11.0.tgz#41f4b4b9629612e6012accffd848875d1aeffb74" + integrity sha512-w67vRK56NZJIKhJM/CrNbfnIcuMvR3ApfxzNZiCZ5w29sxgBDeKuX4M+P7A9r5HXOMGcsOcpgaoTDINNGkdpGQ== + dependencies: + "@date-io/core" "^2.11.0" + +"@date-io/luxon@^2.10.6": + version "2.11.1" + resolved "https://registry.yarnpkg.com/@date-io/luxon/-/luxon-2.11.1.tgz#31a72f7b5e163c74e8a3b29d8f16c4c30de6ed43" + integrity sha512-JUXo01kdPQxLORxqdENrgdUhooKgDUggsNRSdi2BcUhASIY2KGwwWXu8ikVHHGkw+DUF4FOEKGfkQd0RHSvX6g== + dependencies: + "@date-io/core" "^2.11.0" + +"@date-io/moment@^2.10.6": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/moment/-/moment-2.11.0.tgz#850f8dd090d401845b39276d034dbabe20224ef5" + integrity sha512-QSL+83qezQ9Ty0dtFgAkk6eC0GMl/lgYfDajeVUDB3zVA2A038hzczRLBg29ifnBGhQMPABxuOafgWwhDjlarg== + dependencies: + "@date-io/core" "^2.11.0" + +"@emotion/babel-plugin@^11.3.0": + version "11.3.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.3.0.tgz#3a16850ba04d8d9651f07f3fb674b3436a4fb9d7" + integrity sha512-UZKwBV2rADuhRp+ZOGgNWg2eYgbzKzQXfQPtJbu/PLy8onurxlNCLvxMQEvlr1/GudguPI5IU9qIY1+2z1M5bA== + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "^4.0.3" + +"@emotion/cache@^11.4.0": + version "11.4.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.4.0.tgz#293fc9d9a7a38b9aad8e9337e5014366c3b09ac0" + integrity sha512-Zx70bjE7LErRO9OaZrhf22Qye1y4F7iDl+ITjet0J+i+B88PrAOBkKvaAWhxsZf72tDLajwCgfCjJ2dvH77C3g== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.0.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "^4.0.3" + "@emotion/hash@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" @@ -1373,16 +1462,78 @@ dependencies: "@emotion/memoize" "0.7.4" +"@emotion/is-prop-valid@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.0.tgz#29ef6be1e946fb4739f9707def860f316f668cde" + integrity sha512-9RkilvXAufQHsSsjQ3PIzSns+pxuX4EW8EbGeSPjZMHuMx6z/MOzb9LpqNieQX4F3mre3NWS2+X3JNRHTQztUQ== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/memoize@0.7.4": version "0.7.4" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== -"@emotion/unitless@^0.7.0": +"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/react@^11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.4.1.tgz#a1b0b767b5bad57515ffb0cad9349614d27f4d57" + integrity sha512-pRegcsuGYj4FCdZN6j5vqCALkNytdrKw3TZMekTzNXixRg4wkLsU5QEaBG5LC6l01Vppxlp7FE3aTHpIG5phLg== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/cache" "^11.4.0" + "@emotion/serialize" "^1.0.2" + "@emotion/sheet" "^1.0.2" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" + integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.2.tgz#1d9ffde531714ba28e62dac6a996a8b1089719d0" + integrity sha512-QQPB1B70JEVUHuNtzjHftMGv6eC3Y9wqavyarj4x4lg47RACkeSfNo5pxIOKizwS9AEFLohsqoaxGQj4p0vSIw== + +"@emotion/styled@^11.3.0": + version "11.3.0" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.3.0.tgz#d63ee00537dfb6ff612e31b0e915c5cf9925a207" + integrity sha512-fUoLcN3BfMiLlRhJ8CuPUMEyKkLEoM+n+UyAbnqGEsCd5IzKQ7VQFLtzpJOaCD2/VR2+1hXQTnSZXVJeiTNltA== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.3.0" + "@emotion/is-prop-valid" "^1.1.0" + "@emotion/serialize" "^1.0.2" + "@emotion/utils" "^1.0.0" + +"@emotion/unitless@^0.7.0", "@emotion/unitless@^0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== +"@emotion/utils@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af" + integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA== + +"@emotion/weak-memoize@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + "@eoscostarica/eoscr-components@^3.5.4": version "3.5.4" resolved "https://registry.yarnpkg.com/@eoscostarica/eoscr-components/-/eoscr-components-3.5.4.tgz#9a7d05d03f2c21a297215b3530f671fdcf38cadc" @@ -1413,10 +1564,26 @@ "@types/node" "*" typescript "*" -"@eslint/eslintrc@^0.2.1": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" - integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== +"@eoscostarica/ual-reactjs-renderer@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@eoscostarica/ual-reactjs-renderer/-/ual-reactjs-renderer-0.3.1.tgz#4f056ea9a14557aee86f16626cf5a25da3e8fed9" + integrity sha512-ulEv8hSuZwDOqapqY9JNug6iUTsaXbCJTllFAwGjy0Yk6hOnztcR9+6s/KdIHEpCpVJ1g53rOFznHxw/je8klQ== + dependencies: + "@react-icons/all-files" "^4.1.0" + i18next "14.0.1" + i18next-browser-languagedetector "2.2.4" + prop-types "15.7.2" + react "16.13.0" + react-dom "16.13.0" + react-icons "4.1.0" + react-tooltip "3.9.2" + styled-components "4.4.1" + universal-authenticator-library "0.3.0" + +"@eslint/eslintrc@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.3.0.tgz#d736d6963d7003b6514e6324bec9c602ac340318" + integrity sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg== dependencies: ajv "^6.12.4" debug "^4.1.1" @@ -1425,7 +1592,7 @@ ignore "^4.0.6" import-fresh "^3.2.1" js-yaml "^3.13.1" - lodash "^4.17.19" + lodash "^4.17.20" minimatch "^3.0.4" strip-json-comments "^3.1.1" @@ -1449,7 +1616,23 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== -"@greymass/eosio@^0.4.0", "@greymass/eosio@^0.4.3": +"@graphql-typed-document-node/core@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.0.tgz#0eee6373e11418bfe0b5638f654df7a4ca6a3950" + integrity sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg== + +"@greymass/eosio@0.5.2", "@greymass/eosio@^0.5.0": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@greymass/eosio/-/eosio-0.5.2.tgz#b7fa20937e6378277534e97b828ea871f1804953" + integrity sha512-3qMnm4o3B5GZ0cXK/AaKYyDkFLISHSkO3G0hPtn9aYdzNKuefyacyKWKQjQKC4kKLsNoJQd7d1ldAkV8Z0+0gA== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + elliptic "^6.5.4" + hash.js "^1.0.0" + tslib "^2.0.3" + +"@greymass/eosio@^0.4.0": version "0.4.9" resolved "https://registry.yarnpkg.com/@greymass/eosio/-/eosio-0.4.9.tgz#429b0426c0781421903e866612b383953e10e414" integrity sha512-gzSqkJETH3jVPGhgeMI4u6ZFPxnc9GzDTJyvjM59YzrIn/FdqGtB2CKNWJoUdHR8aek85ZkTPx1hhl9rCVWh1A== @@ -1693,10 +1876,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jest/types@^27.1.1": - version "27.1.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.1.1.tgz#77a3fc014f906c65752d12123a0134359707c0ad" - integrity sha512-yqJPDDseb0mXgKqmNqypCsb85C22K1aY5+LUxh7syIM9n/b0AsaltxNy+o6tt29VcfGDpYEve175bm3uOhcehA== +"@jest/types@^27.2.4": + version "27.2.4" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.2.4.tgz#2430042a66e00dc5b140c3636f4474d464c21ee8" + integrity sha512-IDO2ezTxeMvQAHxzG/ZvEyA47q0aVfzT95rGFl7bZs/Go0aIucvfDbS2rmnoEdXxlLQhcolmoG/wvL/uKx4tKA== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" @@ -1750,7 +1933,7 @@ resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-4.72.0.tgz#43df23af013ad1135407e5cf33ca6e4c4c7708d5" integrity sha512-o+TYF8vBcyySRsb2kqBDv/KMeme8a2nwWoG+lAWzbDmWfb2/MrVWYCVYDYvjXdSoI/Cujqy1i0gIDrkdxa9chA== -"@material-ui/core@^4.12.1", "@material-ui/core@^4.12.3": +"@material-ui/core@^4.12.3": version "4.12.3" resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca" integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw== @@ -1768,7 +1951,7 @@ react-is "^16.8.0 || ^17.0.0" react-transition-group "^4.4.0" -"@material-ui/icons@^4.11.2", "@material-ui/icons@^4.9.1": +"@material-ui/icons@^4.11.2": version "4.11.2" resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.11.2.tgz#b3a7353266519cd743b6461ae9fdfcb1b25eb4c5" integrity sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ== @@ -1832,6 +2015,134 @@ prop-types "^15.7.2" react-is "^16.8.0 || ^17.0.0" +"@mui/core@5.0.0-alpha.49": + version "5.0.0-alpha.49" + resolved "https://registry.yarnpkg.com/@mui/core/-/core-5.0.0-alpha.49.tgz#e74d6ec7f83f85b55d48aa05ea6b7cefff88ce1b" + integrity sha512-bZ7UgH84AuKf/IT0U+knHEelDxLV0lNVFg7rKkkDfXEwUpTtAZEtZPFJjNngapSB/4MuFjaFsttex+0DGC5Z1Q== + dependencies: + "@babel/runtime" "^7.15.4" + "@emotion/is-prop-valid" "^1.1.0" + "@mui/utils" "^5.0.1" + clsx "^1.1.1" + prop-types "^15.7.2" + react-is "^17.0.2" + +"@mui/icons-material@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.0.1.tgz#fb7ffeba0b3604aab4a9b91644d2fc1aabb3b4f1" + integrity sha512-AZehR/Uvi9VodsNPk9ae1lENKrf1evqx9suiP6VIqu7NxjZOlw/m/yA2gRAMmLEmIGr7EChfi/wcXuq6BpM9vw== + dependencies: + "@babel/runtime" "^7.15.4" + +"@mui/lab@^5.0.0-alpha.48": + version "5.0.0-alpha.49" + resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.49.tgz#fd26e4f76c1b28b7884c9e89bd710e7b34a99af2" + integrity sha512-AKTh3gAsP5GaveAoBAjEvyuuyFMYzyfUAwo7wvz9A/EiTnkc+2QXsSO7W4ykTIjNoIGBrTd9bTV/YQNK6FpPMw== + dependencies: + "@babel/runtime" "^7.15.4" + "@date-io/date-fns" "^2.10.6" + "@date-io/dayjs" "^2.10.6" + "@date-io/luxon" "^2.10.6" + "@date-io/moment" "^2.10.6" + "@mui/core" "5.0.0-alpha.49" + "@mui/system" "^5.0.2" + "@mui/utils" "^5.0.1" + clsx "^1.1.1" + prop-types "^15.7.2" + react-is "^17.0.2" + react-transition-group "^4.4.2" + rifm "^0.12.0" + +"@mui/material@^5.0.1": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.0.2.tgz#380cf0ef42c538a68158b4da19c317178b22d10f" + integrity sha512-LD2xHSjTLmbN0UoCuKTu09L/7JjpEzg+Cophf+dVJOTNoK7VI0Eqv3bmpF/9pDIk5dVKmeU9Eh4t2lW1ZifM6A== + dependencies: + "@babel/runtime" "^7.15.4" + "@mui/core" "5.0.0-alpha.49" + "@mui/system" "^5.0.2" + "@mui/types" "^7.0.0" + "@mui/utils" "^5.0.1" + "@popperjs/core" "^2.4.4" + "@types/react-transition-group" "^4.4.3" + clsx "^1.1.1" + csstype "^3.0.9" + hoist-non-react-statics "^3.3.2" + prop-types "^15.7.2" + react-is "^17.0.2" + react-transition-group "^4.4.2" + +"@mui/private-theming@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.0.1.tgz#50a0ea6ad5a8d1d78072859c4bdaaa6b6584d986" + integrity sha512-R8Cf2+32cG1OXFAqTighA5Mx9R5BQ57cN1ZVaNgfgdbI87Yig2fVMdFSPrw3txcjKlnwsvFJF8AdwQMqq1tJ3Q== + dependencies: + "@babel/runtime" "^7.15.4" + "@mui/utils" "^5.0.1" + prop-types "^15.7.2" + +"@mui/styled-engine@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.0.1.tgz#401e3e0ff846ad1b1e7e097c8050b36d7b68343e" + integrity sha512-j40nCbaKr1HAZYqpX61XvZYsadYskjo3u6+pRFFaewSViAkkD1rjjbubpnh15nqVfYmijtHMZJ9/l1x1hamvfQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@emotion/cache" "^11.4.0" + prop-types "^15.7.2" + +"@mui/styles@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.0.1.tgz#1634d08d892b5c7e85c9f84e4fc8bc02a5fb0f7a" + integrity sha512-hCtR2ZVOkoIhpTan02I4UEShnZxe59WwhKRJqauMs/addXByhAHHCNheTdiV++Irl/fyyFObmzPM0CUD3q6FIA== + dependencies: + "@babel/runtime" "^7.15.4" + "@emotion/hash" "^0.8.0" + "@mui/private-theming" "^5.0.1" + "@mui/types" "^7.0.0" + "@mui/utils" "^5.0.1" + clsx "^1.1.1" + csstype "^3.0.9" + hoist-non-react-statics "^3.3.2" + jss "^10.8.0" + jss-plugin-camel-case "^10.8.0" + jss-plugin-default-unit "^10.8.0" + jss-plugin-global "^10.8.0" + jss-plugin-nested "^10.8.0" + jss-plugin-props-sort "^10.8.0" + jss-plugin-rule-value-function "^10.8.0" + jss-plugin-vendor-prefixer "^10.8.0" + prop-types "^15.7.2" + +"@mui/system@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.0.2.tgz#9999ab61801810ea01c44588fd0dcc1f64dfcedc" + integrity sha512-K6wMbiSEYSMeYUw7zmZ2/50JFthqtuTz4OADyKc4ic2RP8ubAf/duH/nkJ4gtsKcewU4RIub0HQHl5F77WVp4Q== + dependencies: + "@babel/runtime" "^7.15.4" + "@mui/private-theming" "^5.0.1" + "@mui/styled-engine" "^5.0.1" + "@mui/types" "^7.0.0" + "@mui/utils" "^5.0.1" + clsx "^1.1.1" + csstype "^3.0.9" + prop-types "^15.7.2" + +"@mui/types@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.0.0.tgz#a7398502bc9c508875aafcbe28aea599b2c3d203" + integrity sha512-M/tkF2pZ4uoPhZ8pnNhlVnOFtz6F3dnYKIsnj8MuXKT6d26IE2u0UjA8B0275ggN74dR9rlHG5xJt5jgDx/Ung== + +"@mui/utils@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.0.1.tgz#d4f0f41b82db6ac273920a1b5b6a4de7879271f5" + integrity sha512-GWO104N+o9KG5fKiTEYnAg7kONKEg3vLN+VROAU0f3it6lFGLCVPcQYex/1gJ4QAy96u6Ez8/Hmmhi1+3cX0tQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/prop-types" "^15.7.4" + "@types/react-is" "^16.7.1 || ^17.0.0" + prop-types "^15.7.2" + react-is "^17.0.2" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1881,27 +2192,15 @@ schema-utils "^2.6.5" source-map "^0.7.3" -"@reach/router@^1.3.3": - version "1.3.4" - resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" - integrity sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA== - dependencies: - create-react-context "0.3.0" - invariant "^2.2.3" - prop-types "^15.6.1" - react-lifecycles-compat "^3.0.4" - -"@rematch/core@^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@rematch/core/-/core-2.1.0.tgz#e067ed78a6895d17e3cc2e15aa0db5148c9c6279" - integrity sha512-izr4LlXsHp1gfK8v05FNvqSthX64cCj59/x3tu+3qNXSuSM7d1/YXAlUtBJIoX9RApr+d1mqA7CCAteUjZrdLg== +"@popperjs/core@^2.4.4": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.2.tgz#0798c03351f0dea1a5a4cabddf26a55a7cbee590" + integrity sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ== -"@rematch/persist@^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@rematch/persist/-/persist-2.1.0.tgz#11f61567765e014acfa261e9800b9be15100b420" - integrity sha512-xSXyiegkMN5Aso4MgSzpLyiqPAalrjjk5Hc+6NkotUja2+Kn7uPyG8TZ3hBwzyLEK68SeZmY0Mm182ii+B3B1Q== - dependencies: - redux-persist "^6.0.0" +"@react-icons/all-files@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@react-icons/all-files/-/all-files-4.1.0.tgz#477284873a0821928224b6fc84c62d2534d6650b" + integrity sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ== "@rollup/plugin-node-resolve@^7.1.1": version "7.1.3" @@ -2221,14 +2520,6 @@ dependencies: "@types/node" "*" -"@types/hoist-non-react-statics@^3.3.0": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - "@types/html-minifier-terser@^5.0.0": version "5.1.2" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" @@ -2254,9 +2545,9 @@ "@types/istanbul-lib-report" "*" "@types/jest@*": - version "27.0.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.1.tgz#fafcc997da0135865311bb1215ba16dba6bdf4ca" - integrity sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw== + version "27.0.2" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.2.tgz#ac383c4d4aaddd29bbf2b916d8d105c304a5fcd7" + integrity sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA== dependencies: jest-diff "^27.0.0" pretty-format "^27.0.0" @@ -2272,19 +2563,19 @@ integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= "@types/lodash@^4.14.165": - version "4.14.173" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.173.tgz#9d3b674c67a26cf673756f6aca7b429f237f91ed" - integrity sha512-vv0CAYoaEjCw/mLy96GBTnRoZrSxkGE0BKzKimdR8P3OzrNYNvBgtW7p055A+E8C31vXNUhWKoFCbhq7gbyhFg== + version "4.14.175" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.175.tgz#b78dfa959192b01fae0ad90e166478769b215f45" + integrity sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw== -"@types/minimatch@*", "@types/minimatch@^3.0.3": +"@types/minimatch@*": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== "@types/node@*", "@types/node@>=6": - version "16.9.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.2.tgz#81f5a039d6ed1941f8cc57506c74e7c2b8fc64b9" - integrity sha512-ZHty/hKoOLZvSz6BtP1g7tc7nUeJhoCf3flLjh8ZEv1vFKBWHXcnMbJMyN/pftSljNyy0kNW/UqI3DccnBnZ8w== + version "16.10.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.3.tgz#7a8f2838603ea314d1d22bb3171d899e15c57bd5" + integrity sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -2297,11 +2588,11 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prettier@^2.0.0": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" - integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb" + integrity sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw== -"@types/prop-types@*": +"@types/prop-types@*", "@types/prop-types@^15.7.4": version "15.7.4" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== @@ -2311,17 +2602,14 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== -"@types/react-redux@^7.1.16": - version "7.1.18" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.18.tgz#2bf8fd56ebaae679a90ebffe48ff73717c438e04" - integrity sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ== +"@types/react-is@^16.7.1 || ^17.0.0": + version "17.0.2" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.2.tgz#abc4d910bff5b0bc6b3e1bec57575f6b63fd4e05" + integrity sha512-2+L0ilcAEG8udkDnvx8B0upwXFBbNnVwOsSCTxW3SDOkmar9NyEeLG0ZLa3uOEw9zyYf/fQapcnfXAVmDKlyHw== dependencies: - "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" - hoist-non-react-statics "^3.3.0" - redux "^4.0.0" -"@types/react-transition-group@^4.2.0": +"@types/react-transition-group@^4.2.0", "@types/react-transition-group@^4.4.3": version "4.4.3" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.3.tgz#b0994da0a7023d67dbb4a8910a62112bc00d5688" integrity sha512-fUx5muOWSYP8Bw2BUQ9M9RK9+W1XBK/7FLJ8PTQpnpTEkn0ccyMffyEQvan4C3h53gHdx7KE5Qrxi/LnUGQtdg== @@ -2329,9 +2617,9 @@ "@types/react" "*" "@types/react@*": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.21.tgz#069c43177cd419afaab5ce26bb4e9056549f7ea6" - integrity sha512-GzzXCpOthOjXvrAUFQwU/svyxu658cwu00Q9ugujS4qc1zXgLFaO0kS2SLOaMWLt2Jik781yuHCWB7UcYdGAeQ== + version "17.0.27" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.27.tgz#6498ed9b3ad117e818deb5525fa1946c09f2e0e6" + integrity sha512-zgiJwtsggVGtr53MndV7jfiUESTqrbxOcBvwfe6KS/9bzaVPCTDieTWnFNecVNx6EAaapg5xsLLWFfHHR437AA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2418,33 +2706,34 @@ dependencies: "@types/yargs-parser" "*" -"@types/zen-observable@^0.8.0": +"@types/zen-observable@0.8.3", "@types/zen-observable@^0.8.0": version "0.8.3" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== "@typescript-eslint/eslint-plugin@^4.5.0": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.1.tgz#e938603a136f01dcabeece069da5fb2e331d4498" - integrity sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== dependencies: - "@typescript-eslint/experimental-utils" "4.31.1" - "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" + ignore "^5.1.8" regexpp "^3.1.0" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.31.1", "@typescript-eslint/experimental-utils@^4.0.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz#0c900f832f270b88e13e51753647b02d08371ce5" - integrity sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== +"@typescript-eslint/experimental-utils@4.33.0", "@typescript-eslint/experimental-utils@^4.0.1": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.31.1" - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/typescript-estree" "4.31.1" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -2460,32 +2749,32 @@ eslint-utils "^2.0.0" "@typescript-eslint/parser@^4.5.0": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.1.tgz#8f9a2672033e6f6d33b1c0260eebdc0ddf539064" - integrity sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== dependencies: - "@typescript-eslint/scope-manager" "4.31.1" - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/typescript-estree" "4.31.1" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" debug "^4.3.1" -"@typescript-eslint/scope-manager@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz#0c21e8501f608d6a25c842fcf59541ef4f1ab561" - integrity sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ== +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== dependencies: - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/visitor-keys" "4.31.1" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" "@typescript-eslint/types@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== -"@typescript-eslint/types@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.1.tgz#5f255b695627a13401d2fdba5f7138bc79450d66" - integrity sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ== +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== "@typescript-eslint/typescript-estree@3.10.1": version "3.10.1" @@ -2501,13 +2790,13 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz#4a04d5232cf1031232b7124a9c0310b577a62d17" - integrity sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg== +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== dependencies: - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/visitor-keys" "4.31.1" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -2521,12 +2810,12 @@ dependencies: eslint-visitor-keys "^1.1.0" -"@typescript-eslint/visitor-keys@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz#f2e7a14c7f20c4ae07d7fc3c5878c4441a1da9cc" - integrity sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ== +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== dependencies: - "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" "@webassemblyjs/ast@1.9.0": @@ -2682,6 +2971,13 @@ "@types/node" ">=6" tslib "^1.9.3" +"@wry/context@^0.6.0": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" + integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw== + dependencies: + tslib "^2.3.0" + "@wry/equality@^0.1.2", "@wry/equality@^0.1.9": version "0.1.11" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -2689,6 +2985,20 @@ dependencies: tslib "^1.9.3" +"@wry/equality@^0.5.0": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" + integrity sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.1.tgz#2279b790f15032f8bcea7fc944d27988e5b3b139" + integrity sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw== + dependencies: + tslib "^2.3.0" + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -2813,14 +3123,14 @@ alphanum-sort@^1.0.0: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= -anchor-link-browser-transport@^3.2.3: +anchor-link-browser-transport@^3.2.5: version "3.2.5" resolved "https://registry.yarnpkg.com/anchor-link-browser-transport/-/anchor-link-browser-transport-3.2.5.tgz#23440fab2353d6879e635dcb8190edca6a969cc9" integrity sha512-7X1KHEyi2LnUtlsbgmsh+hTjeYf8av3MMGk2k5FU7gzajkbkUMMFH/J9HGzLAAlY6wR0pjvgX6vy1slKqo4udg== dependencies: tslib "^2.0.3" -anchor-link@^3.3.2: +anchor-link@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/anchor-link/-/anchor-link-3.3.4.tgz#11a21f138bd143e68289005d81cad7be589bc94f" integrity sha512-9Wc2KTV6HLk50IXA3KEqWekLq0kSuKLQXXlIYliYCJnuTh3pZsjyg3jAo1ltjvtFiSEZdzo7wBcAre6RxEn3AA== @@ -2879,7 +3189,7 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-regex@^5.0.0: +ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== @@ -3048,11 +3358,6 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-differ@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" - integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -3064,15 +3369,15 @@ array-flatten@^2.1.0: integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== array-includes@^3.1.1, array-includes@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" - integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + es-abstract "^1.19.1" get-intrinsic "^1.1.1" - is-string "^1.0.5" + is-string "^1.0.7" array-union@^1.0.1: version "1.0.2" @@ -3096,24 +3401,23 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.3, array.prototype.flat@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123" - integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== +array.prototype.flat@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.19.0" -array.prototype.flatmap@^1.2.3, array.prototype.flatmap@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" - integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== +array.prototype.flatmap@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== dependencies: call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - function-bind "^1.1.1" + es-abstract "^1.19.0" arrify@^2.0.1: version "2.0.1" @@ -3163,11 +3467,6 @@ ast-types-flow@^0.0.7: resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -3211,15 +3510,15 @@ attr-accept@^2.2.1: integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== autoprefixer@^9.6.1: - version "9.8.6" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" - integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== + version "9.8.8" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" + integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== dependencies: browserslist "^4.12.0" caniuse-lite "^1.0.30001109" - colorette "^1.2.1" normalize-range "^0.1.2" num2fraction "^1.2.2" + picocolors "^0.2.1" postcss "^7.0.32" postcss-value-parser "^4.1.0" @@ -3305,7 +3604,7 @@ babel-plugin-jest-hoist@^26.6.2: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-macros@2.8.0: +babel-plugin-macros@2.8.0, babel-plugin-macros@^2.6.1: version "2.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== @@ -3328,13 +3627,13 @@ babel-plugin-polyfill-corejs2@^0.2.2: "@babel/helper-define-polyfill-provider" "^0.2.2" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz#68cb81316b0e8d9d721a92e0009ec6ecd4cd2ca9" - integrity sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ== +babel-plugin-polyfill-corejs3@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" + integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== dependencies: "@babel/helper-define-polyfill-provider" "^0.2.2" - core-js-compat "^3.14.0" + core-js-compat "^3.16.2" babel-plugin-polyfill-regenerator@^0.2.2: version "0.2.2" @@ -3712,16 +4011,16 @@ browserslist@4.14.2: escalade "^3.0.2" node-releases "^1.1.61" -browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.17.0, browserslist@^4.3.4, browserslist@^4.6.2, browserslist@^4.6.4: - version "4.17.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.0.tgz#1fcd81ec75b41d6d4994fb0831b92ac18c01649c" - integrity sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g== +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.17.3, browserslist@^4.3.4, browserslist@^4.6.2, browserslist@^4.6.4: + version "4.17.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.3.tgz#2844cd6eebe14d12384b0122d217550160d2d624" + integrity sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ== dependencies: - caniuse-lite "^1.0.30001254" - colorette "^1.3.0" - electron-to-chromium "^1.3.830" + caniuse-lite "^1.0.30001264" + electron-to-chromium "^1.3.857" escalade "^3.1.1" - node-releases "^1.1.75" + node-releases "^1.1.77" + picocolors "^0.2.1" bs58@4.0.1, bs58@^4.0.1: version "4.0.1" @@ -3934,10 +4233,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001254: - version "1.0.30001258" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001258.tgz#b604eed80cc54a578e4bf5a02ae3ed49f869d252" - integrity sha512-RBByOG6xWXUp0CR2/WU2amXz3stjKpSl5J1xU49F1n2OxD//uBZO4wCKUiG+QMGf7CHGfDDcqoKriomoGVxTeA== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001264: + version "1.0.30001265" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3" + integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw== capture-exit@^2.0.0: version "2.0.0" @@ -3977,7 +4276,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -4077,7 +4376,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@2.x, classnames@^2.2.1, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1: +classnames@2.x, classnames@^2.2.1, classnames@^2.2.5, classnames@^2.2.6: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== @@ -4213,11 +4512,16 @@ color@^3.0.0: color-convert "^1.9.3" color-string "^1.6.0" -colorette@^1.2.1, colorette@^1.2.2, colorette@^1.3.0, colorette@^1.4.0: +colorette@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== +colornames@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" + integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -4235,10 +4539,10 @@ commander@^4.0.0, commander@^4.1.1: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== -commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +commander@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== common-tags@^1.8.0: version "1.8.0" @@ -4250,6 +4554,11 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +compare-versions@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" + integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -4310,16 +4619,6 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" - integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.0.2" - typedarray "^0.0.6" - confusing-browser-globals@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" @@ -4340,11 +4639,6 @@ constants-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -4379,7 +4673,7 @@ convert-source-map@^0.3.3: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA= -convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== @@ -4418,28 +4712,28 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.14.0, core-js-compat@^3.16.0, core-js-compat@^3.6.2: - version "3.17.3" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.17.3.tgz#b39c8e4dec71ecdc735c653ce5233466e561324e" - integrity sha512-+in61CKYs4hQERiADCJsdgewpdl/X0GhEX77pjKgbeibXviIt2oxEjTc8O2fqHX8mDdBrDvX8MYD/RYsBv4OiA== +core-js-compat@^3.16.0, core-js-compat@^3.16.2, core-js-compat@^3.6.2: + version "3.18.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.18.2.tgz#e40c266fbd613948dd8d2d2156345da8ac03c142" + integrity sha512-25VJYCJtGjZwLguj7d66oiHfmnVw3TMOZ0zV8DyMJp/aeQ3OjR519iOOeck08HMyVVRAqXxafc2Hl+5QstJrsQ== dependencies: - browserslist "^4.17.0" + browserslist "^4.17.3" semver "7.0.0" core-js-pure@^3.16.0: - version "3.17.3" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.17.3.tgz#98ea3587188ab7ef4695db6518eeb71aec42604a" - integrity sha512-YusrqwiOTTn8058JDa0cv9unbXdIiIgcgI9gXso0ey4WgkFLd3lYlV9rp9n7nDCsYxXsMDTjA4m1h3T348mdlQ== + version "3.18.2" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.18.2.tgz#d8cc11d4885ea919f3de776d45e720e4c769d406" + integrity sha512-4hMMLUlZhKJKOWbbGD1/VDUxGPEhEoN/T01k7bx271WiBKCvCfkgPzy0IeRS4PB50p6/N1q/SZL4B/TRsTE5bA== core-js@^2.4.0, core-js@^2.6.5: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-js@^3.6.5: - version "3.17.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.17.3.tgz#8e8bd20e91df9951e903cabe91f9af4a0895bc1e" - integrity sha512-lyvajs+wd8N1hXfzob1LdOCCHFU4bGMbqqmLn1Q4QlCpDqWPpGf+p0nj+LNrvDDG33j0hZXw2nsvvVpHysxyNw== +core-js@^3.15.2, core-js@^3.6.5: + version "3.18.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.2.tgz#63a551e8a29f305cd4123754846e65896619ba5b" + integrity sha512-zNhPOUoSgoizoSQFdX1MeZO16ORRb9FFQLts8gSYbZU5FcgXhp24iMWMxnOQo5uIaIG7/6FA/IqJPwev1o9ZXQ== core-util-is@~1.0.0: version "1.0.3" @@ -4539,14 +4833,6 @@ create-react-class@^15.6.2: loose-envify "^1.3.1" object-assign "^4.1.1" -create-react-context@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" - integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - cross-fetch@^3.0.4: version "3.1.4" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" @@ -4554,7 +4840,7 @@ cross-fetch@^3.0.4: dependencies: node-fetch "2.6.1" -cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -4873,11 +5159,18 @@ csstype@^2.5.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.18.tgz#980a8b53085f34af313410af064f2bd241784218" integrity sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ== -csstype@^3.0.2: +csstype@^3.0.2, csstype@^3.0.9: version "3.0.9" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b" integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw== +customize-cra@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/customize-cra/-/customize-cra-1.0.0.tgz#73286563631aa08127ad4d30a2e3c89cf4e93c8d" + integrity sha512-DbtaLuy59224U+xCiukkxSq8clq++MOtJ1Et7LED1fLszWe88EoblEYFBJ895sB1mC6B4uu3xPT/IjClELhMbA== + dependencies: + lodash.flow "^3.5.0" + cyclist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" @@ -4905,6 +5198,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +date-fns@^2.24.0: + version "2.25.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680" + integrity sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w== + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -4912,7 +5210,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -5120,14 +5418,6 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -5300,10 +5590,10 @@ ejs@^2.6.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.830: - version "1.3.842" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.842.tgz#641e414012dded277468892c0156cb01984f4f6f" - integrity sha512-P/nDMPIYdb2PyqCQwhTXNi5JFjX1AsDVR0y6FrHw752izJIAJ+Pn5lugqyBq4tXeRSZBMBb2ZGvRGB1djtELEQ== +electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.857: + version "1.3.861" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.861.tgz#981e37a79af7a7b29bbaeed36376f4795527de13" + integrity sha512-GZyflmpMnZRdZ1e2yAyvuFwz1MPSVQelwHX4TJZyXypB8NcxdPvPNwy5lOTxnlkrK13EiQzyTPugRSnj6cBgKg== elliptic@6.5.0: version "6.5.0" @@ -5422,12 +5712,12 @@ env-cmd@^10.1.0: commander "^4.0.0" cross-spawn "^7.0.0" -eosio-signing-request@^2.2.0, eosio-signing-request@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/eosio-signing-request/-/eosio-signing-request-2.2.2.tgz#281cfe0843dc80205c89003d5638baf70fdcc449" - integrity sha512-lxRBHYkk2rAnnZrFnTqweD1FLH3usL5oE24m3+1zNK2vJHRVlIyUk7tlUlmax78j8+FE54Po8LQCQ8TrCSSFGg== +eosio-signing-request@^2.2.0, eosio-signing-request@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/eosio-signing-request/-/eosio-signing-request-2.3.1.tgz#9a0b09ec0dcb5cbd461516779fb47890af7365ef" + integrity sha512-74ouYaB00+Rq4lUxQMRtB9mXU+yd6vW9I6Iq3e8480CO0axaZc7h0ru2GBqO92InclmTnEFDYhr/MFK5yADiJg== dependencies: - "@greymass/eosio" "^0.4.0" + "@greymass/eosio" "^0.5.0" tslib "^2.0.3" eosjs-api@^7.0.4: @@ -5538,7 +5828,7 @@ errno@^0.1.3, errno@~0.1.7: dependencies: prr "~1.0.1" -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== @@ -5552,10 +5842,10 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.1.1" -es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: - version "1.18.6" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.6.tgz#2c44e3ea7a6255039164d26559777a6d978cb456" - integrity sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ== +es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" @@ -5568,7 +5858,9 @@ es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es- is-callable "^1.2.4" is-negative-zero "^2.0.1" is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" is-string "^1.0.7" + is-weakref "^1.0.1" object-inspect "^1.11.0" object-keys "^1.1.1" object.assign "^4.1.2" @@ -5653,7 +5945,7 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^8.3.0: +eslint-config-prettier@^8.1.0: version "8.3.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== @@ -5675,17 +5967,12 @@ eslint-config-standard-react@^11.0.1: resolved "https://registry.yarnpkg.com/eslint-config-standard-react/-/eslint-config-standard-react-11.0.1.tgz#1f488e0062c1e21c4c8584551619f11750658f55" integrity sha512-4WlBynOqBZJRaX81CBcIGDHqUiqxvw4j/DbEIICz8QkMs3xEncoPgAoysiqCSsg71X92uhaBc8sgqB96smaMmg== -eslint-config-standard@16.0.2: - version "16.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.2.tgz#71e91727ac7a203782d0a5ca4d1c462d14e234f6" - integrity sha512-fx3f1rJDsl9bY7qzyX8SAtP8GBSk6MfXFaTfaGgk12aAYW4gJSyRm7dM790L6cbXv63fvjY4XeSzXnb4WM+SKw== - -eslint-config-standard@^16.0.3: +eslint-config-standard@16.0.3, eslint-config-standard@^16.0.2: version "16.0.3" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz#6c8761e544e96c531ff92642eeb87842b8488516" integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg== -eslint-import-resolver-node@^0.3.4, eslint-import-resolver-node@^0.3.6: +eslint-import-resolver-node@^0.3.6: version "0.3.6" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== @@ -5693,7 +5980,7 @@ eslint-import-resolver-node@^0.3.4, eslint-import-resolver-node@^0.3.6: debug "^3.2.7" resolve "^1.20.0" -eslint-module-utils@^2.6.0, eslint-module-utils@^2.6.2: +eslint-module-utils@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz#94e5540dd15fe1522e8ffa3ec8db3b7fa7e7a534" integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q== @@ -5717,7 +6004,7 @@ eslint-plugin-flowtype@^5.2.0: lodash "^4.17.15" string-natural-compare "^3.0.1" -eslint-plugin-import@^2.22.1: +eslint-plugin-import@^2.22.1, eslint-plugin-import@~2.24.2: version "2.24.2" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz#2c8cd2e341f3885918ee27d18479910ade7bb4da" integrity sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q== @@ -5738,29 +6025,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.20.0" tsconfig-paths "^3.11.0" -eslint-plugin-import@~2.22.1: - version "2.22.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" - integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== - dependencies: - array-includes "^3.1.1" - array.prototype.flat "^1.2.3" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.0" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.1" - read-pkg-up "^2.0.0" - resolve "^1.17.0" - tsconfig-paths "^3.9.0" - eslint-plugin-jest@^24.1.0: - version "24.4.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.4.2.tgz#9e8cf05ee6a0e3025e6149df2f36950abfa8d5bf" - integrity sha512-jNMnqwX75z0RXRMXkxwb/+9ylKJYJLJ8nT8nBT0XFM5qx4IQGxP4edMawa0qGkSbHae0BDPBmi8I2QF0/F04XQ== + version "24.5.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.5.2.tgz#f71f98f27fd18b50f55246ca090f36d1730e36a6" + integrity sha512-lrI3sGAyZi513RRmP08sIW241Ti/zMnn/6wbE4ZBhb3M2pJ9ztaZMnSKSKKBUfotVdwqU8W1KtD8ao2/FR8DIg== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" @@ -5781,7 +6049,7 @@ eslint-plugin-jsx-a11y@^6.3.1: jsx-ast-utils "^3.1.0" language-tags "^1.0.5" -eslint-plugin-node@^11.0.0, eslint-plugin-node@~11.1.0: +eslint-plugin-node@^11.1.0, eslint-plugin-node@~11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== @@ -5793,63 +6061,66 @@ eslint-plugin-node@^11.0.0, eslint-plugin-node@~11.1.0: resolve "^1.10.1" semver "^6.1.0" -eslint-plugin-prettier@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" - integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== +eslint-plugin-prettier@^3.3.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" + integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-promise@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" - integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== +eslint-plugin-promise@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" + integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== + +eslint-plugin-promise@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz#fb2188fb734e4557993733b41aa1a688f46c6f24" + integrity sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng== eslint-plugin-react-hooks@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== -eslint-plugin-react@^7.21.5: - version "7.25.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.25.2.tgz#d567a217d306b76dd110561f28074e2328ae38f8" - integrity sha512-elx4585wgmryanJK4C5IoSKQyVZ+e7H0t2JOOtJNBql0cuercvSShvRReuLBbfx8687yW5yv+UL7pXwMsd6adQ== +eslint-plugin-react@^7.21.5, eslint-plugin-react@^7.22.0: + version "7.26.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz#41bcfe3e39e6a5ac040971c1af94437c80daa40e" + integrity sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ== dependencies: array-includes "^3.1.3" array.prototype.flatmap "^1.2.4" doctrine "^2.1.0" estraverse "^5.2.0" - has "^1.0.3" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.0.4" object.entries "^1.1.4" object.fromentries "^2.0.4" + object.hasown "^1.0.0" object.values "^1.1.4" prop-types "^15.7.2" resolve "^2.0.0-next.3" + semver "^6.3.0" string.prototype.matchall "^4.0.5" -eslint-plugin-react@~7.21.5: - version "7.21.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3" - integrity sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g== +eslint-plugin-react@~7.25.1: + version "7.25.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.25.3.tgz#3333a974772745ddb3aecea84621019b635766bc" + integrity sha512-ZMbFvZ1WAYSZKY662MBVEWR45VaBT6KSJCiupjrNlcdakB90juaZeDCbJq19e73JZQubqFtgETohwgAt8u5P6w== dependencies: - array-includes "^3.1.1" - array.prototype.flatmap "^1.2.3" + array-includes "^3.1.3" + array.prototype.flatmap "^1.2.4" doctrine "^2.1.0" - has "^1.0.3" + estraverse "^5.2.0" jsx-ast-utils "^2.4.1 || ^3.0.0" - object.entries "^1.1.2" - object.fromentries "^2.0.2" - object.values "^1.1.1" + minimatch "^3.0.4" + object.entries "^1.1.4" + object.fromentries "^2.0.4" + object.hasown "^1.0.0" + object.values "^1.1.4" prop-types "^15.7.2" - resolve "^1.18.1" - string.prototype.matchall "^4.0.2" - -eslint-plugin-standard@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz#c43f6925d669f177db46f095ea30be95476b1ee4" - integrity sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg== + resolve "^2.0.0-next.3" + string.prototype.matchall "^4.0.5" eslint-plugin-testing-library@^3.9.2: version "3.10.2" @@ -5893,7 +6164,7 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^2.0.0: +eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== @@ -5910,7 +6181,7 @@ eslint-webpack-plugin@^2.5.2: normalize-path "^3.0.0" schema-utils "^3.0.0" -eslint@^7.11.0: +eslint@^7.11.0, eslint@^7.22.0: version "7.32.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== @@ -5956,13 +6227,13 @@ eslint@^7.11.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -eslint@~7.13.0: - version "7.13.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.13.0.tgz#7f180126c0dcdef327bfb54b211d7802decc08da" - integrity sha512-uCORMuOO8tUzJmsdRtrvcGq5qposf7Rw0LwkTJkoDbOycVQtQjmnhZSuLQnozLE4TmAzlMVV45eCHmQ1OpDKUQ== +eslint@~7.18.0: + version "7.18.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.18.0.tgz#7fdcd2f3715a41fe6295a16234bd69aed2c75e67" + integrity sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ== dependencies: "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.2.1" + "@eslint/eslintrc" "^0.3.0" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -5972,10 +6243,10 @@ eslint@~7.13.0: eslint-scope "^5.1.1" eslint-utils "^2.1.0" eslint-visitor-keys "^2.0.0" - espree "^7.3.0" + espree "^7.3.1" esquery "^1.2.0" esutils "^2.0.2" - file-entry-cache "^5.0.1" + file-entry-cache "^6.0.0" functional-red-black-tree "^1.0.1" glob-parent "^5.0.0" globals "^12.1.0" @@ -5986,7 +6257,7 @@ eslint@~7.13.0: js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.19" + lodash "^4.17.20" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" @@ -5995,7 +6266,7 @@ eslint@~7.13.0: semver "^7.2.1" strip-ansi "^6.0.0" strip-json-comments "^3.1.0" - table "^5.2.3" + table "^6.0.4" text-table "^0.2.0" v8-compile-cache "^2.0.3" @@ -6118,7 +6389,7 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^4.0.0: +execa@^4.0.0, execa@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== @@ -6133,21 +6404,6 @@ execa@^4.0.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -6215,9 +6471,9 @@ express@^4.17.1: vary "~1.1.2" ext@^1.1.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.5.0.tgz#e93b97ae0cb23f8370380f6107d2d2b7887687ad" - integrity sha512-+ONcYoWj/SoQwUofMr94aGu05Ou4FepKi7N7b+O8T4jVfyIsZQV1/xeS8jpaBzF0csAk0KLXoHCxU7cKYZjo1Q== + version "1.6.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" + integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== dependencies: type "^2.5.0" @@ -6346,14 +6602,7 @@ figgy-pudding@^3.5.1: resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -file-entry-cache@^6.0.1: +file-entry-cache@^6.0.0, file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== @@ -6438,6 +6687,11 @@ find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -6460,14 +6714,20 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-versions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" + integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== + dependencies: + semver-regex "^3.1.2" flat-cache@^3.0.4: version "3.0.4" @@ -6477,11 +6737,6 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - flatted@^3.1.0: version "3.2.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" @@ -6501,9 +6756,9 @@ flush-write-stream@^1.0.0: readable-stream "^2.3.6" flux@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.1.tgz#7843502b02841d4aaa534af0b373034a1f75ee5c" - integrity sha512-emk4RCvJ8RzNP2lNpphKnG7r18q8elDYNAPx7xn+bDeOIo9FFfxEfIQ2y6YbQNmnsGD3nH1noxtLE64Puz1bRQ== + version "4.0.2" + resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.2.tgz#d71dcaf6cb51ca059f303f3d964d6f325d444952" + integrity sha512-u/ucO5ezm3nBvdaSGkWpDlzCePoV+a9x3KHmy13TV/5MzOaCZDN8Mfd94jmf0nOi8ZZay+nOKbBUkOe2VNaupQ== dependencies: fbemitter "^3.0.0" fbjs "^3.0.0" @@ -6698,11 +6953,6 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -6732,9 +6982,9 @@ glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: is-glob "^4.0.1" glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -6826,7 +7076,7 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== -graphql-tag@^2.12.5: +graphql-tag@^2.12.3, graphql-tag@^2.12.5: version "2.12.5" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.5.tgz#5cff974a67b417747d05c8d9f5f3cb4495d0db8f" integrity sha512-5xNhP4063d16Pz3HBtKprutsPrmHZi5IdUGOWRxA2B6VF7BIRGOHZ5WQvDmJXZuPcBg7rYwaFxvQYjqkSdR3TQ== @@ -6834,20 +7084,15 @@ graphql-tag@^2.12.5: tslib "^2.1.0" graphql@^15.5.1: - version "15.5.3" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.3.tgz#c72349017d5c9f5446a897fe6908b3186db1da00" - integrity sha512-sM+jXaO5KinTui6lbK/7b7H/Knj9BpjGxZ+Ki35v7YbUJxxdBCUqNM0h3CRVU1ZF9t5lNiBzvBCSYPvIwxPOQA== + version "15.6.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.6.1.tgz#9125bdf057553525da251e19e96dab3d3855ddfc" + integrity sha512-3i5lu0z6dRvJ48QP9kFxBkJ7h4Kso7PS8eahyTFz5Jm6CvQfLtNIE8LX9N6JLnXTuwR+sIYnXzaWp6anOg0QQw== growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= -gud@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" - integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== - gzip-size@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" @@ -6958,6 +7203,21 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== +hex-rgb@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776" + integrity sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw== + +highcharts-react-official@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/highcharts-react-official/-/highcharts-react-official-3.0.0.tgz#f2e81ed59d299c3473a0dd5ba5df24028875226a" + integrity sha512-VefJgDY2hkT9gfppsQGrRF2g5u8d9dtfHGcx2/xqiP+PkZXCqalw9xOeKVCRvJKTOh0coiDFwvVjOvB7KaGl4A== + +highcharts@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-9.2.2.tgz#4ace4aa7c4d2b4051115d9be70bfd2038559d656" + integrity sha512-OMEdFCaG626ES1JEcKAvJTpxAOMuchy0XuAplmnOs0Yu7NMd2RMfTLFQ2fCJOxo3ubSdm/RVQwKAWC+5HYThnw== + history@^4.9.0: version "4.10.1" resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" @@ -6970,6 +7230,13 @@ history@^4.9.0: tiny-warning "^1.0.0" value-equal "^1.0.1" +history@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/history/-/history-5.0.1.tgz#de35025ed08bce0db62364b47ebbf9d97b5eb06a" + integrity sha512-5qC/tFUKfVci5kzgRxZxN5Mf1CV8NmJx9ByaPX0YTLx5Vz3Svh7NYp6eA4CpDq4iA9D0C1t8BNIfvQIrUI3mVw== + dependencies: + "@babel/runtime" "^7.7.6" + hmac-drbg@^1.0.0, hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -6979,7 +7246,7 @@ hmac-drbg@^1.0.0, hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -7166,15 +7433,21 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -husky@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" - integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== +husky@4.3.8: + version "4.3.8" + resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" + integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== + dependencies: + chalk "^4.0.0" + ci-info "^2.0.0" + compare-versions "^3.6.0" + cosmiconfig "^7.0.0" + find-versions "^4.0.0" + opencollective-postinstall "^2.0.2" + pkg-dir "^5.0.0" + please-upgrade-node "^3.2.0" + slash "^3.0.0" + which-pm-runs "^1.0.0" hyphenate-style-name@^1.0.3: version "1.0.4" @@ -7205,7 +7478,7 @@ i18next@14.0.1: resolved "https://registry.yarnpkg.com/i18next/-/i18next-14.0.1.tgz#c5f0292ea6389394b6056f597b75f1f9aa03124f" integrity sha512-wsKfQuYsy4RdCaqqN71eDjWMhizhTfQSIBGttEA7vcboQrUfpQlCezrSzrtmoW9F9tmVyNs38iBgLYLMhRSeIQ== -i18next@^20.3.3: +i18next@^20.3.4: version "20.6.1" resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345" integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A== @@ -7255,7 +7528,7 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.1.4: +ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== @@ -7304,9 +7577,9 @@ import-local@^2.0.0: resolve-cwd "^2.0.0" import-local@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" - integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + version "3.0.3" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" + integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -7376,7 +7649,7 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" -invariant@^2.2.2, invariant@^2.2.3: +invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -7499,9 +7772,9 @@ is-color-stop@^1.0.0: rgba-regex "^1.0.0" is-core-module@^2.0.0, is-core-module@^2.2.0, is-core-module@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" - integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== + version "2.7.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.7.0.tgz#3c0ef7d31b4acfc574f80c58409d568a836848e3" + integrity sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ== dependencies: has "^1.0.3" @@ -7594,9 +7867,9 @@ is-glob@^3.1.0: is-extglob "^2.1.0" is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" @@ -7703,6 +7976,11 @@ is-root@2.1.0: resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -7737,6 +8015,13 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-weakref@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" + integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== + dependencies: + call-bind "^1.0.0" + is-what@^3.3.1: version "3.14.1" resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" @@ -7800,9 +8085,9 @@ isomorphic-ws@^4.0.1: integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.1.tgz#e8900b3ed6069759229cf30f7067388d148aeb5e" + integrity sha512-GvCYYTxaCPqwMjobtVcVKvSHtAGe48MNhGjpK8LtVF8K0ISX7hCKl85LgtuaSneWVyQmaGcW3iXVV3GaZSLpmQ== istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: version "4.0.3" @@ -7833,9 +8118,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + version "3.0.3" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.3.tgz#974d682037f6d12b15dc55f9a2a5f8f1ea923831" + integrity sha512-0i77ZFLsb9U3DHi22WzmIngVzfoyxxbQcZRqlF3KoKmCJGq9nhFHoGi8FqBztN2rE8w6hURnZghetn0xpkVb6A== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -7935,14 +8220,14 @@ jest-diff@^26.6.2: pretty-format "^26.6.2" jest-diff@^27.0.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.2.0.tgz#bda761c360f751bab1e7a2fe2fc2b0a35ce8518c" - integrity sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw== + version "27.2.4" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.2.4.tgz#171c51d3d2c105c457100fee6e7bf7cee51c8d8c" + integrity sha512-bLAVlDSCR3gqUPGv+4nzVpEXGsHh98HjUL7Vb2hVyyuBDoQmja8eJb0imUABsuxBeUVmf47taJSAd9nDrwWKEg== dependencies: chalk "^4.0.0" diff-sequences "^27.0.6" jest-get-type "^27.0.6" - pretty-format "^27.2.0" + pretty-format "^27.2.4" jest-docblock@^26.0.0: version "26.0.0" @@ -8416,70 +8701,70 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jss-plugin-camel-case@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.7.1.tgz#e7f7097cf97e9deec599cef3275e213452318b93" - integrity sha512-+ioIyWvmAfgDCWXsQcW1NMnLBvRinOVFkSYJUgewQ6TynOcSj5F1bSU23B7z0p1iqK0PPHIU62xY1iNJD33WGA== +jss-plugin-camel-case@^10.5.1, jss-plugin-camel-case@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.0.tgz#575fd849202d36713a6970796458e375754446c7" + integrity sha512-yxlXrXwcCdGw+H4BC187dEu/RFyW8joMcWfj8Rk9UPgWTKu2Xh7Sib4iW3xXjHe/t5phOHF1rBsHleHykWix7g== dependencies: "@babel/runtime" "^7.3.1" hyphenate-style-name "^1.0.3" - jss "10.7.1" + jss "10.8.0" -jss-plugin-default-unit@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.7.1.tgz#826270e2ee38d7024a281ac67c30d6944f124786" - integrity sha512-tW+dfYVNARBQb/ONzBwd8uyImigyzMiAEDai+AbH5rcHg5h3TtqhAkxx06iuZiT/dZUiFdSKlbe3q9jZGAPIwA== +jss-plugin-default-unit@^10.5.1, jss-plugin-default-unit@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.0.tgz#98db5962e62abbf43f1cc111e62cb70ffb09db59" + integrity sha512-9XJV546cY9zV9OvIE/v/dOaxSi4062VfYQQfwbplRExcsU2a79Yn+qDz/4ciw6P4LV1Naq90U+OffAGRHfNq/Q== dependencies: "@babel/runtime" "^7.3.1" - jss "10.7.1" + jss "10.8.0" -jss-plugin-global@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.7.1.tgz#9725c46d662aac2e596a0a8741944c060e2b90a1" - integrity sha512-FbxCnu44IkK/bw8X3CwZKmcAnJqjAb9LujlAc/aP0bMSdVa3/MugKQRyeQSu00uGL44feJJDoeXXiHOakBr/Zw== +jss-plugin-global@^10.5.1, jss-plugin-global@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.8.0.tgz#0c2b0c056087f5846d600f3332eeb7a1a8b9c9f2" + integrity sha512-H/8h/bHd4e7P0MpZ9zaUG8NQSB2ie9rWo/vcCP6bHVerbKLGzj+dsY22IY3+/FNRS8zDmUyqdZx3rD8k4nmH4w== dependencies: "@babel/runtime" "^7.3.1" - jss "10.7.1" + jss "10.8.0" -jss-plugin-nested@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.7.1.tgz#35563a7a710a45307fd6b9742ffada1d72a62eb7" - integrity sha512-RNbICk7FlYKaJyv9tkMl7s6FFfeLA3ubNIFKvPqaWtADK0KUaPsPXVYBkAu4x1ItgsWx67xvReMrkcKA0jSXfA== +jss-plugin-nested@^10.5.1, jss-plugin-nested@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.8.0.tgz#7ef9a815e9c9fbede41a8f52ce75cffb4c3b86d5" + integrity sha512-MhmINZkSxyFILcFBuDoZmP1+wj9fik/b9SsjoaggkGjdvMQCES21mj4K5ZnRGVm448gIXyi9j/eZjtDzhaHUYQ== dependencies: "@babel/runtime" "^7.3.1" - jss "10.7.1" + jss "10.8.0" tiny-warning "^1.0.2" -jss-plugin-props-sort@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.7.1.tgz#1d12b26048541ed3a2ed1b69f7fc231605728362" - integrity sha512-eyd5FhA+J0QrpqXxO7YNF/HMSXXl4pB0EmUdY4vSJI4QG22F59vQ6AHtP6fSwhmBdQ98Qd9gjfO+RMxcE39P1A== +jss-plugin-props-sort@^10.5.1, jss-plugin-props-sort@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.0.tgz#2a83e8ca80d72828495bad57b485f7d55a33543b" + integrity sha512-VY+Wt5WX5GMsXDmd+Ts8+O16fpiCM81svbox++U3LDbJSM/g9FoMx3HPhwUiDfmgHL9jWdqEuvSl/JAk+mh6mQ== dependencies: "@babel/runtime" "^7.3.1" - jss "10.7.1" + jss "10.8.0" -jss-plugin-rule-value-function@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.7.1.tgz#123eb796eb9982f8efa7a7e362daddd90c0c69fe" - integrity sha512-fGAAImlbaHD3fXAHI3ooX6aRESOl5iBt3LjpVjxs9II5u9tzam7pqFUmgTcrip9VpRqYHn8J3gA7kCtm8xKwHg== +jss-plugin-rule-value-function@^10.5.1, jss-plugin-rule-value-function@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.0.tgz#e011ed180789229e7ea8f75c222d34810bcab520" + integrity sha512-R8N8Ma6Oye1F9HroiUuHhVjpPsVq97uAh+rMI6XwKLqirIu2KFb5x33hPj+vNBMxSHc9jakhf5wG0BbQ7fSDOg== dependencies: "@babel/runtime" "^7.3.1" - jss "10.7.1" + jss "10.8.0" tiny-warning "^1.0.2" -jss-plugin-vendor-prefixer@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.7.1.tgz#217821be2d6dacee31d2d464886760ba7742e19a" - integrity sha512-1UHFmBn7hZNsHXTkLLOL8abRl8vi+D1EVzWD4WmLFj55vawHZfnH1oEz6TUf5Y61XHv0smdHabdXds6BgOXe3A== +jss-plugin-vendor-prefixer@^10.5.1, jss-plugin-vendor-prefixer@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.0.tgz#024b6d77be50b68e5dfca2c75f68091d8b722d61" + integrity sha512-G1zD0J8dFwKZQ+GaZaay7A/Tg7lhDw0iEkJ/iFFA5UPuvZFpMprCMQttXcTBhLlhhWnyZ8YPn4yqp+amrhQekw== dependencies: "@babel/runtime" "^7.3.1" css-vendor "^2.0.8" - jss "10.7.1" + jss "10.8.0" -jss@10.7.1, jss@^10.5.1: - version "10.7.1" - resolved "https://registry.yarnpkg.com/jss/-/jss-10.7.1.tgz#16d846e1a22fb42e857b99f9c6a0c5a27341c804" - integrity sha512-5QN8JSVZR6cxpZNeGfzIjqPEP+ZJwJJfZbXmeABNdxiExyO+eJJDy6WDtqTf8SDKnbL5kZllEpAP71E/Lt7PXg== +jss@10.8.0, jss@^10.5.1, jss@^10.8.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/jss/-/jss-10.8.0.tgz#5063ee73aabd9f228ea3849df7962f0d2e213a42" + integrity sha512-6fAMLJrVQ8epM5ghghxWqCwRR0ZamP2cKbOAtzPudcCMSNdAqtvmzQvljUZYR8OXJIeb/IpZeOXA1sDXms4R1w== dependencies: "@babel/runtime" "^7.3.1" csstype "^3.0.2" @@ -8579,30 +8864,31 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= -lint-staged@^11.0.1: - version "11.1.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.1.2.tgz#4dd78782ae43ee6ebf2969cad9af67a46b33cd90" - integrity sha512-6lYpNoA9wGqkL6Hew/4n1H6lRqF3qCsujVT0Oq5Z4hiSAM7S6NksPJ3gnr7A7R52xCtiZMcEUNNQ6d6X5Bvh9w== +lint-staged@^10.5.4: + version "10.5.4" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.5.4.tgz#cd153b5f0987d2371fc1d2847a409a2fe705b665" + integrity sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg== dependencies: - chalk "^4.1.1" + chalk "^4.1.0" cli-truncate "^2.1.0" - commander "^7.2.0" + commander "^6.2.0" cosmiconfig "^7.0.0" - debug "^4.3.1" + debug "^4.2.0" + dedent "^0.7.0" enquirer "^2.3.6" - execa "^5.0.0" - listr2 "^3.8.2" - log-symbols "^4.1.0" - micromatch "^4.0.4" + execa "^4.1.0" + listr2 "^3.2.2" + log-symbols "^4.0.0" + micromatch "^4.0.2" normalize-path "^3.0.0" please-upgrade-node "^3.2.0" string-argv "0.3.1" stringify-object "^3.3.0" -listr2@^3.8.2: - version "3.12.1" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.12.1.tgz#75e515b86c66b60baf253542cc0dced6b60fedaf" - integrity sha512-oB1DlXlCzGPbvWhqYBZUQEPJKqsmebQWofXG6Mpbe3uIvoNl8mctBEojyF13ZyqwQ91clCWXpwsWp+t98K4FOQ== +listr2@^3.2.2: + version "3.12.2" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.12.2.tgz#2d55cc627111603ad4768a9e87c9c7bb9b49997e" + integrity sha512-64xC2CJ/As/xgVI3wbhlPWVPx0wfTqbUAkpb7bjDi0thSWMqrf07UFhrfsGoo8YSXmF049Rp9C0cjLC8rZxK9A== dependencies: cli-truncate "^2.1.0" colorette "^1.4.0" @@ -8612,16 +8898,6 @@ listr2@^3.8.2: through "^2.3.8" wrap-ansi "^7.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -8698,6 +8974,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash-es@^4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" @@ -8723,7 +9006,7 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash.flow@^3.3.0: +lodash.flow@^3.3.0, lodash.flow@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o= @@ -8748,6 +9031,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.padend@^4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" + integrity sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4= + lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" @@ -8768,6 +9056,11 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" +lodash.trimstart@^4.5.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/lodash.trimstart/-/lodash.trimstart-4.5.1.tgz#8ff4dec532d82486af59573c39445914e944a7f1" + integrity sha1-j/TexTLYJIavWVc8OURZFOlEp/E= + lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -8778,12 +9071,17 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +lodash.words@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.words/-/lodash.words-4.2.0.tgz#5ecfeaf8ecf8acaa8e0c8386295f1993c9cf4036" + integrity sha1-Xs/q+Oz4rKqODIOGKV8Zk8nPQDY= + "lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.1.0: +log-symbols@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -9015,12 +9313,7 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.49.0: - version "1.49.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" - integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== - -"mime-db@>= 1.43.0 < 2": +mime-db@1.50.0, "mime-db@>= 1.43.0 < 2": version "1.50.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== @@ -9038,11 +9331,11 @@ mime-types@2.1.18: mime-db "~1.33.0" mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24: - version "2.1.32" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" - integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A== + version "2.1.33" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" + integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== dependencies: - mime-db "1.49.0" + mime-db "1.50.0" mime@1.6.0: version "1.6.0" @@ -9195,11 +9488,6 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" -mri@^1.1.5: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" - integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -9233,17 +9521,6 @@ multicast-dns@^6.0.1: dns-packet "^1.3.1" thunky "^1.0.2" -multimatch@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" - integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== - dependencies: - "@types/minimatch" "^3.0.3" - array-differ "^3.0.0" - array-union "^2.1.0" - arrify "^2.0.1" - minimatch "^3.0.4" - nan@^2.12.1: version "2.15.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" @@ -9254,10 +9531,10 @@ nanoclone@^0.2.1: resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA== -nanoid@^3.1.23: - version "3.1.25" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" - integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== +nanoid@^3.1.28: + version "3.1.29" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.29.tgz#214fb2d7a33e1a5bef4757b779dfaeb6a4e5aeb4" + integrity sha512-dW2pUSGZ8ZnCFIlBIA31SV8huOGCHb6OwzVCc7A69rb/a+SgPBwfmLvK5TKQ3INPbRkcI8a/Owo0XbiTNH19wg== nanomatch@^1.2.9: version "1.2.13" @@ -9337,9 +9614,11 @@ node-fetch@^1.0.1: is-stream "^1.0.1" node-fetch@^2.6.2, node-fetch@~2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.2.tgz#986996818b73785e47b1965cc34eb093a1d464d0" - integrity sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA== + version "2.6.5" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" + integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== + dependencies: + whatwg-url "^5.0.0" node-forge@^0.10.0: version "0.10.0" @@ -9397,10 +9676,10 @@ node-notifier@^8.0.0: uuid "^8.3.0" which "^2.0.2" -node-releases@^1.1.61, node-releases@^1.1.75: - version "1.1.75" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe" - integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw== +node-releases@^1.1.61, node-releases@^1.1.77: + version "1.1.77" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" + integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" @@ -9451,7 +9730,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npm-run-path@^4.0.0, npm-run-path@^4.0.1: +npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -9536,33 +9815,40 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.0, object.entries@^1.1.2, object.entries@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" - integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== +object.entries@^1.1.0, object.entries@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" -object.fromentries@^2.0.2, object.fromentries@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" - integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== +object.fromentries@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" + es-abstract "^1.19.1" object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" - integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== + version "2.1.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + es-abstract "^1.19.1" + +object.hasown@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.19.1" object.pick@^1.3.0: version "1.3.0" @@ -9571,14 +9857,14 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.0, object.values@^1.1.1, object.values@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" - integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== +object.values@^1.1.0, object.values@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" @@ -9604,7 +9890,7 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -9619,6 +9905,11 @@ open@^7.0.2: is-docker "^2.0.0" is-wsl "^2.1.1" +opencollective-postinstall@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" + integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + opn@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" @@ -9633,6 +9924,14 @@ optimism@^0.10.0: dependencies: "@wry/context" "^0.4.0" +optimism@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d" + integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg== + dependencies: + "@wry/context" "^0.6.0" + "@wry/trie" "^0.3.0" + optimize-css-assets-webpack-plugin@5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz#85883c6528aaa02e30bbad9908c92926bb52dc90" @@ -9729,6 +10028,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" @@ -9808,13 +10114,6 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -9918,13 +10217,6 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -9948,11 +10240,21 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +perfect-scrollbar@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.2.tgz#41167ac6bc95e3a5e87a7402fa36fdacca9bc298" + integrity sha512-McHAinFkyzKbBZrFtb4MT2mxkehp15KvOX/UrjB8C5EZZXHTHgyETo5IGFYtHRTI2Pb2bsV0OE0YnkjT9Cw3aw== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: version "2.3.0" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" @@ -10021,6 +10323,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + pkg-up@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" @@ -10049,6 +10358,13 @@ pnp-webpack-plugin@1.6.4: dependencies: ts-pnp "^1.1.6" +polished@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/polished/-/polished-4.1.3.tgz#7a3abf2972364e7d97770b827eec9a9e64002cfc" + integrity sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA== + dependencies: + "@babel/runtime" "^7.14.0" + popper.js@1.16.1-lts: version "1.16.1-lts" resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" @@ -10708,7 +11024,7 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@7.0.36, postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: +postcss@7.0.36: version "7.0.36" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.36.tgz#056f8cffa939662a8f5905950c07d5285644dfcb" integrity sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw== @@ -10717,13 +11033,21 @@ postcss@7.0.36, postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, pos source-map "^0.6.1" supports-color "^6.1.0" +postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + postcss@^8.1.0: - version "8.3.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" - integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A== + version "8.3.9" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.9.tgz#98754caa06c4ee9eb59cc48bd073bb6bd3437c31" + integrity sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw== dependencies: - colorette "^1.2.2" - nanoid "^3.1.23" + nanoid "^3.1.28" + picocolors "^0.2.1" source-map-js "^0.6.2" prelude-ls@^1.2.1: @@ -10748,7 +11072,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.3.2: +prettier@^2.2.1: version "2.4.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== @@ -10776,28 +11100,16 @@ pretty-format@^26.6.0, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" -pretty-format@^27.0.0, pretty-format@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.2.0.tgz#ee37a94ce2a79765791a8649ae374d468c18ef19" - integrity sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA== +pretty-format@^27.0.0, pretty-format@^27.2.4: + version "27.2.4" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.2.4.tgz#08ea39c5eab41b082852d7093059a091f6ddc748" + integrity sha512-NUjw22WJHldzxyps2YjLZkUj6q1HvjqFezkB9Y2cklN8NtVZN/kZEXGZdFw4uny3oENzV5EEMESrkI0YDUH8vg== dependencies: - "@jest/types" "^27.1.1" - ansi-regex "^5.0.0" + "@jest/types" "^27.2.4" + ansi-regex "^5.0.1" ansi-styles "^5.0.0" react-is "^17.0.1" -pretty-quick@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-3.1.1.tgz#93ca4e2dd38cc4e970e3f54a0ead317a25454688" - integrity sha512-ZYLGiMoV2jcaas3vTJrLvKAYsxDoXQBUn8OSTxkl67Fyov9lyXivJTl0+2WVh+y6EovGcw7Lm5ThYpH+Sh3XxQ== - dependencies: - chalk "^3.0.0" - execa "^4.0.0" - find-up "^4.1.0" - ignore "^5.1.4" - mri "^1.1.5" - multimatch "^4.0.0" - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -11139,6 +11451,13 @@ react-app-polyfill@^2.0.0: regenerator-runtime "^0.13.7" whatwg-fetch "^3.4.1" +react-app-rewired@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/react-app-rewired/-/react-app-rewired-2.1.8.tgz#e192f93b98daf96889418d33d3e86cf863812b56" + integrity sha512-wjXPdKPLscA7mn0I1de1NHrbfWdXz4S1ladaGgHVKdn1hTgKK5N6EdGIJM0KrS6bKnJBj7WuqJroDTsPKKr66Q== + dependencies: + semver "^5.6.0" + react-async-script@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/react-async-script/-/react-async-script-1.2.0.tgz#ab9412a26f0b83f5e2e00de1d2befc9400834b21" @@ -11168,13 +11487,6 @@ react-base16-styling@^0.6.0: lodash.flow "^3.3.0" pure-color "^1.2.0" -react-chartjs-2@^3.0.4: - version "3.0.5" - resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-3.0.5.tgz#afc23993a32e146bdcc9addff16a28d8964b98ad" - integrity sha512-fYr4E82agaZi9IFMe5GtOZ6WE/HWdxy/KywLNOzXsqgPkD2oo1IlrQLKMLUki/2UXko3p95TR2L8Q2rEss/opQ== - dependencies: - lodash "^4.17.19" - react-dev-utils@^11.0.3: version "11.0.4" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a" @@ -11205,7 +11517,7 @@ react-dev-utils@^11.0.3: strip-ansi "6.0.0" text-table "0.2.0" -react-dom@16.13.0, react-dom@17.0.2: +react-dom@16.13.0, react-dom@17.0.2, react-dom@~17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== @@ -11215,9 +11527,9 @@ react-dom@16.13.0, react-dom@17.0.2: scheduler "^0.20.2" react-dropzone@^11.4.0: - version "11.4.0" - resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.4.0.tgz#bbf3b2491341864c91c218a606a7f2568e5a94a8" - integrity sha512-5NRpAN4ZmpEn0kvtkO18rPInE7n4eVjGeTLP/c0JcGAnV+5yrpr5QHdPH27M05SP2tsjkRoRf02DCK/4fxbsog== + version "11.4.2" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.4.2.tgz#1eb99e9def4cc7520f4f58e85c853ce52c483d56" + integrity sha512-ocYzYn7Qgp0tFc1gQtUTOaHHSzVTwhWHxxY+r7cj2jJTPfMTZB5GWSJHdIVoxsl+EQENpjJ/6Zvcw0BqKZQ+Eg== dependencies: attr-accept "^2.2.1" file-selector "^0.2.2" @@ -11233,6 +11545,13 @@ react-fast-compare@^3.1.1: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== +react-feather@^2.0.9: + version "2.0.9" + resolved "https://registry.yarnpkg.com/react-feather/-/react-feather-2.0.9.tgz#6e42072130d2fa9a09d4476b0e61b0ed17814480" + integrity sha512-yMfCGRkZdXwIs23Zw/zIWCJO3m3tlaUvtHiXlW+3FH7cIT6fiK1iJ7RJWugXq7Fso8ZaQyUm92/GOOHXvkiVUw== + dependencies: + prop-types "^15.7.2" + react-file-download@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/react-file-download/-/react-file-download-0.3.5.tgz#7a4e75874528806bfa53ddddd98b4da427d3a897" @@ -11271,7 +11590,7 @@ react-highlighter@^0.4.3: escape-string-regexp "^1.0.5" prop-types "^15.6.0" -react-i18next@^11.11.2: +react-i18next@^11.11.3: version "11.12.0" resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.12.0.tgz#2a053321b9b7a876d5baa7af55a12d986117bffc" integrity sha512-M9BT+hqVG03ywrl+L7CK74ugK+4jIo7AeKJ17+g9BoqJz2+/aVbs8SIVXT4KMQ1rjIdcw+GcSRDy1CXjcz6tLQ== @@ -11286,17 +11605,22 @@ react-icons@3.9.0: dependencies: camelcase "^5.0.0" +react-icons@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.1.0.tgz#9ca9bcbf2e3aee8e86e378bb9d465842947bbfc3" + integrity sha512-FCXBg1JbbR0vWALXIxmFAfozHdVIJmmwCD81Jk0EKOt7Ax4AdBNcaRkWhR0NaKy9ugJgoY3fFvo0PHpte55pXg== + react-identicons@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/react-identicons/-/react-identicons-1.2.5.tgz#3502249e49d88f4e3500092694410a984bb102fa" integrity sha512-x7prkDoc2pD7wSl2C1pGxS+XAoSdq1ABWJWTBUimVTDVJArKOLd0B4wRUJpDm4r+9y7pgf8ylyPGsmlWSV5n2g== -react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -"react-is@^16.8.0 || ^17.0.0", react-is@^17.0.1: +"react-is@^16.8.0 || ^17.0.0", react-is@^17.0.1, react-is@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== @@ -11316,29 +11640,38 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-perfect-scrollbar@^1.5.8: + version "1.5.8" + resolved "https://registry.yarnpkg.com/react-perfect-scrollbar/-/react-perfect-scrollbar-1.5.8.tgz#380959387a325c5c9d0268afc08b3f73ed5b3078" + integrity sha512-bQ46m70gp/HJtiBOF3gRzBISSZn8FFGNxznTdmTG8AAwpxG1bJCyn7shrgjEvGSQ5FJEafVEiosY+ccER11OSA== + dependencies: + perfect-scrollbar "^1.5.0" + prop-types "^15.6.1" + react-placeholder@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/react-placeholder/-/react-placeholder-4.1.0.tgz#943128820b3b0a6f94371655aadec18d306e05e3" integrity sha512-z1HGD86NWJTYTQumHsmGH9jkozv4QHa9dju/vHVUd4f1svu23pf5v7QoBLBfs3kA1S9GLJaCeRMHLbO2SCdz5A== -react-redux@^7.2.4: - version "7.2.5" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.5.tgz#213c1b05aa1187d9c940ddfc0b29450957f6a3b8" - integrity sha512-Dt29bNyBsbQaysp6s/dN0gUodcq+dVKKER8Qv82UrpeygwYeX1raTtil7O/fftw/rFqzaf6gJhDZRkkZnn6bjg== - dependencies: - "@babel/runtime" "^7.12.1" - "@types/react-redux" "^7.1.16" - hoist-non-react-statics "^3.3.2" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-is "^16.13.1" - react-refresh@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== -react-router@^5.2.1: +react-router-dom@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363" + integrity sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.1" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.1, react-router@^5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.1.tgz#4d2e4e9d5ae9425091845b8dbc6d9d276239774d" integrity sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ== @@ -11354,7 +11687,7 @@ react-router@^5.2.1: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react-scripts@4.0.3: +react-scripts@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-4.0.3.tgz#b1cafed7c3fa603e7628ba0f187787964cb5d345" integrity sha512-S5eO4vjUzUisvkIPB7jVsKtuH2HhWcASREYWHAQ1FP5HyCv3xgn+wpILAEWkmy+A+tTNbSZClhxjT3qz6g4L1A== @@ -11449,7 +11782,7 @@ react-tooltip@3.9.2: classnames "^2.2.5" prop-types "^15.6.0" -react-transition-group@^4.4.0: +react-transition-group@^4.4.0, react-transition-group@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== @@ -11471,7 +11804,7 @@ react-virtualized@^9.22.3: prop-types "^15.7.2" react-lifecycles-compat "^3.0.4" -react@16.13.0, react@17.0.2: +react@16.13.0, react@17.0.2, react@~17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== @@ -11479,14 +11812,6 @@ react@16.13.0, react@17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - read-pkg-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" @@ -11504,15 +11829,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -11545,7 +11861,7 @@ read-pkg@^5.2.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.6.0: +readable-stream@^3.0.6, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -11585,18 +11901,6 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -redux-persist@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8" - integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ== - -redux@^4.0.0, redux@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47" - integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw== - dependencies: - "@babel/runtime" "^7.9.2" - regenerate-unicode-properties@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" @@ -11862,6 +12166,11 @@ rework@1.0.1: convert-source-map "^0.3.3" css "^2.0.0" +rgb-hex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/rgb-hex/-/rgb-hex-3.0.0.tgz#eab0168cc1279563b18a14605315389142e2e487" + integrity sha512-8h7ZcwxCBDKvchSWbWngJuSCqJGQ6nDuLLg+QcRyQDbX9jMWt+PpPeXAhSla0GOooEomk3lCprUpGkMdsLjKyg== + rgb-regex@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" @@ -11872,12 +12181,10 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" +rifm@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.0.tgz#8d3a9dc0de9c190e0de9bdc8861a91a221dc1341" + integrity sha512-PqOl+Mo2lyqrKiD34FPlnQ+ksD3F+a62TQlphiZshgriyHdfjn6jGyqUZhd+s3nsMYXwXYDdjrrv8wX7QsOG3g== rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" @@ -12084,6 +12391,11 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= +semver-regex@^3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.3.tgz#b2bcc6f97f63269f286994e297e229b6245d0dc3" + integrity sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ== + "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -12295,10 +12607,10 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.4.tgz#366a4684d175b9cab2081e3681fda3747b6c51d7" - integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q== +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.5" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" + integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== simple-swizzle@^0.2.2: version "0.2.2" @@ -12317,15 +12629,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - slice-ansi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" @@ -12374,19 +12677,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -snazzy@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/snazzy/-/snazzy-9.0.0.tgz#663639d059efd96c89f2aa63272acfacc5feda1f" - integrity sha512-8QZmJb11OiYaUP90Nnjqcj/LEpO8CLgChnP87Wqjv5tNB4djwHaz27VO2usSRR0NmViapeGW04p0aWAMhxxLXg== - dependencies: - chalk "^4.1.0" - inherits "^2.0.4" - minimist "^1.2.5" - readable-stream "^3.6.0" - standard-json "^1.1.0" - strip-ansi "^6.0.0" - text-table "^0.2.0" - sockjs-client@^1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" @@ -12462,7 +12752,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -12579,25 +12869,18 @@ standard-engine@^14.0.1: pkg-conf "^3.1.0" xdg-basedir "^4.0.0" -standard-json@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/standard-json/-/standard-json-1.1.0.tgz#33ac0d2eccaddb0556f5ae28c43a35624cf1fb25" - integrity sha512-nkonX+n5g3pyVBvJZmvRlFtT/7JyLbNh4CtrYC3Qfxihgs8PKX52f6ONKQXORStuBWJ5PI83EUrNXme7LKfiTQ== - dependencies: - concat-stream "^2.0.0" - standard@^16.0.3: - version "16.0.3" - resolved "https://registry.yarnpkg.com/standard/-/standard-16.0.3.tgz#a854c0dd2dea6b9f0b8d20c65260210bd0cee619" - integrity sha512-70F7NH0hSkNXosXRltjSv6KpTAOkUkSfyu3ynyM5dtRUiLtR+yX9EGZ7RKwuGUqCJiX/cnkceVM6HTZ4JpaqDg== + version "16.0.4" + resolved "https://registry.yarnpkg.com/standard/-/standard-16.0.4.tgz#779113ba41dd218ab545e7b4eb2405561f6eb370" + integrity sha512-2AGI874RNClW4xUdM+bg1LRXVlYLzTNEkHmTG5mhyn45OhbgwA+6znowkOGYy+WMb5HRyELvtNy39kcdMQMcYQ== dependencies: - eslint "~7.13.0" - eslint-config-standard "16.0.2" + eslint "~7.18.0" + eslint-config-standard "16.0.3" eslint-config-standard-jsx "10.0.0" - eslint-plugin-import "~2.22.1" + eslint-plugin-import "~2.24.2" eslint-plugin-node "~11.1.0" - eslint-plugin-promise "~4.2.1" - eslint-plugin-react "~7.21.5" + eslint-plugin-promise "~5.1.0" + eslint-plugin-react "~7.25.1" standard-engine "^14.0.1" static-extend@^0.1.1: @@ -12668,6 +12951,18 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== +string-to-color@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/string-to-color/-/string-to-color-2.2.2.tgz#46210bf7777dc9198dcdf997bd18ae6749cc9a73" + integrity sha512-XeA2goP7PNsSlz8RRn6KhYswnMf5Tl+38ajfy8n4oZJyMGC4qqKgHNHsZ/3qwvr42NRIjf9eSr721SyetDeMkA== + dependencies: + colornames "^1.1.1" + hex-rgb "^4.1.0" + lodash.padend "^4.6.1" + lodash.trimstart "^4.5.1" + lodash.words "^4.2.0" + rgb-hex "^3.0.0" + string-width@^2.0.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -12685,23 +12980,23 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" -string.prototype.matchall@^4.0.2, string.prototype.matchall@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz#59370644e1db7e4c0c045277690cf7b01203c4da" - integrity sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q== +string.prototype.matchall@^4.0.5: + version "4.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" get-intrinsic "^1.1.1" has-symbols "^1.0.2" internal-slot "^1.0.3" @@ -12747,7 +13042,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -strip-ansi@6.0.0, strip-ansi@^6.0.0: +strip-ansi@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== @@ -12775,6 +13070,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -12866,6 +13168,11 @@ stylis@^3.5.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe" integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q== +stylis@^4.0.3: + version "4.0.10" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240" + integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg== + subscriptions-transport-ws@^0.9.19: version "0.9.19" resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz#10ca32f7e291d5ee8eb728b9c02e43c52606cdcf" @@ -12935,32 +13242,27 @@ symbol-observable@^1.0.2, symbol-observable@^1.0.4: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -table@^6.0.9: - version "6.7.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== +table@^6.0.4, table@^6.0.9: + version "6.7.2" + resolved "https://registry.yarnpkg.com/table/-/table-6.7.2.tgz#a8d39b9f5966693ca8b0feba270a78722cbaf3b0" + integrity sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g== dependencies: ajv "^8.0.1" lodash.clonedeep "^4.5.0" lodash.truncate "^4.4.2" slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" @@ -13048,9 +13350,9 @@ terser@^4.1.2, terser@^4.6.2, terser@^4.6.3: source-map-support "~0.5.12" terser@^5.3.4: - version "5.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.8.0.tgz#c6d352f91aed85cc6171ccb5e84655b77521d947" - integrity sha512-f0JH+6yMpneYcRJN314lZrSwu9eKkUFEHLN/kNy8ceh8gaRiLgFPJqrB9HsXjhEGdv4e/ekjTOFxIlL6xlma8A== + version "5.9.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351" + integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ== dependencies: commander "^2.20.0" source-map "~0.7.2" @@ -13200,6 +13502,11 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + tryer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" @@ -13217,12 +13524,19 @@ ts-invariant@^0.4.0, ts-invariant@^0.4.4: dependencies: tslib "^1.9.3" +ts-invariant@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.3.tgz#4b41e0a80c2530a56ce4b8fd4e14183aaac0efa8" + integrity sha512-HinBlTbFslQI0OHP07JLsSXPibSegec6r9ai5xxq/qHYCsIQbzpymLpDhAUsnXcSrDEcd0L62L8vsOEdzM0qlA== + dependencies: + tslib "^2.1.0" + ts-pnp@1.2.0, ts-pnp@^1.1.6: version "1.2.0" resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== -tsconfig-paths@^3.11.0, tsconfig-paths@^3.9.0: +tsconfig-paths@^3.11.0: version "3.11.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA== @@ -13237,7 +13551,7 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0: +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -13344,15 +13658,15 @@ ua-parser-js@^0.7.18: integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== ual-anchor@^1.0.6: - version "1.0.9" - resolved "https://registry.yarnpkg.com/ual-anchor/-/ual-anchor-1.0.9.tgz#c777e9f3d69cdd6affa46de914732847027e5477" - integrity sha512-aaQ//gJ8tQnsmaEe5iiFbJovKuiTFJ8FPNUrlvHLjaMqJnjFbprDT4AhLfpHHe+9fwSp/ol8wP4spPACpuofPg== + version "1.1.1" + resolved "https://registry.yarnpkg.com/ual-anchor/-/ual-anchor-1.1.1.tgz#0dae8979ff97e13e7ca1cdf05dd15f4cd6bb6fb6" + integrity sha512-yuUed9f2fNGibDxMjwqUEwz2KiQEBDKVL8ESA5k8eqfWi/tFBmcjWIs5U3JblwybmeyisTLDUigVSoiiaBZgAw== dependencies: - "@greymass/eosio" "^0.4.3" - anchor-link "^3.3.2" - anchor-link-browser-transport "^3.2.3" + "@greymass/eosio" "0.5.2" + anchor-link "^3.3.4" + anchor-link-browser-transport "^3.2.5" elliptic "6.5.4" - eosio-signing-request "^2.2.1" + eosio-signing-request "^2.3.1" eosjs "^21.0.3" universal-authenticator-library "0.3.0" @@ -13731,13 +14045,6 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -warning@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - watchpack-chokidar2@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" @@ -13768,6 +14075,11 @@ web-vitals@^1.0.1: resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-1.1.2.tgz#06535308168986096239aa84716e68b4c6ae6d1c" integrity sha512-PFMKIY+bRSXlMxVAQ+m2aw9c/ioUYfDgrYot0YUa+/xa0sakubWhSDyxAKwzymvXVdF4CZI71g06W+mqhzu6ig== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + webidl-conversions@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" @@ -13914,6 +14226,14 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + whatwg-url@^8.0.0, whatwg-url@^8.5.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" @@ -13939,6 +14259,11 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -14174,13 +14499,6 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - "ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.4.3, ws@^7.4.6: version "7.5.5" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" @@ -14313,7 +14631,15 @@ zen-observable-ts@^0.8.21: tslib "^1.9.3" zen-observable "^0.8.0" -zen-observable@^0.8.0: +zen-observable-ts@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" + integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== + dependencies: + "@types/zen-observable" "0.8.3" + zen-observable "0.8.15" + +zen-observable@0.8.15, zen-observable@^0.8.0: version "0.8.15" resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==